Complete WIP: Architecture refactor.

Mount JSX server side templating for blog posts. Send AppShell conditionally. Maintain support for HMR via HTMLbundles using Bun's native fullstack dev server under an /hmr path. This is only mounted in development and is supported by the onImport Bun plugin. Add DB creation on startup and load pages based on those records.
This commit is contained in:
2026-01-08 05:13:48 -08:00
parent 3abd97702d
commit f46f4667a1
32 changed files with 2779 additions and 353 deletions

View File

@@ -0,0 +1,52 @@
import type { BunPlugin } from 'bun';
import React from 'react';
import { renderToString } from "react-dom/server";
import matter from 'gray-matter';
import { marked } from 'marked';
import { addToDatabase } from "../src/db/index";
import { AppShell } from "../src/frontend/AppShell";
import { Post } from "../src/frontend/pages/post";
// TODO: Add better type handling for if Markdown parsing fails
const markdownLoader: BunPlugin = {
name: 'markdown-loader',
setup(build) {
// Plugin implementation
build.onLoad({filter: /\.md$/}, async args => {
console.log("Loading markdown file:", args.path);
const {data, content } = matter(await Bun.file(args.path).text());
// Remove the title from content if it matches the frontmatter title to avoid duplicate H1s
let processedContent = content;
if (data.title) {
const titleHeadingRegex = new RegExp(`^#\\s+${data.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'm');
processedContent = content.replace(titleHeadingRegex, '').trim();
}
const bodyHtml = await marked.parse(processedContent);
// AppShell is required here for rendering. If used at route level
// Bun will only see an htmlBundle and fail to load anything
// Validate required fields
if (!data.title || !data.date) {
throw new Error(`Markdown files must include title and date in frontmatter: ${args.path}`);
}
const meta = {
title: data.title,
date: new Date(data.date),
readingTime: data.readingTime || `${Math.ceil(content.split(/\s+/).length / 200)} min read`
};
const renderedHtml = renderToString(<AppShell><Post meta={meta} children={bodyHtml} /></AppShell>);
addToDatabase(args.path, meta, bodyHtml); // Load the post to the database for dynamic querying
// JSX Approach
return {
contents: renderedHtml,
loader: 'html',
};
});
},
};
export default markdownLoader;