From 6e400f4263958652a8981c573c1d1d2ee5fbf89c Mon Sep 17 00:00:00 2001 From: Dave Smith-Hayes Date: Fri, 26 Jul 2024 22:31:09 -0400 Subject: [PATCH] Most all posts into memory at startup and render those on requests. --- bun.lockb | Bin 28248 -> 28248 bytes src/handlers/home.tsx | 30 +++++++++------ src/handlers/posts.tsx | 41 +++++++++++---------- src/index.tsx | 9 ++++- src/middleware/post-service.ts | 14 +++++++ src/models/Post.ts | 8 ++-- src/services/database.ts | 1 - src/services/post-file.ts | 20 +++++----- src/services/repository/post-repository.ts | 11 +++++- src/templates/components/PostList.tsx | 2 +- 10 files changed, 87 insertions(+), 49 deletions(-) create mode 100644 src/middleware/post-service.ts diff --git a/bun.lockb b/bun.lockb index da0768bad3489c00b78ed15e4f0bcb44a80d46f0..1d94372d8d6a16a6ba75130ee2b84a001674ff84 100755 GIT binary patch delta 42 ycmca{hw;W8#tkm+(#8zAiAC9|DGUs(K`L`y7BFTrF~%7h>lx@7ZH{;UsRjT;8x6|< delta 42 ycmca{hw;W8#tkm+(gqBlx@7ZjN{VsRjT-wGGDr diff --git a/src/handlers/home.tsx b/src/handlers/home.tsx index 6489ae3..730fbef 100644 --- a/src/handlers/home.tsx +++ b/src/handlers/home.tsx @@ -1,17 +1,25 @@ -import { Hono } from 'hono'; -import { Home } from '@blog/templates/Pages/Home'; -import { getPostList } from '@blog/post/post-reader'; -import { PostMeta } from '@blog/model/PostMeta'; +import { Hono } from "hono"; +import { Home } from "@blog/templates/Pages/Home"; +import { PostMeta } from "@blog/models/PostMeta"; +import { Post } from '@blog/models/Post'; +import { PostFileService } from '@blog/services/post-file'; -const app = new Hono(); +type Posts = { + postService: PostFileService +}; -app.get('/', async (c) => { - const postDir = __dirname + '/../../posts'; - const postList: PostMeta[] = await getPostList(postDir); +const app = new Hono<{ Variables: Posts }>(); - return c.render(, { meta: { - description: "The blog for Dave Smith-Hayes, a dad and developer." - }}); +app.get("/", async (c) => { + const postService: PostFileService = c.get('postService'); + const posts = postService.getPosts(); + const postList: PostMeta[] = Array.from(posts.values()).map((p: Post) => p.meta); + + return c.render(, { + meta: { + description: "The blog for Dave Smith-Hayes, a dad and developer.", + }, + }); }); export default app; diff --git a/src/handlers/posts.tsx b/src/handlers/posts.tsx index 278745a..60b5b3e 100644 --- a/src/handlers/posts.tsx +++ b/src/handlers/posts.tsx @@ -1,34 +1,37 @@ import { Hono } from 'hono'; import { PostPage } from '@blog/templates/Pages/PostPage'; import { FourOhFour } from '@blog/templates/Pages/FourOhFour'; -import { readdir } from 'node:fs/promises'; -import { SiteMeta } from '@blog/model/SiteMeta'; -import { readPostMarkdown } from '@blog/post/post-reader'; +import { SiteMeta } from '@blog/models/SiteMeta'; +import { PostFileService } from '@blog/services/post-file'; -const app = new Hono(); +type Posts = { + postService: PostFileService +} + +const app = new Hono<{ Variables: Posts }>(); app.get('/:slug', async (c) => { const postSlug: string = c.req.param("slug"); - const fileName: string = postSlug + '.md'; - const files = await readdir(__dirname + "/../../posts"); + const postService: PostFileService = c.get('postService'); - const postFile = files.find(f => f === fileName); - if (!postFile) { - c.status(404); + try { + const post = postService.getPost(postSlug); const meta: SiteMeta = { - description: "Page does not exist." + description: post.meta.description, + tags: post.meta.tags, + author: "Dave Smith-Hayes" }; + + return c.render(, { meta }); + } catch (e) { + const description: string = "Page does not exist."; + console.error(description); + console.error(e); + + c.status(404); + const meta: SiteMeta = { description }; return c.render(, { meta }); } - - const post = await readPostMarkdown(__dirname + "/../../posts/" + postFile); - const meta: SiteMeta = { - description: post.meta.description, - tags: post.meta.tags, - author: "Dave Smith-Hayes" - }; - - return c.render(, { meta }); }); export default app; diff --git a/src/index.tsx b/src/index.tsx index 9479e8e..72883b3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -4,6 +4,8 @@ import { Page } from '@blog/templates/Page'; import home from '@blog/handlers/home'; import posts from '@blog/handlers/posts'; import type { SiteMeta } from '@blog/models/SiteMeta'; +import { postFileMiddleware } from '@blog/middleware/post-service'; +import { logger } from 'hono/logger'; declare module 'hono' { interface ContextRenderer { @@ -13,7 +15,10 @@ declare module 'hono' { const app = new Hono(); -// Render the JSX views +app.use(postFileMiddleware); +app.use(logger()); + +// JSX Rendering for Templates app.get( '*', jsxRenderer( @@ -22,7 +27,7 @@ app.get( ) ); -console.log({ message: "Bootstrapping the routes..." }); +console.log(JSON.stringify({ message: "Bootstrapping the routes..." })); app.route('/', home); app.route('/posts', posts); diff --git a/src/middleware/post-service.ts b/src/middleware/post-service.ts new file mode 100644 index 0000000..2e842ca --- /dev/null +++ b/src/middleware/post-service.ts @@ -0,0 +1,14 @@ +import { createFactory } from 'hono/factory'; +import { PostFileService } from '@blog/services/post-file'; + +const factory = createFactory(); +let postFileService: PostFileService; + +export const postFileMiddleware = factory.createMiddleware(async (c, next) => { + if (!postFileService) { + postFileService = await PostFileService.create(); + } + + c.set('postService', postFileService); + await next(); +}); diff --git a/src/models/Post.ts b/src/models/Post.ts index b373990..c5e7b73 100644 --- a/src/models/Post.ts +++ b/src/models/Post.ts @@ -1,7 +1,7 @@ -import { PostMeta } from '@blog/model/PostMeta'; +import { PostMeta } from "@blog/models/PostMeta"; export type Post = { - meta: PostMeta, - content: string, - html?: string + meta: PostMeta; + content: string; + html?: string; }; diff --git a/src/services/database.ts b/src/services/database.ts index 8f63e36..796eea4 100644 --- a/src/services/database.ts +++ b/src/services/database.ts @@ -1,4 +1,3 @@ import { Database } from "bun:sqlite"; import { SQLITE_DATABASE_FILE } from "@blog/config"; export const db = new Database(SQLITE_DATABASE_FILE); - diff --git a/src/services/post-file.ts b/src/services/post-file.ts index e65dc8f..7356f94 100644 --- a/src/services/post-file.ts +++ b/src/services/post-file.ts @@ -1,19 +1,19 @@ -import { POST_PATH, POST_ROUTE_PREFIX } from '@blog/config'; -import { readdir } from 'node:fs/promises'; -import type { Post } from '@blog/models/Post'; -import * as yamlFront from 'yaml-front-matter'; -import { marked } from 'marked'; +import { POST_PATH } from "@blog/config"; +import { readdir } from "node:fs/promises"; +import type { Post } from "@blog/models/Post"; +import * as yamlFront from "yaml-front-matter"; +import { marked } from "marked"; export async function readPostFile(path: string): Promise { const file = Bun.file(path); const fileContent = await file.text(); - const parsedData = yamlFront.loadFront(fileContent); + const parsedData = yamlFront.loadFront(fileContent); const postHtml = await marked.parse(parsedData.__content); let slug = parsedData.slug; if (!slug) { - slug = path.split('/').pop().slice(0, -3); + slug = path.split("/").pop()?.slice(0, -3); } return { @@ -23,15 +23,15 @@ export async function readPostFile(path: string): Promise { date: new Date(parsedData.date), draft: parsedData?.draft || false, tags: parsedData.tags, - slug: slug + slug: slug, }, content: parsedData.__content, - html: postHtml + html: postHtml, }; } export class PostFileService { - private posts: Map; + private posts: Map; public constructor(posts: Map) { this.posts = posts; diff --git a/src/services/repository/post-repository.ts b/src/services/repository/post-repository.ts index 9febbc3..933e527 100644 --- a/src/services/repository/post-repository.ts +++ b/src/services/repository/post-repository.ts @@ -11,7 +11,16 @@ WHERE id = $id const query = db.query(queryString); const results = query.get({ $id: id }); - return {} + return { + meta: { + title: results.title, + slug: results.slug, + description: results.description, + date: new Date(results.published_date), + draft: results.is_draft, + }, + content: results.raw_content, + } } public async getPostBySlug(slug: string): Post { diff --git a/src/templates/components/PostList.tsx b/src/templates/components/PostList.tsx index bc222a8..0c35933 100644 --- a/src/templates/components/PostList.tsx +++ b/src/templates/components/PostList.tsx @@ -6,7 +6,7 @@ export function PostList({ posts }: { posts: PostMeta[] }) { {posts.map(p => { return (
  • - {p.title} + {p.title}
  • ); })}