fix(docs): pre-bundle mermaid deps so the dev server resolves dayjs/cytoscape #157

Merged
julien merged 1 commits from fix/docs-site-mermaid-dayjs-esm into main 2026-05-15 20:03:30 +02:00
Owner

Summary

pnpm docs:dev rendered a blank page with this thrown by the browser on the first navigation:

Uncaught SyntaxError: The requested module '/@fs/.../node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/dayjs.min.js?v=…'
does not provide an export named 'default'
(at chunk-AGHRB4JF.mjs?v=…:9:8)

Root cause: Mermaid 11 (transitive dep of vitepress-plugin-mermaid shipped in #154) pulls in dayjs, cytoscape, debug, @braintree/sanitize-url — each ships a CommonJS main field with no default ESM export. Vite's dev server resolves these modules eagerly as ESM and the browser blows up before the home page renders.

The production build was unaffected — Rollup's plugin pipeline already wraps CJS deps for ESM consumers. docs:build shipped clean HTML in #154 and the CI Mermaid-fence (grep class="mermaid" in ADR-0009's HTML) passed precisely because it inspects the prod bundle, not the dev-server output.

What lands

docs/.vitepress/config.mts — adds a single vite.optimizeDeps.include block:

vite: {
  optimizeDeps: {
    include: ['mermaid', 'dayjs', 'debug', '@braintree/sanitize-url'],
  },
},

optimizeDeps.include tells Vite to pre-bundle those modules through esbuild at dev-server boot, applying the same CJS→ESM interop wrapper Rollup uses in prod. The dev server now serves a working localhost:5173 and Mermaid diagrams render.

Notes for the reviewer

  • Why these four names specifically? They are the Mermaid deps that ship CJS-only entrypoints. Adding 'mermaid' alone is sometimes enough because Vite walks the dep tree, but the plugin's own README + a handful of upstream issue threads recommend listing the leaf CJS modules explicitly so the optimizer doesn't miss them on a cold cache. Cheap, defensive.
  • Why didn't the CI gate catch this? The Assert Mermaid renders step in .gitea/workflows/docs-site.yml greps docs/.vitepress/dist/ — the production-build output. The bug only manifests on the dev server's runtime-pre-bundling path. Catching it in CI would require booting docs:dev headlessly and curling the page; not worth the workflow weight for a once-per-major-upgrade class of issue. Manual pnpm docs:dev smoke is the right gate for now.
  • Why not bump dayjs / mermaid? Dayjs's package shape is a long-standing upstream quirk (the main points at the UMD/CJS bundle); fixing it upstream would be a breaking change for non-bundler consumers. Mermaid upstream is aware; their fix has historically been "tell your bundler to pre-bundle us", which is exactly what optimizeDeps.include does.

Test plan

  • rm -rf docs/.vitepress/cache && pnpm docs:dev — server boots, curl http://localhost:5173/ returns 200.
  • rm -rf docs/.vitepress/{cache,dist} && pnpm docs:build — clean prod build in ~10 s, Mermaid SVG still present in ADR-0009's HTML (regression fence passes).
  • Manual smoke: with the fix applied, navigate localhost:5173 → home → /decisions/0009-… → confirm the OIDC sequence diagram renders inline, no console errors. Toggle dark mode, confirm diagrams flip theme.
