72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import "server-only";
|
|
|
|
import { compileMDX } from "next-mdx-remote/rsc";
|
|
import rehypePrettyCode, {
|
|
type Options as PrettyCodeOptions,
|
|
} from "rehype-pretty-code";
|
|
import rehypeSlug from "rehype-slug";
|
|
import rehypeAutolinkHeadings from "rehype-autolink-headings";
|
|
import remarkGfm from "remark-gfm";
|
|
import { mdxComponents } from "@/components/mdx/mdx-components";
|
|
|
|
/**
|
|
* MDX 编译管线。
|
|
*
|
|
* 插件顺序(rehype 在 remark 之后执行):
|
|
* 1. remark-gfm → 表格、任务列表、删除线
|
|
* 2. rehype-slug → 为标题生成 id(TOC 锚点依赖它)
|
|
* 3. rehype-autolink-headings → 标题旁生成可点击的 # 锚点
|
|
* 4. rehype-pretty-code → 基于 Shiki 的语法高亮 + 行号/高亮行
|
|
*
|
|
* Shiki 在构建期完成高亮,输出静态 HTML,运行时零 JS 开销。
|
|
*/
|
|
|
|
/** 代码高亮主题:深色 surface-code (#1c1c1e) 上对比度良好 */
|
|
const CODE_THEME = "github-dark-default";
|
|
|
|
const prettyCodeOptions: PrettyCodeOptions = {
|
|
theme: CODE_THEME,
|
|
// 保留默认的 pre/code 结构,样式由 globals.css 的 .prose-blog 控制
|
|
keepBackground: true,
|
|
defaultLang: "plaintext",
|
|
};
|
|
|
|
export interface CompiledMdx {
|
|
content: React.ReactElement;
|
|
}
|
|
|
|
/** 编译 MDX 正文为可渲染的 React 元素树 */
|
|
export async function compilePostMdx(source: string): Promise<CompiledMdx> {
|
|
const { content } = await compileMDX({
|
|
source,
|
|
components: mdxComponents,
|
|
options: {
|
|
parseFrontmatter: false,
|
|
mdxOptions: {
|
|
remarkPlugins: [remarkGfm],
|
|
rehypePlugins: [
|
|
rehypeSlug,
|
|
[
|
|
rehypeAutolinkHeadings,
|
|
{
|
|
behavior: "append",
|
|
properties: {
|
|
className: "heading-anchor",
|
|
ariaLabel: "锚点链接",
|
|
tabIndex: -1,
|
|
},
|
|
content: {
|
|
type: "text",
|
|
value: "#",
|
|
},
|
|
},
|
|
],
|
|
[rehypePrettyCode, prettyCodeOptions],
|
|
],
|
|
},
|
|
},
|
|
});
|
|
|
|
return { content };
|
|
}
|