Repository navigation
Highlight code blocks on the server with chroma - #693
Conversation
Fenced code in posts and pages is coloured at markdown time with goldmark-highlighting, so highlight.js and its stylesheet no longer load. Unlabelled fences are guessed with chroma's analyser; a block it cannot identify renders as plain text until its fence is labelled. Colours are chroma's "github" classes in www/css/base.css, which themes can override. Closes #625 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
🔵 Needs a closer look
It changes the core server-side content rendering path for every post/page and adds new runtime dependencies, with a known visible regression (unlabelled fences across much of the existing archive rendering as plain text) that a human maintainer should sign off on.
No open issues 🎉
What changed in this PR
This PR moves fenced-code syntax highlighting from client-side highlight.js to server-side rendering with chroma (via goldmark-highlighting), resolving #625. Fenced code is now coloured when markdown is rendered for posts, pages, and the admin Preview tab, so the highlight.js script and stylesheet are dropped (two fewer CDN requests, no flash of uncoloured code, and colour without JavaScript). Chroma's github-style classes are added to www/css/base.css so themes can restyle .chroma in their own CSS. Because almost no existing fences name a language, unlabelled fences are guessed and fall back to plain text when chroma can't identify them — a documented migration cost covered in UPGRADING.md.
Changes:
- Add chroma highlighting (class-based, with language guessing) to the
authorMarkdowngoldmark renderer and bundle thegithubpalette intobase.css. - Remove the highlight.js script/stylesheet from
_head.htmland thehljs.highlightAll()bootstrap from the default theme'sfooter.html. - Document the migration (label fences, drop
hljs.highlightAll()) inUPGRADING.mdand addTestPostHTML_HighlightsCode.
| File | Description |
|---|---|
blog/render.go |
Adds the chroma highlighting extension (guess language + class output) to the author markdown renderer. |
www/css/base.css |
Adds chroma github-style classes (.chroma and token classes) with highlight.js-like padding/scrolling. |
templates/shared/_head.html |
Removes the highlight.js script and stylesheet CDN links. |
themes/default/templates/footer.html |
Removes the hljs.highlightAll() DOMContentLoaded bootstrap. |
go.mod / go.sum |
Adds chroma/v2 and goldmark-highlighting/v2 (and regexp2/v2 indirect). |
blog/render_test.go |
Adds TestPostHTML_HighlightsCode; relaxes a GFM assertion now that tokens are split into spans. |
UPGRADING.md |
Documents labelling fences and removing hljs.highlightAll() from themes. |
Review effort: Balanced
Closes #625.
Fenced code in posts and pages is now coloured at markdown time with goldmark-highlighting (chroma). highlight.js and its stylesheet no longer load, so that's two fewer CDN requests on post and admin pages, no flash of uncoloured code, and colour without JavaScript. The admin Preview tab is coloured too: it renders on the server, and highlight.js never ran on it.
WithGuessLanguage). It's weak: in a quick check it identified Go (with an import), a#!/bin/bashscript and C, but not a bare shell command, Python, JSON, HTML, YAML or Java. Anything it can't identify renders as plain text, and labelling the fence fixes it. Expect most of the 36 posts to need labels.githubstyle, appended towww/css/base.csswith highlight.js's padding and scrolling. Themes can restyle.chromain theirgoblog.css, which loads after it.UPGRADING.mdcovers labelling fences and removinghljs.highlightAll()from theme footers.Not covered:
hljs.highlightAll()infooter.html. That throws a consoleReferenceErroruntil they're updated; nothing else breaks.Test plan
go test ./...TestPostHTML_HighlightsCode: covers a labelled fence, a guessed fence, and an unguessable fence (escaped plain text)🤖 Generated with Claude Code