Code highlighting
Pluto colors no code by default: a code block of a post reaches the site as plain text, in <pre><code class="language-ts">. A highlighter is something you add:
- The syntax colors layer (
@plutocms/syntax-lowlight, with lowlight): install it and import its theme. - Shiki, or another library: register it in a Nitro plugin of your site (see below).
- An add-on layer of your own.
Pluto runs the highlighter on the server, when the public API sends a post. Every backend gets it, a page needs no JavaScript for it, and a static build colors the code when it builds. The preview of the post editor shows the same colors.
How a highlighter works
A highlighter is a function that gets the code and the language of one block (ts, python, the word after the backticks), and returns HTML:
- the inside of the
<code>element: spans with classes, like lowlight; - or a whole
<pre>element, like Shiki; - or nothing, for a language it does not know. The next highlighter tries, and with none left the block stays plain.
A block with no language stays plain.
Register it with definePlutoHighlighter in a Nitro plugin:
export default defineNitroPlugin(() => {
definePlutoHighlighter({
id: 'mine',
order: 50,
highlight({ code, lang }) {
if (lang !== 'ts') {
return null
}
return myHighlighter(code) // escape the code: it is plain text
},
})
})
The function can be async. Pluto keeps the result of each block in memory, so the same code is colored once.
pre, code and span, classes, and colors and font styles in style (custom properties such as --shiki-dark too). Everything else goes. Escape the code in your highlighter: Pluto reads any < that is left as markup.Choose the highlighter
With more than one highlighter, Pluto tries them by order, lowest first (the default is 100). To try one first, set its id:
export default defineNuxtConfig({
runtimeConfig: {
plutoApi: { highlighter: 'shiki' },
},
})
Or set NUXT_PLUTO_API_HIGHLIGHTER=shiki in the environment. The others still color the languages that the first one does not know.
Shiki
Shiki gives the colors of VS Code themes, with a light and a dark theme at once. Install it, then register it:
npm install shiki
import { createHighlighter } from 'shiki'
const shiki = createHighlighter({
themes: ['github-light', 'github-dark'],
langs: ['ts', 'js', 'vue', 'bash', 'json', 'css', 'html'],
})
export default defineNitroPlugin(() => {
definePlutoHighlighter({
id: 'shiki',
order: 50,
async highlight({ code, lang }) {
const highlighter = await shiki
try {
return highlighter.codeToHtml(code, {
lang,
themes: { light: 'github-light', dark: 'github-dark' },
})
} catch {
return null // a language that this highlighter did not load
}
},
})
})
Shiki writes the light colors, and the dark ones as --shiki-dark variables. Switch to them in the CSS of your site:
.dark .shiki,
.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: var(--shiki-dark-bg) !important;
}
Load only the languages that your posts use: each one adds to the server bundle.