简体中文
  • remark
  • mdx
  • reading-time
  • esm

创建一个插件来提取 MDX 阅读时间

一个创建插件的指南,用于在将 MDX 文件作为 ES 模块导入时,使阅读时间数据可用。

Gao
Gao
Founder

Remark 是一个功能强大的 markdown 处理器,可以用来创建自定义插件来转换 markdown 内容。在使用 remark 解析 markdown 文件时,内容被转换为抽象语法树(AST),可以通过插件进行操作。

为了更好的用户体验,我们通常会显示文章的预计阅读时间。在本指南中,我们将创建一个插件,提取 MDX 文件的阅读时间数据,并在将 MDX 文件作为 ES 模块导入时使其可用。

开始

让我们从创建一个 MDX 文件开始:

假设我们使用 Vite 作为打包工具,并使用官方的 @mdx-js/rollup 插件来转换 MDX 文件,因此我们可以将 MDX 文件作为 ES 模块导入。Vite 配置应类似于以下内容:

如果我们将 MDX 文件作为 ES 模块导入,内容将是一个带有 default 属性的对象,其中包含编译后的 JSX。例如:

将会得到如下结果:

一旦我们有了类似的输出,我们就可以准备创建插件了。

创建插件

让我们来看看为了实现目标需要做些什么:

  1. 提取 MDX 内容为文本以便计算阅读时间。
  2. 计算阅读时间。
  3. 将阅读时间数据附加到 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 树摇优化的性能。