A better MDX pipeline
Replacing Contentlayer with next-mdx-remote-rsc and rehype-pretty-code, with line numbers, warm code blocks, and a synced table of contents.
Contentlayer is a lovely idea that stopped keeping up with the App Router. The good news is that the replacement is three packages and about twenty lines of config.
The renderer
The App Router is built on React Server Components, so the renderer has to be RSC-aware. next-mdx-remote ships an /rsc entrypoint for exactly that.
import { MDXRemote } from 'next-mdx-remote/rsc';
import { mdxOptions } from '@/lib/mdx';
export function MdxContent({ source }: { source: string }) {
return (
<div className="prose-blog">
<MDXRemote source={source} options={mdxOptions} />
</div>
);
}Syntax highlighting without a runtime
rehype-pretty-code runs Shiki at build time. Zero JavaScript ships to the reader; the colors are baked in as inline styles. One setting does all the heavy lifting:
const options = {
theme: 'one-dark-pro',
keepBackground: false, // we set our own #2A2421 in CSS
};Setting keepBackground to false is the trick that lets a warm #2A2421 background replace Shiki's default theme background, so code blocks belong to the page instead of fighting it.
Line highlighting
Lines are highlighted with the {1,3-5} meta syntax on the fence:
function add(a: number, b: number) {
return a + b; // highlighted
}
const result = add(2, 3); // highlighted
console.log(result);A table of contents that matches
The last piece is a TOC whose anchors line up with the rendered headings. The fix is to produce heading ids with the same slugger the renderer uses.
import GithubSlugger from 'github-slugger';
const slugger = new GithubSlugger();
// slug(text) === the id rehype-slug will produceThat is the whole system: read a file, strip frontmatter, render with one component, and the headings, anchors, and sidebar all agree.
相关阅读
评论
评论区尚未配置:部署 Twikoo 后端后,将 envId 填入 lib/site.ts。