This guide delves into how unified can be used to transform a Markdown file to HTML. It’ll also show how to generate a table of contents, and sidestep into checking prose.
Stuck? A good place to get help fast is Spectrum. Have an idea for another guide? Share it on Spectrum!
For this example, we’ll start out with Markdown content, then transform to HTML. We need a Markdown parser and an HTML stringifier for that. The relevant projects are respectively
rehype-stringify. To transform between the two syntaxes, we’ll use
remark-rehype. Finally, we’ll use unified itself to glue these together, and
unified-stream for streaming.
Let’s install those with npm, which comes bundled with Node.
Let’s first create a Markdown file that we’re going to transform.
Then, create an
index.js script as well. It’ll transform Markdown to HTML. It’s hooked up to read from stdin and write to stdout.
Now, running our script with Node (this uses your Shell to read
example.md and write
…gives us an
example.html file that looks as follows:
remark-rehype doesn’t deal with HTML inside the Markdown. You’ll need
rehype-raw if you’re planning on doing that.
🎉 Nifty! It doesn’t do much yet, but we’ll get there. In the next section, we’ll make this more useful by introducing plugins.
We’re still missing some things, notably a table of contents, and proper HTML document structure.
Respectively, we can use
rehype-document to do these two tasks.
Let’s now use those two as well, by modifying our
We pass options to
rehype-document. In this case, we use that to make sure we get a proper
<title> element in our
<head>, as required by the HTML specification. More options are accepted by
rehype-document, such as which language tag to use. These are described in detail in its
readme.md. Many other plugins accept options as well, so make sure to read through their docs to learn more.
Note that plugins work on a Markdown tree, and rehype plugins work on an HTML tree. It’s important that you place your
.use calls in the correct places.
Now, when running our script like before, we’d get the following
You may noticed the document isn’t formatted nicely. There’s a plugin for that though! Feel free to add
rehype-format to the plugins, below
💯 You’re acing it! This is getting pretty useful, right?
In the next section, we’ll lay the groundwork for creating a report.
Before we check some prose (yes, we’re getting there), we’ll first switch up our
index.js file to print a pretty report (we’ll fill it in the next section).
We can use
to-vfile to read and write virtual files from the file system, and we can use
vfile-reporter to report messages relating to those files. Let’s install those.
…and now unhook stdin/stdout from our example and use the file-system instead, like so:
If we now run our script on its own, without shell redirects, we get a report showing everything’s fine:
But everything’s not fine, there’s a typo in the Markdown! The next section shows how to detect prose errors by adding retext.
I did notice a typo in there, so let’s check some prose to prevent that from happening in the future. We can use retext and its ecosystem for our natural language parsing. As we’re writing in English, we use
retext-english specifically to parse English natural language. The problem in our
example.md file is that it has
a example instead of
an example, which is conveniently checked for by
retext-indefinite-article. To bridge from markup to prose, we’ll use
remark-retext. First, let’s install these dependencies as well.
…and change our
index.js like so:
As the code shows,
remark-retext receives another
unified middleware pipeline. A natural language pipeline. The plugin will transform the origin syntax (Markdown) with the given pipeline’s parser. Then, it’ll run the attached plugins on the natural language syntax tree.
Now, when running our script one final time:
…we’ll get a useful message.
💃 You’ve got a really cool system set up already, nicely done! That’s a wrap though, check out the next section for further exercises and resources.
Finally, check out the lists of available plugins for retext, remark, and rehype, and try some of them out.
If you haven’t already, check out the other guides!