Fix some of the blog post, get the container built, and remove config for the database.

This commit is contained in:
Dave Smith-Hayes 2024-08-07 21:53:04 -04:00
parent 4c8f3063b2
commit bd883ac4ef
7 changed files with 29 additions and 24 deletions

1
.env.sample Normal file
View File

@ -0,0 +1 @@
DEPLOY_MODE="development"

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
# deps # deps
node_modules/ node_modules/
.env

View File

@ -4,9 +4,9 @@ WORKDIR /app
COPY bun.lockb . COPY bun.lockb .
COPY package.json . COPY package.json .
COPY tsconfig.json .
RUN bun install --frozen-lockfile RUN bun install --frozen-lockfile
RUN mkdir src posts
COPY ./src ./src COPY ./src ./src
COPY ./posts ./posts COPY ./posts ./posts

3
build.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
docker build --pull -t dsh-blog . --no-cache

View File

@ -11,7 +11,7 @@ slug: fullstack-hono
draft: true draft: true
--- ---
# Context and My Blog ## Context and My Blog
I like my blog. I don't write nearly as much as I should for it but at the endof the day I like the three small posts that I have put into it. However, I never really liked how I had it set up. I have no real qualms with the SSG I chose ([11ty](https://www.11ty.dev/)) or the web server to host the HTML (NGiNX) but I never really felt like it was _mine_. I like my blog. I don't write nearly as much as I should for it but at the endof the day I like the three small posts that I have put into it. However, I never really liked how I had it set up. I have no real qualms with the SSG I chose ([11ty](https://www.11ty.dev/)) or the web server to host the HTML (NGiNX) but I never really felt like it was _mine_.
@ -27,7 +27,7 @@ But that made no sense once I _actually_ thought it. What advantage does having
_Note:_ I am going to talk a lot about JavaScript and TypeScript, and I want to make it very clear that I am talking about running JavaScript on the server. I feel like when people talk about JavaScript, there is an assumption we are talking about building frontend SPAs and not high-IO server applications (for good reasons, honestly). However, in my career and experience, the bulk of JavaScript I have written runs on Node.js. Anyways, after such a long introduction, here is my blog post about what I learned building a very basic blog with Hono and Bun. _Note:_ I am going to talk a lot about JavaScript and TypeScript, and I want to make it very clear that I am talking about running JavaScript on the server. I feel like when people talk about JavaScript, there is an assumption we are talking about building frontend SPAs and not high-IO server applications (for good reasons, honestly). However, in my career and experience, the bulk of JavaScript I have written runs on Node.js. Anyways, after such a long introduction, here is my blog post about what I learned building a very basic blog with Hono and Bun.
# Organizing Hono applications ## Organizing Hono applications
I make no effort to hide the fact that I come from the MVC Web Framework world. I have spent a lot of time in my career thinking of web applications in the terms of Models, Views, and Controllers. This has made a lot of sense to me over the years, and I posit that it's still a great framework for organizing your code. However when it comes to JavaScript, it feels verbose to create classes full of methods to handle requests and responses. I think this verbosity comes from how JavaScript code is actually organized for Node.js (Deno, Bun, etc). I make no effort to hide the fact that I come from the MVC Web Framework world. I have spent a lot of time in my career thinking of web applications in the terms of Models, Views, and Controllers. This has made a lot of sense to me over the years, and I posit that it's still a great framework for organizing your code. However when it comes to JavaScript, it feels verbose to create classes full of methods to handle requests and responses. I think this verbosity comes from how JavaScript code is actually organized for Node.js (Deno, Bun, etc).
@ -37,7 +37,7 @@ So with my understanding that a Class in JavaScript should be a collection of me
I like to call this pattern Handler, Service, Presentation. This pattern is nearly identical to MVC and you can immediately see the analogues to the original acronym. I don't think there is a clear advantage of using these words in particular, other than it can hopefully erode some of the _web-brainrot_ on how we organize our we applications. I like to call this pattern Handler, Service, Presentation. This pattern is nearly identical to MVC and you can immediately see the analogues to the original acronym. I don't think there is a clear advantage of using these words in particular, other than it can hopefully erode some of the _web-brainrot_ on how we organize our we applications.
## An Example of a Service ### An Example of a Service
Let's think of a Blog. This blog. What services do we have in the code for this blog? Right now, it is solely the `PostService`. This is a class that is given a list of `Post` types, and creates an internal Map of that with the `slug` as a key. From there we can do things like, get all the posts, get the latest post, get a post by slugs, get un-published posts, etc. Let's think of a Blog. This blog. What services do we have in the code for this blog? Right now, it is solely the `PostService`. This is a class that is given a list of `Post` types, and creates an internal Map of that with the `slug` as a key. From there we can do things like, get all the posts, get the latest post, get a post by slugs, get un-published posts, etc.
@ -45,7 +45,7 @@ Within the `PostService` module is two helper functions. One of these is an `asy
Another good way to think of a service, is a Repository class. Think of a class that should handle querying data to and from a database. If you need another example, image an HTTP Client for a specific HTTP API. Think of something that provides data to something else. I guess that's how I'd describe it. Another good way to think of a service, is a Repository class. Think of a class that should handle querying data to and from a database. If you need another example, image an HTTP Client for a specific HTTP API. Think of something that provides data to something else. I guess that's how I'd describe it.
## What Handlers Are ### What Handlers Are
Handlers should be thought of as callback functions for particular requests and responses. The _handle_ the request and response. In the world of Hono, we get to decide what Middleware is type'd into the Application and can be accessed within a handler. This allows us to bootstrap our middleware elsewhere and be assured it will be there when it runs. Handlers should be thought of as callback functions for particular requests and responses. The _handle_ the request and response. In the world of Hono, we get to decide what Middleware is type'd into the Application and can be accessed within a handler. This allows us to bootstrap our middleware elsewhere and be assured it will be there when it runs.
@ -95,7 +95,7 @@ _`src/handlers/posts.tsx`_
Now I haven't done this yet - but if I need to test the `handleSinglePost` function, I can properly mock the `Context` object with the right `PostService` class. Now I haven't done this yet - but if I need to test the `handleSinglePost` function, I can properly mock the `Context` object with the right `PostService` class.
## How Presentation Works ### How Presentation Works
Like I mentioned earlier, one of the selling points of using Hono for the framework was its suppose of rendering JSX with `jsxRenderer` middleware. Its trivial to set up, but you have to remember to re-save your files as `tsx` and `jsx` if you want to use it. I have not spent a lot of time writing JSX in my life but once I got some of the basics it became super easy to understand. I can understand why people like React, honestly. Like I mentioned earlier, one of the selling points of using Hono for the framework was its suppose of rendering JSX with `jsxRenderer` middleware. Its trivial to set up, but you have to remember to re-save your files as `tsx` and `jsx` if you want to use it. I have not spent a lot of time writing JSX in my life but once I got some of the basics it became super easy to understand. I can understand why people like React, honestly.
@ -151,12 +151,12 @@ app.get(
); );
``` ```
# Development ## Development
If the environment variable `ENVIRONMENT` is set and the value is `DEVELOPMENT` If the environment variable `ENVIRONMENT` is set and the value is `DEVELOPMENT`
then we can easily grab all the Posts, including Drafts, from the then we can easily grab all the Posts, including Drafts, from the
`PostService`. `PostService`.
# Deployment ## Deployment
We can simply depoy the application within a Docker container into Dokku. We can simply depoy the application within a Docker container into Dokku.

View File

@ -1,4 +1,3 @@
export const POST_PATH: string = __dirname + '/../posts'; export const POST_PATH: string = __dirname + '/../posts';
export const STATIC_PATH: string = __dirname + '/assets'; export const STATIC_PATH: string = __dirname + '/assets';
export const POST_ROUTE_PREFIX: string = '/posts' export const POST_ROUTE_PREFIX: string = '/posts'
export const SQLITE_DATABASE_FILE: string = __dirname + '/../db/blog.sqlite';

View File

@ -61,6 +61,16 @@ export async function createPostService(path: string): Promise<PostService> {
return new PostService(posts); return new PostService(posts);
} }
export function sortPostsByDate(posts: Post[], desc: boolean = true): Post[] {
return posts.sort((p1: Post, p2: Post) => {
if (desc) {
return p2.meta.date.getTime() - p1.meta.date.getTime();
}
return p1.meta.date.getTime() - p2.meta.date.getTime();
});
}
export class PostService { export class PostService {
private posts: Map<string, Post>; private posts: Map<string, Post>;
@ -73,28 +83,19 @@ export class PostService {
} }
public getAllPosts(): Post[] { public getAllPosts(): Post[] {
return Array.from(this.posts.values()); return this.getPostsSortedByDate();
} }
public getPostsSortedByDate(desc: boolean = true): Post[] { public getPostsSortedByDate(desc: boolean = true): Post[] {
return Array.from(this.posts.values()) return sortPostsByDate(Array.from(this.getPosts().values()), desc);
.sort((p1: Post, p2: Post) => {
if (desc) {
return p2.meta.date.getTime() - p1.meta.date.getTime();
}
return p1.meta.date.getTime() - p2.meta.date.getTime();
});
} }
public getPublishedPosts(desc: boolean = true): Post[] { public getPublishedPosts(): Post[] {
return this.getPostsSortedByDate(desc) return this.getAllPosts().filter((p: Post) => p.meta.draft == false);
.filter((p: Post) => p.meta.draft == false);
} }
public getDraftPosts(desc: boolean = true): Post[] { public getDraftPosts(): Post[] {
return this.getPostsSortedByDate(desc) return this.getAllPosts().filter((p: Post) => p.meta.draft == true);
.filter((p: Post) => p.meta.draft == true);
} }
public getPost(slug: string): Post { public getPost(slug: string): Post {