Create a remark plugin to extract MDX reading time
A guide to create a remark plugin to make the reading time data available when importing MDX files as ES modules.
Remark is a powerful markdown processor that can be used to create custom plugins to transform markdown content. When parsing markdown files with remark, the content is transformed into an abstract syntax tree (AST) that can be manipulated using plugins.
For a better user experience, it's common to display the estimated reading time of an article. In this guide, we'll create a remark plugin to extract the reading time data from an MDX file and make it available when importing the MDX file as an ES module.
Get started
Let's start by creating an MDX file:
Assuming we are using Vite as the bundler, with the official @mdx-js/rollup
plugin to transform MDX files, thus we can import the MDX file as an ES module. The Vite configuration should look like this:
If we import the MDX file as an ES module, the content will be an object with the default
property containing the compiled JSX. For example:
Will yield:
Once we have the output like this, we can are ready to create the remark plugin.
Create the remark plugin
Let's check out what we need to do to achieve the goal:
- Extract MDX content to text for reading time calculation.
- Calculate the reading time.
- Attach the reading time data to the MDX content, make it available when importing the MDX file as an ES module.
Luckily, there are already libraries to help us with the reading time calculation and basic AST operations:
reading-time
to calculate the reading time.mdast-util-to-string
to convert the MDX AST to text.estree-util-value-to-estree
to convert the reading time data to an ESTree node.
If you are a TypeScript user, you may also need to install these packages for type definitions:
@types/mdast
for MDX root node type definitions.unified
for plugin type definitions.
As long as we have the packages installed, we can start creating the plugin:
As we can see, the plugin simply extracts the MDX content to text and calculates the reading time. Now we need to attach the reading time data to the MDX content, and it looks not that straightforward. But if we take a look at the other awesome libraries like remark-mdx-frontmatter, we can find a way to do it:
Note the type: 'mdxjsEsm'
in the code above. This is a node type that is used to serialize MDX ESM. The code above attaches the reading time data using the name readingTime
to the MDX content, which will yield the following output when importing the MDX file as an ES module:
If you need to change the name of the reading time data, you can update the name
property of the Identifier
node.
TypeScript support
To make the plugin even more developer-friendly, we can make one last touch by augmenting the MDX type definitions:
Now, when importing the MDX file, TypeScript will recognize the readingTime
property:
Conclusion
I hope this guide helps you have a better experience when working with MDX files. With this remark plugin, you can use the reading time data directly and even leverage ESM tree-shaking for better performance.