创建一个插件来提取 MDX 阅读时间
一个创建插件的指南,用于在将 MDX 文件作为 ES 模块导入时,使阅读时间数据可用。
Remark 是一个功能强大的 markdown 处理器,可以用来创建自定义插件来转换 markdown 内容。在使用 remark 解析 markdown 文件时,内容被转换为抽象语法树(AST),可以通过插件进行操作。
为了更好的用户体验,我们通常会显示文章的预计阅读时间。在本指南中,我们将创建一个插件,提取 MDX 文件的阅读时间数据,并在将 MDX 文件作为 ES 模块导入时使其可用。
开始
让我们从创建一个 MDX 文件开始:
假设我们使用 Vite 作为打包工具,并使用官方的 @mdx-js/rollup
插件来转换 MDX 文件,因此我们可以将 MDX 文件作为 ES 模块导入。Vite 配置应类似于以下内容:
如果我们将 MDX 文件作为 ES 模块导入,内容将是一个带有 default
属性的对象,其中包含编译后的 JSX。例如:
将会得到如下结果:
一旦我们有了类似的输出,我们就可以准备创建插件了。
创建插件
让我们来看看为了实现目标需要做些什么:
- 提取 MDX 内容为文本以便计算阅读时间。
- 计算阅读时间。
- 将阅读时间数据附加到 MDX 内容中,使其在将 MDX 文件作为 ES 模块导入时可用。
幸运的是,已经有一些库可以帮助我们进行阅读时间的计算和基本的 AST 操作:
reading-time
用于计算阅读时间。mdast-util-to-string
用于将 MDX AST 转换为文本。estree-util-value-to-estree
用于将阅读时间数据转换为 ESTree 节点。
如果你是 TypeScript 用户,可能还需要安装这些用于类型定义的包:
@types/mdast
用于 MDX 根节点类型定义。unified
用于插件类型定义。
只要我们安装了这些包,就可以开始创建插件了:
如我们所见,插件只是简单地提取 MDX 内容为文本并计算阅读时间。现在,我们需要将阅读时间数据附加到 MDX 内容中,这看起来并不那么简单。但是,如果我们查看其他优秀的库,比如 remark-mdx-frontmatter,我们可以找到一种方法来实现这一目的:
注意代码中的 type: 'mdxjsEsm'
。这是一个用于 序列化 MDX ESM 的节点类型。上述代码通过 readingTime
的名字将阅读时间数据附加到 MDX 内容中,这将在将 MDX 文件作为 ES 模块导入时得到如下输出:
如果你需要更改阅读时间数据的名称,可以更新 Identifier
节点的 name
属性。
TypeScript 支持
为了使插件更加友好,我们可以通过增强 MDX 类型定义来最后一次优化:
现在,当导入 MDX 文件时,TypeScript 将会识别 readingTime
属性:
总结
希望本指南能帮助你在处理 MDX 文件时获得更好的体验。通过这个插件,你可以直接使用阅读时间数据,甚至可以利用 ESM 树摇优化的性能。