How to Build a Remark.js Syntax Highlighter
Tags: javascript, nextjs, programming, react
Published: 2022-02-13 00:04:03

This was a bit of an adventure and not in a good way. I spent the better part of two days trying to do something that was seemingly very simple, but I could not for the life of me seem to figure out. In this post I hope to help some of you that maybe on the same path, just trying to build a really simple Markdown blog with code highlighting, but unlike me you should not have to spend two days doing so.

## What is Remark.js

Remark JS is a very neet little library that parses Markdown into an AST (Abstract Styntax Tree) which allows you to do all sorts of interesting operations on it, including converting markdown into HTML and allowing you to add a css class to the output html so you can easily connect it to highlight.js which will do the actual syntax highlighting. Remark is part of a bigger family of tools. The umbrella tool is called `Unified` which is not tied to Markdown and there's another sub-parser for HTML. All of these three tools have a bunch of different plugins that can be used with them to modify the AST and the output.

So I will show you how to do this in isolation and then give you a few tips if you are also trying to build your website in Next.js like I did.

### Step 1

You'll need to include either `unified` or `remark` in your project using NPM or Yarn.

```sh
npm install remark --save
```

you will also need `remark-html`. This is the plugin for generating our output html from our markdown.

```sh
npm install remark-html --save
```

lastly You'll need `remark-highlight.js`. This is responsible for adding the css class to your code block in order to properly format it with [Highlight.js](https://highlightjs.org/).

```sh
npm install remark-highlight.js --save
```

If you installed unified instead of remark, that's fine, but you'll need `remark-parse` if and only if you are using unified.

### Step 2

Now that youy have all of your dependencies installed it's time to build our process chain. I will do this with just a markdown string right now to keep things simple, but you can load your markdown in from your file system or from an API dosen't really matter

````ts
import { remark } from 'remark'
import remarkHtml from 'remark-html'
import remarkHighlightjs from 'remark-highlight.js'

function convertMarkdownToHtml() {
    const output = remark()
        .use(remarkHighlightjs) // we can add , {include: ['css']} or exclude: [a list of langages]
        .use(remarkHtml, { sanitize: false })
        .processSync('# Hello!\n\n```css\nh1{}\n```')
    return output
}
````

This line is the most important out of all of them and what cost me so much time. I could not find anything documenting the fact that if you turn sanitize: true or just omit it... it'll be true by default... you will loose everything `remarkHighlightjs` is doing

```ts
 .use(remarkHtml, {sanitize: false})
```

I also want to note: you can include or exclude certin languages from your highlighter. I'm not totally sure what the usecase is for this, but it's possible.

```ts
.use(remarkHighlightjs, {exclude: ['css', 'html']} )
```

also you can run `process()` instead of `processSync()` which will be an async call.

I know that probably seemed super basic, but sadly it was not well documented. I hope this clears up some confusion for others working on similar issues. One word of advice when looking at these tools if they don't work right... try stepping through the code with a debugger and see if things are working as you expect. Things can sighlently fail.

Last thing to note about this generall process. If you are tying to get syntax highlighting to work with this system you'll also need to include the highlight.js css file with the theme you'd like. Without it your class name that this process will add will not do anything.

## A Note About Nextjs

I built my blog using Next.js and static markdown files using this process. Currently Next.js has some sort of issue with ESM modules, so if you want to work with remark without a headach you can use the versions below otherwise you'll likely fight weird errors.

```json
"remark-highlight.js": "^6.0.0",
"remark-html": "^13.0.1",
"remark-parse": "^9.0.0",
"remark":"^9.0.0"
"unified": "^9.2.0"
```

## A Few Resources I Found Very Helpful

[This is a fantastic project and website that I used as a refrence](https://github.com/james-wallis/wallis.dev)

[Also Nextjs has a fantastic blog post on this as well](https://nextjs.org/blog/markdown)