Files
novaconium/novaconium/pages/admin/docs/upgrading-highlightjs/index.twig
T
code cb64836901 Add syntax highlighting on code blocks, plus a Code Highlighting post
Colors <pre><code> blocks site-wide via vendored highlight.js v11.11.1
(pinned to that stable tag, not main, which tracks an in-progress
11.0.0-beta1), auto-detected and restricted to
configure({ languages: ['php', 'bash', 'xml', 'css', 'python',
'javascript', 'yaml', 'json', 'ini'] }) - no per-block markup needed for
the ~60 existing code blocks across the site. css/python/javascript ship
in the core bundle; yaml/json/ini (ini covers .env-style files too)
don't and are vendored as separate per-language files.

Themes swap with the existing dark/light toggle: ir-black (dark) +
github (light, resolving the entry's own open question), via the same
data-theme-driven mechanism as the main palette
(syntax-highlight-init.twig/syntax-highlight.twig, mirroring
theme-init.twig/nav.twig's split) - a MutationObserver swaps the theme
link live without touching the existing toggle button's click handler.

Twig-syntax code blocks have no highlight.js grammar and are marked
class="nohighlight" by hand (15 blocks across 9 files, found by grepping
for literal {% %}/{{ }} syntax rather than guessing) rather than
force-matched into the restricted candidate set, which would color them
wrong instead of leaving them plain.

One correction to the original backlog entry's suggested approach: it
suggested vendoring highlight.js under novaconium/vendor/ next to Twig.
That would have silently 404ed on every request - Twig is server-side
PHP, never fetched by a browser, but highlight.js's .js/.css files are,
and only public/ is web-reachable. Vendored to public/vendor/highlightjs/
instead; documented in AGENTS.md and a new upgrading-highlightjs doc,
since public/ isn't touched by the usual novaconium/-swap framework
update workflow, so a future highlight.js bump won't propagate to
existing projects automatically the way it does for everything else
under novaconium/.

Caught two real bugs via testing rather than review: hljs.highlightAll()
silently no-ops if called before the document finishes parsing rather
than deferring itself, and a bash example starting with the word "php"
auto-detects as PHP, not bash.

Also adds App/pages/blog/code-highlighting/ - a new blog post
demonstrating the feature with a verified worked example in each of the
nine languages, plus how to force a language via an explicit
language-<name> class when auto-detection isn't enough.

Closes the "Syntax highlighting on code blocks" backlog item in
novaconium/ISSUES.md.
2026-07-14 19:00:48 +00:00

45 lines
6.1 KiB
Twig

{% extends 'admin/docs/_layout/layout.twig' %}
{% block title %}Upgrading highlight.js{% endblock %}
{% block description %}How to bump the vendored copy of highlight.js.{% endblock %}
{% block robots %}noindex, nofollow{% endblock %}
{% block docs_content %}
<h1>Upgrading vendored highlight.js</h1>
<p>Like Twig (see <a href="/admin/docs/upgrading-twig">Upgrading Twig</a>), highlight.js is vendored by hand — no Composer, no npm, no lockfile. Upgrading is a manual copy-and-verify process.</p>
<h2>The one thing that makes this different from every other vendored/framework file</h2>
<p>Everything else under <code>novaconium/</code> gets refreshed automatically when a project runs the <a href="/admin/docs/getting-started">"Updating the framework"</a> workflow (<code>rm -rf novaconium && cp -r &lt;new-novaconium&gt;</code>). highlight.js is vendored under <code>public/vendor/highlightjs/</code> instead, because its files are fetched by the browser and only <code>public/</code> is the Apache document root — <code>novaconium/</code> isn't web-reachable at all. <code>public/</code> is project-owned and that update workflow never touches it. <strong>A future framework release that bumps the vendored highlight.js version will not update it on an existing project automatically</strong> — re-vendoring it is a separate, manual step, following this page, even after an otherwise-routine framework update.</p>
<h2>What's currently vendored</h2>
<ul>
<li>Version: <strong>11.11.1</strong> (see the version comment at the top of <code>public/vendor/highlightjs/highlight.min.js</code> — that comment is always the source of truth, this doc can drift).</li>
<li>The root <code>build/highlight.min.js</code> bundle from <a href="https://github.com/highlightjs/cdn-release">highlightjs/cdn-release</a> — includes <code>php</code>, <code>bash</code>, <code>css</code>, <code>python</code>, <code>javascript</code>, and <code>xml</code> (covers HTML) out of the box.</li>
<li>Three separate per-language files under <code>public/vendor/highlightjs/languages/</code> — <code>yaml.min.js</code>, <code>json.min.js</code>, <code>ini.min.js</code> (covers <code>.env</code>-style key/value files too) — checked, not assumed, that these aren't part of the core bundle before vendoring them separately from <code>build/languages/</code> in the same <code>cdn-release</code> repo, at the same pinned tag.</li>
<li>Two themes: <code>public/vendor/highlightjs/styles/ir-black.min.css</code> (dark) and <code>styles/github.min.css</code> (light), swapped via the site's existing <code>data-theme</code> toggle — see <a href="/admin/docs/styling">Styling</a>.</li>
<li><code>public/vendor/highlightjs/LICENSE</code> (BSD-3-Clause) — covers the per-language files too, same license, same repo.</li>
</ul>
<p>All nine languages are why <code>hljs.configure({ languages: [...] })</code> in <code>novaconium/pages/_layout/syntax-highlight.twig</code> lists <code>['php', 'bash', 'xml', 'css', 'python', 'javascript', 'yaml', 'json', 'ini']</code> — see <a href="/blog/code-highlighting">the Code Highlighting post</a> for a worked example of each.</p>
<h2>How to upgrade</h2>
<ol>
<li>Pick a target version from the <a href="https://github.com/highlightjs/cdn-release/tags">cdn-release tags</a> — always a stable tag (e.g. <code>11.x.y</code>), never the <code>main</code> branch, which tracks an in-progress pre-release (this project's own vendored copy was pinned from tag <code>11.11.1</code> specifically for this reason, not <code>main</code>).</li>
<li>Download, from that same tag: <code>build/highlight.min.js</code>, <code>build/languages/yaml.min.js</code>, <code>build/languages/json.min.js</code>, <code>build/languages/ini.min.js</code>, <code>build/styles/ir-black.min.css</code>, <code>build/styles/github.min.css</code>, and <code>build/LICENSE</code>.</li>
<li>Replace the seven files under <code>public/vendor/highlightjs/</code> wholesale (<code>highlight.min.js</code>, the three files under <code>languages/</code>, the two under <code>styles/</code>, and <code>LICENSE</code>).</li>
<li>Confirm <code>php</code>, <code>bash</code>, <code>css</code>, <code>python</code>, and <code>javascript</code> are still present in the new core bundle (e.g. <code>grep -o '"php"' highlight.min.js</code>) — the root bundle's included-language set can change between releases; if one of these ever drops out, either vendor that language's individual file from <code>build/languages/</code> the same way <code>yaml</code>/<code>json</code>/<code>ini</code> already are, or adjust <code>hljs.configure({ languages: [...] })</code> to match what's actually available.</li>
<li>Run the app and check: code blocks still get colored on <a href="/blog/code-highlighting">the Code Highlighting post</a> (all nine languages, one worked example each) and the theme still swaps live with the dark/light toggle, and a <code>class="nohighlight"</code> Twig-syntax block (e.g. on <code>/admin/docs/seo</code>) still renders plain, uncolored. There's no automated test suite, so this is the real regression check.</li>
<li>Update the version note at the top of this page.</li>
</ol>
<h2>Adding a new highlighted language</h2>
<p>If a project adds code blocks in a language outside the nine above, vendor that language's file from <code>build/languages/&lt;name&gt;.min.js</code> in <code>cdn-release</code> (at the same pinned tag as everything else) into <code>public/vendor/highlightjs/languages/</code>, add a <code>&lt;script src="/vendor/highlightjs/languages/&lt;name&gt;.min.js"&gt;&lt;/script&gt;</code> tag after the core bundle (and after the other <code>languages/</code> scripts, order between them doesn't matter) in <code>novaconium/pages/_layout/syntax-highlight.twig</code>, and add the language's name to the <code>hljs.configure({ languages: [...] })</code> call there — each language file self-registers against the global <code>hljs</code> via its own <code>hljs.registerLanguage(...)</code> call once loaded, no other wiring needed.</p>
{% endblock %}