53 lines
1.9 KiB
TypeScript
53 lines
1.9 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 { dbConnection } 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>);
|
|
dbConnection.addPost(args.path, meta, bodyHtml); // Load the post to the database for dynamic querying
|
|
|
|
// JSX Approach
|
|
return {
|
|
contents: renderedHtml,
|
|
loader: 'html',
|
|
};
|
|
});
|
|
},
|
|
};
|
|
|
|
export default markdownLoader;
|