Learn Shiki Rehype Pretty Code - Setup & Hello World
Episode 3 of 23

Learn Shiki Rehype Pretty Code - Setup & Hello World

You will install shiki and rehype-pretty-code, then assemble a minimal unified pipeline that turns Markdown into HTML with syntax highlighting. At the end of the episode there is a first code block ready to use in your project.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

The architecture theory in episode 2 is enough. Now you'll get your hands dirty with real code. Episode 3 is the setup and hello world: installing dependencies, assembling a minimal pipeline, and seeing the first highlighted HTML produced from plain Markdown.

The goal of this episode is simple but important: a Node.js script that converts a Markdown string containing a code block into full HTML with syntax highlighting. From this point you can test every option discussed in the following episodes.

Setting Up the Project and Installation

Initializing a Node.js Project

Start from an empty folder. Initialize the project with npm or bun, then install the two main packages. Both are ESM-only, so make sure the value "type": "module" is present in package.json.

Initialize the project
mkdir learn-shiki
cd learn-shiki
npm init -y
npm i shiki rehype-pretty-code

The rehype-pretty-code package pulls shiki in as a dependency, but installing it explicitly makes it easier to manage versions and use the Shiki API directly when needed. It's best to always install both so the versions in use are clear.

Supporting Pipeline Plugins

Besides the two main packages, the unified pipeline needs the official plugins from the unified ecosystem:

Install pipeline plugins
npm i unified remark-parse remark-rehype rehype-stringify

unified is the pipeline core, remark-parse turns Markdown into an MDAST tree, remark-rehype converts it to HAST, and rehype-stringify produces the final HTML string. Without these four, rehype-pretty-code has no stage to work on.

Your First Minimal Pipeline

Assembling the Pipeline in a JavaScript File

Create a highlight.mjs file with the following contents. This pipeline accepts Markdown text and returns highlighted HTML.

JShighlight.mjs
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import rehypePrettyCode from "rehype-pretty-code";
import rehypeStringify from "rehype-stringify";
 
const md = [
  "```ts",
  'const pesan: string = "Halo Shiki";',
  "console.log(pesan);",
  "```",
].join("\n");
 
const html = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypePrettyCode, { theme: "github-dark-default" })
  .use(rehypeStringify)
  .process(md);
 
console.log(html.toString());

Notice the .use() order that must be exact: parse, then conversion to HAST, then rehype-pretty-code, finally stringify. rehypePrettyCode(options) is installed right before rehypeStringify.

Running and Inspecting the Output

Run the script to see the generated HTML:

Run the pipeline
node highlight.mjs

The output will contain <pre> and <code> with many color-styled <span> elements. This is where the magic happens: the TypeScript code has been tokenized and colored without a single piece of JavaScript running in the browser.

Checking the Result in the Browser

Saving the Output as an HTML File

To see the visual result, modify the script to write the output to an output.html file and open it in the browser:

JSSave output to a file
import { writeFile } from "node:fs/promises";
 
const hasil = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypePrettyCode, { theme: "github-dark-default" })
  .use(rehypeStringify)
  .process(md);
 
await writeFile("output.html", hasil.toString());
Open in the browser
node highlight.mjs
xdg-open output.html

What You Should See

In the browser, you'll see code colored according to the github-dark-default theme. Open DevTools and inspect the element structure: every token is wrapped in a <span> with an inline color. This structure will change slightly later when rehype-pretty-code adds data attributes in episode 4.

If you see text without colors, it's likely that the pipeline isn't running rehype-pretty-code at all, or the theme name used is wrong. Re-check the plugin order and the spelling of the theme name.

Conclusion

Key takeaways:

  • Shiki and rehype-pretty-code are installed as ESM dependencies.
  • The unified pipeline needs four plugins: parse, HAST, highlight, stringify.
  • The order of plugin installation determines highlighting success.
  • rehypePrettyCode is installed after remarkRehype and before rehypeStringify.
  • The output is colored HTML spans you can view in the browser.
  • DevTools becomes the main tool for inspecting the result.

In episode 4 you'll dissect the basic options of rehype-pretty-code: theme, keepBackground, defaultLang, grid, and bypassInlineCode, plus understand the <figure>, <pre>, and <code> structure along with the data attributes generated. All these options will shape the way you present code.