diff --git a/index.html b/index.html
index 48e1e0a..b162833 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,9 @@
Nitro
+
+
diff --git a/vite.config.mjs b/vite.config.mjs
index 1b6899f..e51a1a0 100644
--- a/vite.config.mjs
+++ b/vite.config.mjs
@@ -164,18 +164,46 @@ export default defineConfig({
rollupOptions: {
output: {
assetFileNames: 'src/assets/[name]-[hash].[ext]',
+ // Granular chunking: split the monolithic vendor / nitro-renderer
+ // bundles into smaller chunks so the browser can fetch them in
+ // parallel and CF can cache each independently. Splits chosen
+ // by size impact (pixi ~600KB, react ~150KB, framer-motion ~100KB,
+ // jodit ~250KB lazy-loaded only by admin news, etc.).
manualChunks: id =>
{
- // Renderer source is consumed via filesystem alias
- // (../Nitro_Render_V3/packages/*/src) so it is NOT
- // under node_modules — needs its own branch before
- // the node_modules check.
- if(id.includes('Nitro_Render_V3') || id.includes(`${ rendererRoot }`)) return 'nitro-renderer';
+ // Vendor checks first — pixi.js/howler are aliased to
+ // ../Nitro_Render_V3/node_modules so they match
+ // `Nitro_Render_V3` too. Without this priority, they end
+ // up bundled into nitro-renderer instead of getting their
+ // own chunks (pixi alone is ~600KB). Use `/pixi.js/` to
+ // avoid matching path fragments like `assets/pixi.js/`.
+ const norm = id.replace(/\\/g, '/');
+ if(norm.includes('pixi.js') || norm.includes('pixi-filters')) return 'vendor-pixi';
+ if(norm.includes('howler')) return 'vendor-audio';
+ if(norm.includes('@emoji-mart')) return 'vendor-emoji';
+ if(norm.includes('jodit') || norm.includes('@react-page')) return 'vendor-editor';
+
+ if(id.includes('Nitro_Render_V3') || id.includes(`${ rendererRoot }`))
+ {
+ // Heaviest renderer packages get their own chunks so
+ // pages that don't touch them (login flow, very early
+ // boot) don't have to pay for them upfront.
+ if(id.includes('/packages/avatar/')) return 'nitro-renderer-avatar';
+ if(id.includes('/packages/communication/')) return 'nitro-renderer-comm';
+ if(id.includes('/packages/room/')) return 'nitro-renderer-room';
+ if(id.includes('/packages/assets/')) return 'nitro-renderer-assets';
+ return 'nitro-renderer';
+ }
if(id.includes('node_modules'))
{
if(id.includes('@nitrots/nitro-renderer') || id.includes('renderer3')) return 'nitro-renderer';
-
+ if(id.match(/\/react(-dom)?\/|\/scheduler\//) || id.includes('react-error-boundary')) return 'vendor-react';
+ if(id.includes('framer-motion')) return 'vendor-motion';
+ if(id.includes('@tanstack')) return 'vendor-query';
+ if(id.includes('zustand') || id.includes('use-between')) return 'vendor-state';
+ if(id.includes('react-icons')) return 'vendor-icons';
+ if(id.includes('json5')) return 'vendor-json5';
return 'vendor';
}
}