我的官网创作之路(八)-Markdown解析

966 阅读2分钟

前言

在前两个小节中,我分别介绍了mdx的实时编译与预编译的案例及用法,这一小节就来具体讲讲如何实现代码高亮、以及如何生成 toc 目录等功能。

其实说到这里,那就不得不提一下 unified 大家族了,可以说它提供的功能是非常全的了,它能够处理 Markdown、HTML、自然语言等,提供了非常多的插件,其提供的插件生态主要包含如下:

image.png

虽然有这么多插件,但是我们平时常用的就两个 remarkrehype,我们以react-markdown 解析编译 markdown 文件为例来看看它们俩分别在什么时候发生作用的。

企业微信截图_16873280164187.png

有了上面知识的铺垫,对于后面我们要实现的功能相信你能更好的理解,接着我们就来完成我们上面说的两个功能。

如何生成toc目录(remark)

export const compileMDX = async (source: any) => {  
    const toc: Toc = [];  
    const { code, frontmatter } = await bundleMDX({  
        source,  
        cwd: path.join(root, 'components'),  
        mdxOptions(options, frontmatter) {   
            options.remarkPlugins = [  
                ...(options.remarkPlugins ?? []),  
                remarkGfm,  
                remarkFrontmatter,  
                [remarkTocHeadings, { exportRef: toc }],  
            ];  
            options.rehypePlugins = [  
                ...(options.rehypePlugins ?? []),  
                rehypeSlug,  
                rehypeExternalLinks,  
                rehypeAutolinkHeadings,  
                [rehypePrismPlus, { ignoreMissing: true }],  
            ];  
            return options;  
        },  
        esbuildOptions: (options) => {  
            options.loader = {  
                ...options.loader,  
                '.js': 'jsx',  
                };  
            return options;  
        },  
    });  

    return {  
        mdxSource: code,  
        toc,  
        frontMatter: frontmatter,  
    };  
};

上面的代码在前面的章节也提到过,不过这里要注意代码中的 remarkPlugins 中的 [remarkTocHeadings, { exportRef: toc }],它是实现生成toc目录的关键,以下是 remarkTocHeadings 的代码

import { Parent } from 'unist';  
import { visit } from 'unist-util-visit';  
import { slug } from 'github-slugger';  
import { toString } from 'mdast-util-to-string';  
  
export default function remarkTocHeadings(options: any) {  
    return (tree: Parent) =>  
        visit(tree, 'heading', (node: any) => {  
            const textContent = toString(node);  
            options.exportRef.push({  
                text: textContent,  
                url: '#' + slug(textContent),  
                depth: node.depth,  
            });  
        });  
}

如何实现代码高亮(rehype)

还是上面的第一段代码,我就不重复粘贴了,这里要注意的是 rehypePlugins 中的 [rehypePrismPlus, { ignoreMissing: true }],它是实现代码高亮的关键,当然该插件也支持我们自定义代码高亮的颜色,以下为代码片段

.token.tag,  
.token.operator,  
.token.keyword {  
    color: rgb(127, 219, 202);  
}  
  
.token.boolean {  
    color: rgb(255, 88, 116);  
}  
  
.token.number {  
    color: rgb(247, 140, 108);  
}  
  
.token.constant,  
.token.function,  
.token.builtin,  
.token.char {  
    color: rgb(130, 170, 255);  
}

最后

  1. 欢迎访问我的个人网站:openbytecode.com/
  2. 本周四(23/06/22)我会在 b 站直播手把手教你搭建 chatgpt,欢迎围观,space.bilibili.com/383654866