[NextJS] Blog Overhaul Journey - 4. Implementing a Markdown Converter Using marked
[NextJS] Blog Overhaul Journey - 4. Implementing a Markdown Converter Using marked
Static blogs make heavy use of Markdown, because it's very familiar as a plain-text format while also having excellent compatibility with HTML.
My previous blog used the Remark and Rehype plugins. With various plugins available, they were quite convenient for basic use, but it was very difficult for a user to customize the conversion process directly.
I wanted to add extra functionality and styling to TOCs, code blocks, and links by attaching HTML tags, but since there was no relevant API, I had no choice but to use whatever tags were given as-is.
While researching this, the marked plugin seemed to satisfy what I wanted, so during the blog overhaul I made many changes to the Markdown plugin as well.
This chapter covers the process of converting Markdown to HTML using marked.
If you think about how we normally write on the web, though, it's not a familiar concept. Think about a situation where you'd write a post on the web—like writing a forum post or an email—you probably haven't heard of Markdown in that context.
So why use Markdown despite that? Using Markdown gives you the following advantages.
- Excellent compatibility with HTML.
- Being text-based, it's easier to write than the HTML approach.
- Even people without HTML knowledge can easily write HTML documents.
- There's Markdown syntax that maps to the major HTML tags, and it's much easier than HTML.
- When needed, you can mix Markdown and HTML tags together.
- No separate editor (e.g. Naver Smart Editor) is required, giving it excellent accessibility.
Markdown has excellent compatibility with HTML, and converting between the two is very easy. In any case, to apply content to a web page, the final result must ultimately be in HTML form.
If you were to write the same content directly in HTML, the efficiency of writing would drop significantly due to HTML's tag-centric syntax. Even just writing sentences, you'd have to wrap each one in a p tag.
By comparison, Markdown, which is nearly identical to writing plain text, lets users write relatively comfortably while still being easily convertible to HTML, making it very well suited for use on the web.
Also, Markdown isn't just an abstract concept but a file format with a defined extension in the file system, so it can be easily written even in an offline environment using nothing but Notepad or a vi editor, without any special tools.
On top of that, even if you write raw HTML tags directly inside Markdown, it will convert them automatically! This means that if the author has knowledge of HTML, they can input HTML tags directly to write richer posts that go beyond plain text.
Because of these advantages and its developer-friendly nature, Markdown is mainly used on development-related platforms and static blogs.
Let's apply the marked plugin through the process below.
BASH
npm install marked --save-dev yarn add marked -dev
Install marked using the command above.
TYPESCRIPT
const marked = require('marked'); const body = ` # h1 header Loren ipsum **test** area [link](https://blog.itcode.dev)  <span class="red">native html tag</span> `; const result = marked(body); // Display HTML content console.log(result.toString());
That's how you convert Markdown to HTML with marked.
As a result, it's transformed as shown below.
MARKDOWN
# h1 header Loren ipsum **test** area [link](https://blog.itcode.dev)  <span class="red">native html tag</span>
HTML
<h1 id="h1-header">h1 header</h1> <p>Loren ipsum <strong>test</strong> area</p> <p><a href="https://blog.itcode.dev">link</a></p> <p><img src="https://blog.itcode.dev/img/" alt="image"></p> <p><span class="red">native html tag</span></p>
This is how Markdown gets converted to HTML. Depending on which conversion plugin you use, the result may be transformed slightly differently.
This is actually the biggest reason I ended up using marked. marked provides renderer and tokenizer as APIs. Through these two APIs, you can customize how specific tags are converted. You don't need to pointlessly bolt on plugin after plugin, and since you can design the conversion process yourself, it should be easy to add feature improvements or styling.
The HTML conversion process of marked can broadly be divided into tokenization and rendering, so let's directly work with each of these processes through their respective APIs.
tokenizer defines how Markdown text is converted into tokens. When you specify a tokenizer, it's merged with the existing tokenizer and redefined according to the tokenizer the developer wrote.
It seems like you can roughly customize the default tokenization process directly, but what exactly is a token, and what's it used for?
Markdown converts its own syntax into the matching HTML tags. marked performs a tokenization process to predefine this conversion. All Markdown text is classified into appropriate tokens. Link syntax [link](https://example.com) is classified as a link token, image syntax  is classified as an image token, and so on. To classify these, Markdown syntax patterns are defined, and matching strings are found using those patterns.
If a developer wants to add a string with a particular pattern as image syntax, they just need to find strings with that syntax and replace them with an image token.
TYPESCRIPT
// Declare marked const marked = require('marked'); // Redefine tokenizer const tokenizer = { codespan(src) { const match = src.match(/\$+([^\$\n]+?)\$+/); // If the pattern matches if (match) { return { type: 'codespan', raw: match[0], text: match[1].trim() }; } return false; } }; marked.use({ tokenizer }); // Convert console.log(marked('$ latex code $\n\n` other code `'));
The code above redefines the codespan token. codespan is this syntax, mainly used to display code.
LaTeX, which expresses mathematical formulas, uses dollar signs as a wrapper, which isn't official Markdown syntax. To use LaTeX, we detect inline text wrapped in dollar signs and designate it as a codespan token. This lets us display formulas like .
In codespan(src), the Markdown text is passed in via the src argument. Design a regular expression to specify the pattern of the syntax you want, and if it matches, redefine it as the token you want. If you return false, it falls back to the default tokenizer configuration.
- type - the token type
- raw - the entire content of the token
- text - the text content of the token
That's the content of the token object.
Besides codespan, you can redefine various other tokens like table and header. For more details, see the marked official documentation - tokenizer.
renderer defines how each token is converted into HTML. All Markdown text is assigned a token matching the defined pattern, and the renderer analyzes that token and converts it into the HTML for the designated token.
In other words, the developer can directly define how each tag is converted.
TYPESCRIPT
// Create reference instance const marked = require('marked'); // Override function const renderer = { heading(text, level) { const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); return ` <h${level}> <a name="${escapedText}" class="anchor" href="#${escapedText}"> <span class="header-link"></span> </a> ${text} </h${level}>`; } }; marked.use({ renderer }); // Run marked console.log(marked('# heading+'));
HTML
<h1> <a name="heading-" class="anchor" href="#heading-"> <span class="header-link"></span> </a> heading+ </h1>
The code above redefines the rendering of header tags like h1 and h2. This process builds a frame that puts a link inside the header tag, so that clicking the header focuses on that heading.
In heading(text, level), the text argument refers to the content of the header tag, and the level argument refers to the depth of the header tag. For h4, level would be assigned 4.
You just need to build and return the appropriate HTML tag using these two arguments. Besides headers, you can redefine various other renderers as well. For more details, see the marked official documentation - renderer.
marked provides a variety of useful APIs related to HTML conversion. By making good use of these APIs, you can implement a Markdown converter unique to your own blog.

![[OAuth2.0] Building an OAuth2.0 Authentication Server with ScribeJAVA - 9. Providing RESTful API Services with Jersey](https://user-images.githubusercontent.com/50317129/137171016-99af1db1-a346-4def-9329-6072b927bdc0.png)