Skip to content

Highlight code blocks on the server with chroma - #693

Merged
compscidr merged 1 commit into
mainfrom
compscidr/syntax-highlight-code-blocks-on-the-server-block
Oct 17, 2026
Merged

compscidr merged 1 commit into
mainfrom
compscidr/syntax-highlight-code-blocks-on-the-server-block

Conversation

@compscidr

Copy link
Copy Markdown
Collaborator

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.

  • Unlabelled fences are guessed with chroma's analyser (WithGuessLanguage). It's weak: in a quick check it identified Go (with an import), a #!/bin/bash script 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.
  • Palette: chroma's classes in its github style, appended to www/css/base.css with highlight.js's padding and scrolling. Themes can restyle .chroma in their goblog.css, which loads after it.
  • UPGRADING.md covers labelling fences and removing hljs.highlightAll() from theme footers.

Not covered:

  • Code in comments stays plain. The comment sanitiser strips chroma's classes, and highlight.js used to colour it.
  • Indented (non-fenced) code blocks aren't highlighted.
  • goblog-site-theme and goblog-theme-forest still call hljs.highlightAll() in footer.html. That throws a console ReferenceError until they're updated; nothing else breaks.

Test plan

  • go test ./...
  • New TestPostHTML_HighlightsCode: covers a labelled fence, a guessed fence, and an unguessable fence (escaped plain text)

🤖 Generated with Claude Code

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>
Copilot AI balanced review requested due to automatic review settings October 17, 2026 09:31
@codecov

codecov Bot commented Oct 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 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 authorMarkdown goldmark renderer and bundle the github palette into base.css.
  • Remove the highlight.js script/stylesheet from _head.html and the hljs.highlightAll() bootstrap from the default theme's footer.html.
  • Document the migration (label fences, drop hljs.highlightAll()) in UPGRADING.md and add TestPostHTML_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

@compscidr
compscidr merged commit 9080319 into main Oct 17, 2026
7 of 8 checks passed
@compscidr
compscidr deleted the compscidr/syntax-highlight-code-blocks-on-the-server-block branch October 17, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Syntax-highlight code blocks on the server (blocked on unlabelled fences)

2 participants