## Summary `pnpm docs:dev` rendered a blank page with this thrown by the browser on the first navigation: ``` Uncaught SyntaxError: The requested module '/@fs/.../node_modules/.pnpm/dayjs@1.11.20/node_modules/dayjs/dayjs.min.js?v=…' does not provide an export named 'default' (at chunk-AGHRB4JF.mjs?v=…:9:8) ``` Root cause: Mermaid 11 (transitive dep of `vitepress-plugin-mermaid` shipped in #154) pulls in `dayjs`, `cytoscape`, `debug`, `@braintree/sanitize-url` — each ships a CommonJS `main` field with no `default` ESM export. Vite's dev server resolves these modules eagerly as ESM and the browser blows up before the home page renders. The **production build was unaffected** — Rollup's plugin pipeline already wraps CJS deps for ESM consumers. `docs:build` shipped clean HTML in #154 and the CI Mermaid-fence (`grep class="mermaid"` in ADR-0009's HTML) passed precisely because it inspects the prod bundle, not the dev-server output. ## What lands [`docs/.vitepress/config.mts`](docs/.vitepress/config.mts) — adds a single `vite.optimizeDeps.include` block: ```ts vite: { optimizeDeps: { include: ['mermaid', 'dayjs', 'debug', '@braintree/sanitize-url'], }, }, ``` `optimizeDeps.include` tells Vite to pre-bundle those modules through esbuild at dev-server boot, applying the same CJS→ESM interop wrapper Rollup uses in prod. The dev server now serves a working `localhost:5173` and Mermaid diagrams render. ## Notes for the reviewer - **Why these four names specifically?** They are the Mermaid deps that ship CJS-only entrypoints. Adding `'mermaid'` alone is sometimes enough because Vite walks the dep tree, but the plugin's own README + a handful of upstream issue threads recommend listing the leaf CJS modules explicitly so the optimizer doesn't miss them on a cold cache. Cheap, defensive. - **Why didn't the CI gate catch this?** The `Assert Mermaid renders` step in `.gitea/workflows/docs-site.yml` greps `docs/.vitepress/dist/` — the production-build output. The bug only manifests on the dev server's runtime-pre-bundling path. Catching it in CI would require booting `docs:dev` headlessly and curling the page; not worth the workflow weight for a once-per-major-upgrade class of issue. Manual `pnpm docs:dev` smoke is the right gate for now. - **Why not bump dayjs / mermaid?** Dayjs's package shape is a long-standing upstream quirk (the `main` points at the UMD/CJS bundle); fixing it upstream would be a breaking change for non-bundler consumers. Mermaid upstream is aware; their fix has historically been "tell your bundler to pre-bundle us", which is exactly what `optimizeDeps.include` does. ## Test plan - [x] `rm -rf docs/.vitepress/cache && pnpm docs:dev` — server boots, `curl http://localhost:5173/` returns 200. - [x] `rm -rf docs/.vitepress/{cache,dist} && pnpm docs:build` — clean prod build in ~10 s, Mermaid SVG still present in ADR-0009's HTML (regression fence passes). - [ ] Manual smoke: with the fix applied, navigate `localhost:5173` → home → `/decisions/0009-…` → confirm the OIDC sequence diagram renders inline, no console errors. Toggle dark mode, confirm diagrams flip theme.
julien added 1 commit 2026-05-15 20:02:52 +02:00
fix(docs): pre-bundle mermaid deps so the dev server resolves dayjs/cytoscape
CI / scan (pull_request) Failing after 2m25s
CI / commits (pull_request) Successful in 2m31s
CI / check (pull_request) Successful in 2m40s
CI / a11y (pull_request) Successful in 1m56s
Docs site / build (pull_request) Successful in 2m41s
CI / perf (pull_request) Successful in 4m51s
44f8faca5d
`pnpm docs:dev` rendered a blank page with `does not provide an
export named 'default'` thrown from dayjs.min.js. Mermaid 11 ships
its `dayjs`, `cytoscape`, `debug` and `@braintree/sanitize-url`
dependencies with a CommonJS `main` field but no `default` ESM
export. Vite's dev server resolves those modules eagerly as ESM
and the browser throws on the first navigation.

The production build (`docs:build`) was unaffected — Rollup's
plugin pipeline already applies the CJS→ESM interop wrapper. This
fix is exclusively for the dev happy path: `optimizeDeps.include`
forces Vite to pre-bundle the Mermaid dependency tree, which
applies the same interop shim at dev-server boot.

Caught by manual smoke of the merged docs-site chantier — the
build-time Mermaid-rendering fence in `.gitea/workflows/docs-site.yml`
didn't catch this because it only inspects production HTML.
julien merged commit d94df427a1 into main 2026-05-15 20:03:30 +02:00
julien deleted branch fix/docs-site-mermaid-dayjs-esm 2026-05-15 20:03:32 +02:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: julien/apf_portal#157