From 3d27c0a0cad022657ba3ebf1cf5cf6da75b1895f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 26 Jun 2026 11:26:11 +0000 Subject: [PATCH] perf(build): fix bun .bun chunk parsing and isolate Vite preload helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The manualChunks package-name parser used the first node_modules/ segment, which under bun's isolated install (.bun/@/node_modules/) is always '.bun'. This collapsed nearly every dependency — including lazy-only heavy libs (Shiki langs/themes, transformers, katex, mermaid, elkjs, etc.) — into one 18.5 MB eager 'vendor-.bun' chunk, defeating all code splitting. - Resolve the real package from the LAST node_modules/ segment. - Pin Vite's __vitePreload helper to its own chunk so Rollup stops co-locating it inside vendor-shiki and dragging Shiki core + the 629 KB oniguruma engine into the eager bootstrap. - Drop the now-dead react-syntax-highlighter chunk rule. Eager bootstrap graph drops from ~18.5 MB to ~0.44 MB. Co-authored-by: Serhii Dziupin --- packages/web/vite.config.ts | 17 +++++++++++++++-- vite.config.ts | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index 553a892b..3fcabff7 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -109,9 +109,23 @@ export default defineConfig({ external: ['node:child_process', 'node:fs', 'node:path', 'node:url'], output: { manualChunks(id) { + // Pin Vite's tiny runtime helpers to their own stable chunk. Otherwise + // Rollup co-locates the `__vitePreload` helper into an arbitrary vendor + // chunk (e.g. `shiki`), and since every dynamic import pulls the helper, + // that whole vendor (here Shiki core + the 629KB oniguruma engine) gets + // dragged into the eager bootstrap graph. + if (id.includes('vite/preload-helper') || id.includes('vite/modulepreload-polyfill')) { + return 'vendor-vite-runtime'; + } if (!id.includes('node_modules')) return undefined; - const match = id.split('node_modules/')[1]; + // Resolve the real package from the LAST `node_modules/` segment. + // bun's isolated install nests packages as + // `node_modules/.bun/@/node_modules//...`, so the first + // `node_modules/` segment is `.bun` — using it collapses every dependency + // (incl. lazy-only ones) into a single giant eager `vendor-.bun` chunk. + const lastNodeModules = id.lastIndexOf('node_modules/'); + const match = id.slice(lastNodeModules + 'node_modules/'.length); if (!match) return undefined; const segments = match.split('/'); @@ -123,7 +137,6 @@ export default defineConfig({ if (packageName === '@opencode-ai/sdk') return 'vendor-opencode-sdk'; if (packageName.includes('remark') || packageName.includes('rehype') || packageName === 'react-markdown') return 'vendor-markdown'; if (packageName === '@base-ui/react' || packageName.startsWith('@base-ui')) return 'vendor-base-ui'; - if (packageName.includes('react-syntax-highlighter') || packageName.includes('highlight.js')) return 'vendor-syntax'; const sanitized = packageName.replace(/^@/, '').replace(/\//g, '-'); return `vendor-${sanitized}`; diff --git a/vite.config.ts b/vite.config.ts index 5f6cb03c..ae9721f4 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -33,9 +33,23 @@ export default defineConfig({ external: ['node:child_process', 'node:fs', 'node:path', 'node:url'], output: { manualChunks(id) { + // Pin Vite's tiny runtime helpers to their own stable chunk. Otherwise + // Rollup co-locates the `__vitePreload` helper into an arbitrary vendor + // chunk (e.g. `shiki`), and since every dynamic import pulls the helper, + // that whole vendor (here Shiki core + the 629KB oniguruma engine) gets + // dragged into the eager bootstrap graph. + if (id.includes('vite/preload-helper') || id.includes('vite/modulepreload-polyfill')) { + return 'vendor-vite-runtime' + } if (!id.includes('node_modules')) return undefined - const match = id.split('node_modules/')[1] + // Resolve the real package from the LAST `node_modules/` segment. + // bun's isolated install nests packages as + // `node_modules/.bun/@/node_modules//...`, so the first + // `node_modules/` segment is `.bun` — using it collapses every dependency + // (incl. lazy-only ones) into a single giant eager `vendor-.bun` chunk. + const lastNodeModules = id.lastIndexOf('node_modules/') + const match = id.slice(lastNodeModules + 'node_modules/'.length) if (!match) return undefined const segments = match.split('/') @@ -46,7 +60,6 @@ export default defineConfig({ if (packageName === '@opencode-ai/sdk') return 'vendor-opencode-sdk' if (packageName.includes('remark') || packageName.includes('rehype') || packageName === 'react-markdown') return 'vendor-markdown' if (packageName === '@base-ui/react' || packageName.startsWith('@base-ui')) return 'vendor-base-ui' - if (packageName.includes('react-syntax-highlighter') || packageName.includes('highlight.js')) return 'vendor-syntax' const sanitized = packageName.replace(/^@/, '').replace(/\//g, '-') return `vendor-${sanitized}`