fix: fix empty post bodies — stop double-compiling MDX

This commit is contained in:
2026-06-01 21:20:44 -05:00
parent 7685a81f76
commit 6dc42c1ba8
2 changed files with 47 additions and 33 deletions

View File

@@ -1,5 +1,10 @@
import { notFound } from 'next/navigation' import { notFound } from 'next/navigation'
import { MDXRemote } from 'next-mdx-remote/rsc' import { MDXRemote } from 'next-mdx-remote/rsc'
import { useMDXComponents } from '@/mdx-components'
import remarkMath from 'remark-math'
import remarkGfm from 'remark-gfm'
import rehypePrettyCode from 'rehype-pretty-code'
import rehypeKatex from 'rehype-katex'
import { getPosts, getPost, getReadingTime } from '@/lib/posts' import { getPosts, getPost, getReadingTime } from '@/lib/posts'
import { TableOfContents } from '@/components/blog/TableOfContents' import { TableOfContents } from '@/components/blog/TableOfContents'
import { ScrollToTop } from '@/components/ui/ScrollToTop' import { ScrollToTop } from '@/components/ui/ScrollToTop'
@@ -43,7 +48,19 @@ export default async function PostPage({ params }: { params: Promise<{ slug: str
</p> </p>
</header> </header>
<div className="prose prose-lg max-w-none"> <div className="prose prose-lg max-w-none">
<MDXRemote source={post.source} /> <MDXRemote
source={post.source}
components={useMDXComponents({})}
options={{
mdxOptions: {
remarkPlugins: [remarkMath, remarkGfm],
rehypePlugins: [
[rehypePrettyCode, { theme: 'github-dark' }],
rehypeKatex,
],
},
}}
/>
</div> </div>
</article> </article>
<aside className="hidden lg:block"> <aside className="hidden lg:block">

View File

@@ -1,13 +1,7 @@
import fs from 'fs/promises' import fs from 'fs'
import path from 'path' import path from 'path'
import matter from 'gray-matter' import matter from 'gray-matter'
import { compileMDX } from 'next-mdx-remote/rsc'
import { cache } from 'react' import { cache } from 'react'
import { useMDXComponents as getMDXComponents } from '@/mdx-components'
import remarkMath from 'remark-math'
import remarkGfm from 'remark-gfm'
import rehypeKatex from 'rehype-katex'
import rehypePrettyCode from 'rehype-pretty-code'
const postsDirectory = path.join(process.cwd(), 'content/posts') const postsDirectory = path.join(process.cwd(), 'content/posts')
@@ -16,15 +10,19 @@ export interface PostMeta {
title: string title: string
date: string date: string
excerpt: string excerpt: string
tags: string[]
author: string | null
coverImage: string | null
readingTime: number
} }
export interface Post extends PostMeta { export interface Post extends PostMeta {
source: string source: string // raw MDX string, NOT compiled
} }
const getMdxFiles = cache(async () => { const getMdxFiles = cache(async () => {
try { try {
const files = await fs.readdir(postsDirectory) const files = await fs.promises.readdir(postsDirectory)
return files.filter((f) => f.endsWith('.mdx') || f.endsWith('.md')) return files.filter((f) => f.endsWith('.mdx') || f.endsWith('.md'))
} catch { } catch {
return [] return []
@@ -36,14 +34,23 @@ export const getPosts = cache(async (): Promise<PostMeta[]> => {
return Promise.all( return Promise.all(
files.map(async (file) => { files.map(async (file) => {
const filePath = path.join(postsDirectory, file) const filePath = path.join(postsDirectory, file)
const raw = await fs.readFile(filePath, 'utf8') const raw = await fs.promises.readFile(filePath, 'utf-8')
const { data } = matter(raw) const { data } = matter(raw)
const slug = file.replace(/\.(mdx|md)$/, '')
// Compute reading time from content (everything after frontmatter)
const content = raw.split(/---\n*\n*/).slice(2).join('\n')
const readingTime = Math.max(1, Math.ceil(content.split(/\s+/).length / 200))
return { return {
slug: file.replace(/\.(mdx|md)$/, ''), slug,
title: data.title ?? file, title: data.title ?? slug,
date: data.date ?? 'Unknown', date: data.date ?? 'Unknown',
excerpt: data.excerpt ?? '', excerpt: data.excerpt ?? '',
} as PostMeta tags: data.tags ?? [],
author: data.author ?? null,
coverImage: data.coverImage ?? null,
readingTime,
}
}) })
).then((posts) => ).then((posts) =>
posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) posts.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
@@ -56,32 +63,22 @@ export const getPost = async (slug: string): Promise<Post | null> => {
if (!file) return null if (!file) return null
const filePath = path.join(postsDirectory, file) const filePath = path.join(postsDirectory, file)
const raw = await fs.readFile(filePath, 'utf8') const raw = await fs.promises.readFile(filePath, 'utf8')
const { data, content } = matter(raw) const { data, content } = matter(raw)
const components = getMDXComponents({})
const { content: compiledContent } = await compileMDX({ const readingTime = Math.max(1, Math.ceil(content.split(/\s+/).length / 200))
source: content,
components,
options: {
parseFrontmatter: true,
mdxOptions: {
remarkPlugins: [remarkMath, remarkGfm],
rehypePlugins: [
[rehypePrettyCode, { theme: 'github-dark' }],
rehypeKatex,
],
},
},
})
return { return {
slug, slug,
title: data.title ?? file, title: data.title ?? slug,
date: data.date ?? 'Unknown', date: data.date ?? 'Unknown',
excerpt: data.excerpt ?? '', excerpt: data.excerpt ?? '',
source: compiledContent, tags: data.tags ?? [],
} as unknown as Post author: data.author ?? null,
coverImage: data.coverImage ?? null,
source: content,
readingTime,
} satisfies Post
} }
export const getReadingTime = (content: string): number => { export const getReadingTime = (content: string): number => {