Installation and Basic Usage
Shiki provides syntax highlighting for a wide range of languages and themes. When converting Markdown to HTML via unified, the @shikijs/rehype plugin handles code block highlighting automatically.
Installation
First, install the Shiki-related packages in your project. You can use the following command to install @shikijs/rehype.
npm i -D @shikijs/rehype
Usage
To use Shiki, you will process the Markdown file and convert it to HTML using plugins from the remark and rehype series along with unified. Here is a basic usage example.
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeShiki from '@shikijs/rehype';
const file = await unified()
.use(remarkParse) // Parse Markdown
.use(remarkRehype) // Convert to HTML
.use(rehypeShiki, {
// Single theme
// theme: 'vitesse-light' // Use a single theme
// Multiple themes
themes: {
light: 'vitesse-light', // Light theme
dark: 'vitesse-dark' // Dark theme
}
})
.use(rehypeStringify) // Convert to HTML string
.process(await fs.readFile('./input.md')); // Read and process the Markdown file
This code reads a file named input.md, applies Shiki with light/dark themes to the code blocks in that file, and converts it to HTML.
Managing Shiki Instances
By default, the default export of @shikijs/rehype uses a shared Shiki instance from getSingletonHighlighter. This allows the instance to persist across multiple processes. However, if you want to have complete control over the lifecycle of the Shiki highlighter, you can use the fine-grained bundle from @shikijs/rehype/core.
Using the Fine-Grained Bundle
If you want to load only the necessary parts instead of the entire Shiki bundle, you can use rehypeShikiFromHighlighter. Here is an example of using the fine-grained bundle.
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
import { createHighlighterCore } from 'shiki/core';
const highlighter = await createHighlighterCore({
themes: [
import('shiki/themes/vitesse-light.mjs') // Light theme
],
langs: [
import('shiki/langs/javascript.mjs') // JavaScript language highlighting
],
loadWasm: import('shiki/wasm') // Load WASM file
});
const raw = await fs.readFile('./input.md');
const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeShikiFromHighlighter, highlighter, {
themes: {
light: 'vitesse-light',
dark: 'vitesse-dark'
}
})
.use(rehypeStringify)
.processSync(raw); // Can be processed synchronously
In this example, you can selectively load only the necessary themes and languages. This can reduce the bundle size and provide better performance.