From dca6c7f43d49ecb9e92411681503895244823383 Mon Sep 17 00:00:00 2001 From: Stefan Ernst <24554551+stefan-ernst@users.noreply.github.com> Date: Mon, 2 Nov 2026 22:07:31 +0100 Subject: [PATCH] perf(frontend): split the optional editors into named chunks (WI-1916) The build named only milkdown/dnd/xterm, so Excalidraw, mermaid and cytoscape landed in opaque chunk-* files shared with unrelated code. Add explicit groups for the three libraries and extend the entry guard to reject mermaid/cytoscape assets in index.html. includeDependenciesRecursively: false keeps each group to the modules it names; with the default Excalidraw absorbs mermaid and mermaid absorbs cytoscape, producing one multi-megabyte chunk per group. The app locales and shiki grammars stay per-file dynamic imports (one chunk per locale/language) and are deliberately not grouped. Main entry payload: 187.1 KiB before and after (root shell 28.6 KiB raw / 11.6 KiB gzip, under the 50/20 budget). Total JS 19.69 MB -> 19.66 MB. --- frontend/scripts/check-entry-assets.js | 2 ++ frontend/vite.config.js | 31 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/frontend/scripts/check-entry-assets.js b/frontend/scripts/check-entry-assets.js index f0f046728..01dffb414 100644 --- a/frontend/scripts/check-entry-assets.js +++ b/frontend/scripts/check-entry-assets.js @@ -10,6 +10,8 @@ const defaultIndexPath = path.resolve(scriptDir, '../dist/index.html'); const forbiddenEntryAssets = [ { name: 'Excalidraw', pattern: /(?:excalidraw|mermaid-to-excalidraw)/i }, + { name: 'Mermaid', pattern: /(?:^|[/_.-])mermaid(?:[/_.-]|$)/i }, + { name: 'Cytoscape', pattern: /(?:^|[/_.-])cytoscape(?:[/_.-]|$)/i }, { name: 'React', pattern: /(?:^|[/_.-])react(?:-dom)?(?:[/_.-]|$)/i }, { name: 'SvelteFlow', pattern: /(?:svelteflow|xyflow)/i }, { name: 'D3', pattern: /(?:^|[/_.-])d3(?:[/_.-]|$)/i }, diff --git a/frontend/vite.config.js b/frontend/vite.config.js index c6e601cfc..07cce699f 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -186,6 +186,37 @@ export default defineConfig({ name: 'xterm', test: /@xterm/, }, + // Excalidraw, mermaid and cytoscape are large optional editors. + // Each gets a stable named chunk so a deploy invalidates only the + // library that changed, instead of an opaque `chunk-*` shared with + // unrelated code. + // + // `includeDependenciesRecursively: false` keeps each group to the + // modules it names. With the default, Excalidraw would absorb + // mermaid (a dependency of @excalidraw/mermaid-to-excalidraw) and + // mermaid would absorb cytoscape, producing one multi-megabyte + // chunk per group. + // + // Excalidraw ships its own ~100 locale files, excluded here so they + // stay per-locale dynamic imports. The app's own locales and the + // shiki grammars are likewise deliberately left ungrouped: each is + // imported on demand, so one chunk per locale/language is the whole + // point (merging them would make the first switch load every one). + { + name: 'excalidraw', + test: /@excalidraw\/(?!excalidraw\/dist\/(?:prod|dev)\/locales)/, + includeDependenciesRecursively: false, + }, + { + name: 'mermaid', + test: /node_modules\/mermaid\//, + includeDependenciesRecursively: false, + }, + { + name: 'cytoscape', + test: /node_modules\/cytoscape\//, + includeDependenciesRecursively: false, + }, ], }, },