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.
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
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;
|