#3216·mdBook

`preload-js` for custom highlightjs/ace support

Author: dalanceCreated Sep 4, 2026Updated Sep 4, 2026
LabelsC-enhancement

Problem

This is a part of #3124.

Now there is no way to override highlightjs/ace language without theme override. About custom highlightjs, some issues had been opened previously (ex. #2505, #657, #1459), but this issue aims for a complete resolution of both highlightjs and ace.

If this issue is resolved, user can easily add custom language playground by the way of #3124.

Proposed Solution

  • add preload-js field to book.toml
  • change load order and insert preload-js

https://github.com/rust-lang/mdBook/blob/a57975d499a660fd11da05a9010e93fe245525ba/crates/mdbook-html/front-end/templates/index.hbs#L309

+        <script src="{{ resource "highlight.js" }}"></script>
         {{#if playground_js}}
         <script src="{{ resource "ace.js" }}"></script>
         <script src="{{ resource "mode-rust.js" }}"></script>
+        {{/if}}
+
+        {{#each preload_js}}
+        <script src="{{ resource this }}"></script>
+        {{/each}}
+
+        {{#if playground_js}}
         <script src="{{ resource "editor.js" }}"></script>
         <script src="{{ resource "theme-dawn.js" }}"></script>
         <script src="{{ resource "theme-tomorrow_night.js" }}"></script>
@@
         <script src="{{ resource "clipboard.min.js" }}"></script>
-        <script src="{{ resource "highlight.js" }}"></script>
         <script src="{{ resource "book.js" }}"></script>
  • change ace mode by language

https://github.com/rust-lang/mdBook/blob/a57975d499a660fd11da05a9010e93fe245525ba/crates/mdbook-html/front-end/playground_editor/editor.js#L8

+    function playground_mode(editable) {
+        const cls = Array.from(editable.classList)
+            .find(c => c.startsWith("language-"));
+        return cls ? "ace/mode/" + cls.slice("language-".length)
+                   : "ace/mode/rust";
+    }
+
     Array.from(document.querySelectorAll('.editable')).forEach(function(editable) {
@@
-        editor.getSession().setMode("ace/mode/rust");
+        editor.getSession().setMode(playground_mode(editable));

By this change, user can specify custom language syntax like below, and they are effective because they are load after highlight.js, ace.js and before book.js.

[output.html]
preload-js = ["hljs-example.js", "mode-example.js"]

Notes

No response