Skip to content

fix(docs): render Mermaid/KaTeX on swup navigation (HYP-10, #82)#83

Draft
markovejnovic wants to merge 2 commits into
mainfrom
marko/hyp-10-docs-rendering-is-broken
Draft

fix(docs): render Mermaid/KaTeX on swup navigation (HYP-10, #82)#83
markovejnovic wants to merge 2 commits into
mainfrom
marko/hyp-10-docs-rendering-is-broken

Conversation

@markovejnovic

@markovejnovic markovejnovic commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

slop. need to review.


Problem

Mermaid diagrams and TeX math were broken on the published HexDocs site (e.g. https://hypervm.hexdocs.pm/architecture.html#storage) — reported in HYP-10 / #82.

Root cause (verified in a real headless browser)

ExDoc renders the docs as a swup single-page app: clicking a sidebar link, following an internal link, or landing via HexDocs search swaps page content client-side via fetch, with no full reload. The old before_closing_body_tag/1 initialized Mermaid on DOMContentLoaded and KaTeX via a <script onload=...> attribute — both fire only on the initial hard load. After any in-docs navigation neither refires, so Mermaid fences and $$…$$ math were left as raw source.

Reproduced with Playwright/Chromium against the live site and a local build:

  • Hard load architecture.html: 33 KaTeX elements + 1 Mermaid SVG ✅ (why it looked intermittent)
  • swup nav to the same page: 0 KaTeX, 0 Mermaid — raw \begin{cases} and raw <code class="mermaid"> visible ❌

Two secondary bugs found along the way: the Mermaid selector queried pre.mermaid, but ExDoc emits <pre><code class="mermaid"> (it only worked by accident via bare mermaid.run()); and the theme was read before ExDoc set the dark class.

Fix

Drive all rendering from ExDoc's window exdoc:loaded event, which fires on the initial load and after every swup content swap. Fix the Mermaid selector to lift pre > code.mermaid into div.mermaid, with an idempotent (:not([data-processed])) run so re-rendering across navigations is safe. Single-file change to mix.exs; KaTeX/Mermaid versions and the Mermaid SRI hash are unchanged.

Verification

Playwright harness (serving the built doc/ over HTTP so swup's fetch works):

  • Before fix — swup-nav case FAILs: {katex:0, mermaidSvg:0, leftoverRawMermaid:1}
  • After fix — both hard-load and swup-nav PASS: {katex:33, mermaidSvg:1, leftoverRawMermaid:0}
  • No-diagram page via swup: no JS exception (empty mermaid.run is a safe no-op)

Gate green: mix format --check-formatted, compile --warnings-as-errors, credo --strict, test (438 passed), dialyzer (0 errors).

Note: the change ships to readers on the next docs publish; nothing renders differently until HexDocs rebuilds from this mix.exs.

Closes #82.

ExDoc uses swup for client-side page transitions, so DOMContentLoaded and
the KaTeX auto-render onload fire only on the initial hard load. After any
in-docs navigation (sidebar link, internal link, HexDocs search) both
Mermaid diagrams and $$..$$ math were left as raw source. Drive all
rendering from ExDoc's window `exdoc:loaded` event, which fires on the
initial load and after every swup content swap. Also fix the Mermaid
selector: ExDoc emits <pre><code class="mermaid">, not <pre class="mermaid">.

Closes HYP-10 (#82).
@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown

Test Results

    4 files  ± 0  227 suites  ±0   3m 21s ⏱️ - 1m 4s
  675 tests + 6  675 ✅ +6    0 💤 ±0  0 ❌ ±0 
1 151 runs  +12  675 ✅ +6  476 💤 +6  0 ❌ ±0 

Results for commit 5567e24. ± Comparison against base commit f6f88dd.

This pull request removes 2 and adds 8 tests. Note that renamed tests count towards both.
Elixir.HyperTest ‑ test exec/3 with a pid that is not a VM supervisor returns {:error, :not_found}
Elixir.HyperTest ‑ test exec/3 with an unregistered vm_id returns {:error, :not_found}
Elixir.Hyper.Metering.UsageTest ‑ test Hyper.usage/1 across a VM's lifetime a stopped-but-metered VM reports its recorded lifetime total
Elixir.Hyper.Metering.UsageTest ‑ test Hyper.usage/1 across a VM's lifetime an entirely unknown VM is :not_found
Elixir.Hyper.Metering.UsageTest ‑ test Hyper.usage/1 across a VM's lifetime usage/1 resolves a pid handle to its vm_id and delegates
Elixir.HyperTest ‑ test exec/3 by a non-supervisor pid refuses with {:error, :not_found}
Elixir.HyperTest ‑ test exec/3 by an unregistered vm_id refuses with {:error, :not_found}
Elixir.HyperTest ‑ test fork_vm/1 by an unregistered vm_id refuses with {:error, :not_found}
Elixir.HyperTest ‑ test id/1 answers nil when the VM's owning node is unreachable
Elixir.HyperTest ‑ test usage/1 by a non-supervisor pid refuses with {:error, :not_found}

♻️ This comment has been updated with latest results.

@markovejnovic markovejnovic marked this pull request as draft July 13, 2026 22:42
Replace the hand-rolled DOM surgery with the snippet ExDoc's own README
prescribes: two `exdoc:loaded` listeners, KaTeX via renderMathInElement, and
Mermaid via mermaid.render() per <pre code.mermaid> block. Drops the unused
\[ / \( delimiters (docs use only $ / $$), which removes the quad-backslash
heredoc escaping, and loads mermaid with defer to match the reference. Same
behavior, verified: KaTeX + Mermaid render on both hard load and swup nav.
@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

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.

Docs rendering is broken

1 participant