From 913a6b9b679c8f6057f7fbd4dc909986cd3d8305 Mon Sep 17 00:00:00 2001 From: tianma-if Date: Sat, 5 Sep 2026 23:17:12 +0800 Subject: [PATCH] fix(web): keep X6 diagram runtime atomic --- apps/web/src/desktop-renderer-test.tsx | 71 +++++++++++++++++--------- apps/web/vite.config.ts | 14 ++++- scripts/verify-desktop-renderer.mjs | 2 +- scripts/verify-web-performance.mjs | 6 +-- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/apps/web/src/desktop-renderer-test.tsx b/apps/web/src/desktop-renderer-test.tsx index 308d5b66..10e5c027 100644 --- a/apps/web/src/desktop-renderer-test.tsx +++ b/apps/web/src/desktop-renderer-test.tsx @@ -59,31 +59,54 @@ const BubbleMenuTransactionRegression = () => { ); }; -const DesktopRendererTest = () => ( -
- - - - - - - Rename - - +const useDiagramEditorRegressionReady = () => { + const [ready, setReady] = useState(false); - -
-); + useEffect(() => { + let mounted = true; + void import("@/components/DiagramEditorPane").then(() => { + if (mounted) setReady(true); + }); + return () => { + mounted = false; + }; + }, []); + + return ready; +}; + +const DesktopRendererTest = () => { + const diagramEditorReady = useDiagramEditorRegressionReady(); + + return ( +
+ + + + + + + Rename + + + + +
+ ); +}; const root = document.getElementById("desktop-renderer-test-root"); diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 9a565865..70bdc27c 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -193,6 +193,7 @@ export default defineConfig({ "**/vendor-mermaid-*.js", "**/*Diagram-*.js", "**/*DiagramEditorPane-*.js", + "**/vendor-x6-*.js", "**/vendor-codemirror-*.js", // PDF.js is loaded only when a PDF preview or thumbnail is rendered. // Keep its runtime out of the install-time app-shell precache and cache @@ -233,7 +234,7 @@ export default defineConfig({ }, }, { - urlPattern: ({ url }) => /\/assets\/(?:.*beautiful-mermaid|vendor-mermaid|.*mermaid\.core|.*Diagram-|vendor-codemirror)/.test(url.pathname), + urlPattern: ({ url }) => /\/assets\/(?:.*beautiful-mermaid|vendor-mermaid|.*mermaid\.core|.*Diagram-|vendor-x6|vendor-codemirror)/.test(url.pathname), handler: "CacheFirst", options: { cacheName: "edgeever-optional-diagrams", @@ -291,7 +292,7 @@ export default defineConfig({ ? false : { resolveDependencies: (_filename, dependencies) => dependencies.filter((dependency) => - !/(?:vendor-code-highlight|vendor-(?:mermaid|D3|tiptap|prosemirror|floating|codemirror|zod)|vendor-radix(?!-slot)|ui-primitives|ui-button-tooltip)/.test(dependency), + !/(?:vendor-code-highlight|vendor-(?:mermaid|D3|tiptap|prosemirror|floating|codemirror|x6|zod)|vendor-radix(?!-slot)|ui-primitives|ui-button-tooltip)/.test(dependency), ), }, rolldownOptions: { @@ -328,6 +329,15 @@ export default defineConfig({ test: /node_modules[\\/](react|react-dom|scheduler|react-router)[\\/]/, priority: 40, }, + { + name: "vendor-x6", + test: /node_modules[\\/]@antv[\\/]x6[\\/]/, + priority: 39, + // X6 initializes registries and plugins through a cyclic module + // graph. Size-based splitting can evaluate clipboard storage + // before Config is initialized, crashing the lazy diagram editor. + // Keep the graph atomic and defer the resulting chunk instead. + }, { name: "vendor-prosemirror", test: /node_modules[\\/](prosemirror-|orderedmap|rope-sequence)[\\/]/, diff --git a/scripts/verify-desktop-renderer.mjs b/scripts/verify-desktop-renderer.mjs index e26a2dc5..97906c88 100644 --- a/scripts/verify-desktop-renderer.mjs +++ b/scripts/verify-desktop-renderer.mjs @@ -54,7 +54,7 @@ try { }); await verifyEntry({ filePath: componentTestPath, - readySelector: '[data-desktop-renderer-test-ready] [data-bubble-menu-regression-ready="true"]', + readySelector: '[data-desktop-renderer-test-ready][data-diagram-editor-regression-ready="true"] [data-bubble-menu-regression-ready="true"]', label: "Desktop renderer component test", }); diff --git a/scripts/verify-web-performance.mjs b/scripts/verify-web-performance.mjs index e3df10ce..0dcc6505 100644 --- a/scripts/verify-web-performance.mjs +++ b/scripts/verify-web-performance.mjs @@ -22,7 +22,7 @@ assert.ok(precacheStart >= 0 && precacheEnd > precacheStart, "Web service worker const precacheManifest = serviceWorker.slice(precacheStart, precacheEnd); assert.doesNotMatch(precacheManifest, /\{url:"index\.html",/, "Current HTML must not be served by a cache-first precache route"); assert.match(precacheManifest, /index\.html\?edgeever-offline-shell=/, "PWA must retain a versioned offline HTML shell"); -const optionalDiagramPattern = /(?:beautiful-mermaid|vendor-mermaid|mermaid\.core|vendor-codemirror|[^"']*Diagram(?:EditorPane)?-)[^"']*\.js/; +const optionalDiagramPattern = /(?:beautiful-mermaid|vendor-mermaid|mermaid\.core|vendor-x6|vendor-codemirror|[^"']*Diagram(?:EditorPane)?-)[^"']*\.js/; assert.doesNotMatch(precacheManifest, optionalDiagramPattern, "Optional diagram chunks must remain out of the initial PWA precache"); assert.doesNotMatch(precacheManifest, /vendor~pdf-[^"']*\.js/, "Optional PDF.js runtime must remain out of the initial PWA precache"); assert.doesNotMatch(precacheManifest, /noto-sans-sc-[^"']*\.woff2/, "Print-only Noto Sans SC shards must remain out of the PWA precache"); @@ -37,7 +37,7 @@ const precacheBytes = precacheURLs const PRECACHE_BUDGET = 5 * 1024 * 1024; assert.ok(precacheBytes <= PRECACHE_BUDGET, `PWA precache budget exceeded: ${precacheBytes} > ${PRECACHE_BUDGET}`); const modulePreloads = indexHtml.match(/]+>/g)?.join("\n") ?? ""; -const initialOptionalPattern = /vendor-code-highlight|vendor-D3|beautiful-mermaid|vendor-(?:mermaid|tiptap|prosemirror|floating|codemirror)|ui-primitives|mermaid\.core|[^"']*Diagram(?:EditorPane)?-/; +const initialOptionalPattern = /vendor-code-highlight|vendor-D3|beautiful-mermaid|vendor-(?:mermaid|tiptap|prosemirror|floating|codemirror|x6)|ui-primitives|mermaid\.core|[^"']*Diagram(?:EditorPane)?-/; assert.doesNotMatch(modulePreloads, initialOptionalPattern, "Optional editor and diagram chunks must remain out of the initial HTML modulepreload list"); assert.doesNotMatch(modulePreloads, /ui-button-tooltip/, "Button tooltips must load only when a titled button is rendered"); assert.doesNotMatch(modulePreloads, /vendor-radix(?!-slot)/, "Radix overlays must remain out of the initial HTML modulepreload list"); @@ -48,7 +48,7 @@ const INITIAL_MODULE_PRELOAD_BUDGET = 750 * 1024; assert.ok(initialModulePreloadBytes <= INITIAL_MODULE_PRELOAD_BUDGET, `Initial modulepreload budget exceeded: ${initialModulePreloadBytes} > ${INITIAL_MODULE_PRELOAD_BUDGET}`); const DEFAULT_CHUNK_WARNING_BYTES = 500 * 1024; -const allowedLargeChunkPattern = /^(?:vendor-(?:code-highlight|beautiful-mermaid|mermaid-(?:layout|render)|codemirror)|.*Diagram-).*\.js$/; +const allowedLargeChunkPattern = /^(?:vendor-(?:code-highlight|beautiful-mermaid|mermaid-(?:layout|render)|codemirror|x6)|.*Diagram-).*\.js$/; const largeChunks = readdirSync(join(distDirectory, "assets")) .filter((name) => name.endsWith(".js")) .map((name) => ({ name, size: statSync(join(distDirectory, "assets", name)).size }))