-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vite duplicates code across main bundle and web worker bundle #16719
Comments
@sapphi-red @hi-ogawa I was wondering if you have any thoughts please. This issue is still affecting us and doubling our bundle size (a significant burden on bandwidth required by users and loading speed) |
@gabrielecirulli Current behavior is by design and Vite build triggers a dedicated rollup build for a worker entry (even with a separate set of plugins https://vitejs.dev/config/worker-options.html#worker-plugins). A few reasons are explained in #16554 (comment)
If worker entries were treated simply as a part of main client build (just like dynamic import), then Vite cannot guarantee it won't access things like If you know this risk, then it's possible to write a plugin using Plugin codeimport { defineConfig, Plugin } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
server: {
host: true,
},
worker: {
format: "es",
},
build: {
minify: false,
// need to eliminate `document` reference
modulePreload: false,
},
plugins: [workerChunkPlugin()],
});
// use emitFile to create a worker entry as a chunk of main client build.
function workerChunkPlugin(): Plugin {
return {
name: workerChunkPlugin.name,
apply: "build",
enforce: "pre",
async resolveId(source, importer, _options) {
// intercept "xxx?worker"
if (source.endsWith("?worker")) {
const resolved = await this.resolve(source.split("?")[0], importer);
return "\0" + resolved?.id + "?worker-chunk";
}
},
load(id, _options) {
if (id.startsWith("\0") && id.endsWith("?worker-chunk")) {
const referenceId = this.emitFile({
type: "chunk",
id: id.slice(1).split("?")[0],
});
return `
export default function WorkerWrapper() {
return new Worker(
import.meta.ROLLUP_FILE_URL_${referenceId},
{ type: "module" }
);
}
`;
}
},
};
} $ pnpm build
vite v5.2.11 building for production...
✓ 616 modules transformed.
dist/index.html 0.38 kB │ gzip: 0.26 kB
dist/assets/batchSamplersUniformGroup-BZfrq0yw.js 0.43 kB │ gzip: 0.28 kB
dist/assets/index-BsivXy7a.js 0.76 kB │ gzip: 0.35 kB
dist/assets/CanvasPool-HXi5M9ss.js 2.01 kB │ gzip: 0.71 kB
dist/assets/colorToUniform-BBLU0xpW.js 49.00 kB │ gzip: 11.74 kB
dist/assets/WebGPURenderer-D3B6HnuZ.js 63.89 kB │ gzip: 13.54 kB
dist/assets/SharedSystems-CtlWS3fy.js 87.52 kB │ gzip: 18.96 kB
dist/assets/browserAll-yDBsCdS0.js 97.48 kB │ gzip: 19.72 kB
dist/assets/WebGLRenderer-C4toZjTE.js 112.72 kB │ gzip: 24.12 kB
dist/assets/worker-CKKmHEZU.js 113.95 kB │ gzip: 30.33 kB
dist/assets/webworkerAll-DLeBSlo-.js 161.31 kB │ gzip: 35.30 kB
dist/assets/canvas-D3GKaOyS.js 466.66 kB │ gzip: 104.15 kB
✓ built in 1.78s |
Thank you very much! At a basic level, this appears to work in our scenario. |
Describe the bug
Please refer to this repository for a way to reproduce the issue: https://github.com/gabrielecirulli/vite-pixi-bundling
When bundling Web Worker code with Vite, some of the dependencies that are used
by both the worker and the page context are duplicated in the final bundle, even
though they should be shared because they are virtually the same code.
In the provided repository,
pixi.js
is used to render to two instances ofcanvas
, once within the page context and once within a Web Worker.To do this, we have a file
canvas.ts
which importspixi.js
and exports a class calledCanvas
. We also have aworker.ts
script that will run as a web worker. Both the worker script andmain.ts
import theCanvas
class and set it up. Other than this they virtually do the same thing.Intuitively, all of
pixi.js
should just be bundled once and shared across the two page context and web worker scripts which import it. However, the code ends up duplicated and bloating the bundle size (see build logs)As far as I can tell, there is nothing in the Vite or Rollup docs that helps with this. I have tried various combinations of
manualChunks
and other options to no avail.Reproduction
https://github.com/gabrielecirulli/vite-pixi-bundling
Steps to reproduce
pnpm install
pnpm run build
dist/assets
Comparing the build output
The repository includes a branch called
with-manual-chunks
. This branch forces Rollup to bundle all code belonging topixi.js
into a manual chunk calledpixi.js
. This way, you can compare the two bundles to see the (lack of) differences:with-manual-chunks
pnpm install
pnpm run build
git diff --no-index dist/assets/pixi.js*
System Info
Used Package Manager
npm
Logs
`vite build --debug`
```shell 2024-05-19T19:25:38.250Z vite:config bundled config file loaded in 13.52ms 2024-05-19T19:25:38.266Z vite:config using resolved config: { server: { preTransformRequests: true, host: true, sourcemapIgnoreList: [Function: isInNodeModules$1], middlewareMode: false, fs: { strict: true, allow: [Array], deny: [Array], cachedChecks: undefined } }, worker: { format: 'es', plugins: '() => plugins', rollupOptions: {} }, build: { target: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], cssTarget: [ 'es2020', 'edge88', 'firefox78', 'chrome87', 'safari14' ], outDir: 'dist', assetsDir: 'assets', assetsInlineLimit: 4096, cssCodeSplit: true, sourcemap: false, rollupOptions: {}, minify: 'esbuild', terserOptions: {}, write: true, emptyOutDir: null, copyPublicDir: true, manifest: false, lib: false, ssr: false, ssrManifest: false, ssrEmitAssets: false, reportCompressedSize: true, chunkSizeWarningLimit: 500, watch: null, commonjsOptions: { include: [Array], extensions: [Array] }, dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] }, modulePreload: { polyfill: true }, cssMinify: true }, configFile: '/dir/to/vite-pixi-bundling/vite.config.ts', configFileDependencies: [ '/dir/to/vite-pixi-bundling/vite.config.ts' ], inlineConfig: { root: undefined, base: undefined, mode: undefined, configFile: undefined, logLevel: undefined, clearScreen: undefined, build: {} }, root: '/dir/to/vite-pixi-bundling', base: '/', rawBase: '/', resolve: { mainFields: [ 'browser', 'module', 'jsnext:main', 'jsnext' ], conditions: [], extensions: [ '.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json' ], dedupe: [], preserveSymlinks: false, alias: [ [Object], [Object] ] }, publicDir: '/dir/to/vite-pixi-bundling/public', cacheDir: '/dir/to/vite-pixi-bundling/node_modules/.vite', command: 'build', mode: 'production', ssr: { target: 'node', optimizeDeps: { noDiscovery: true, esbuildOptions: [Object] } }, isWorker: false, mainConfig: null, bundleChain: [], isProduction: true, plugins: [ 'vite:build-metadata', 'vite:watch-package-data', 'vite:pre-alias', 'alias', 'vite:modulepreload-polyfill', 'vite:resolve', 'vite:html-inline-proxy', 'vite:css', 'vite:esbuild', 'vite:json', 'vite:wasm-helper', 'vite:worker', 'vite:asset', 'vite:wasm-fallback', 'vite:define', 'vite:css-post', 'vite:build-html', 'vite:worker-import-meta-url', 'vite:asset-import-meta-url', 'vite:force-systemjs-wrap-complete', 'commonjs', 'vite:data-uri', 'vite:dynamic-import-vars', 'vite:import-glob', 'vite:build-import-analysis', 'vite:esbuild-transpile', 'vite:terser', 'vite:reporter', 'vite:load-fallback' ], css: { lightningcss: undefined }, esbuild: { jsxDev: false }, preview: { port: undefined, strictPort: undefined, host: true, https: undefined, open: undefined, proxy: undefined, cors: undefined, headers: undefined }, envDir: '/dir/to/vite-pixi-bundling', env: { BASE_URL: '/', MODE: 'production', DEV: false, PROD: true }, assetsInclude: [Function: assetsInclude], logger: { hasWarned: false, info: [Function: info], warn: [Function: warn], warnOnce: [Function: warnOnce], error: [Function: error], clearScreen: [Function: clearScreen], hasErrorLogged: [Function: hasErrorLogged] }, packageCache: Map(1) { 'fnpd_/dir/to/vite-pixi-bundling' => { dir: '/dir/to/vite-pixi-bundling', data: [Object], hasSideEffects: [Function: hasSideEffects], webResolvedImports: {}, nodeResolvedImports: {}, setResolvedCache: [Function: setResolvedCache], getResolvedCache: [Function: getResolvedCache] }, set: [Function (anonymous)] }, createResolver: [Function: createResolver], optimizeDeps: { holdUntilCrawlEnd: true, esbuildOptions: { preserveSymlinks: false } }, appType: 'spa', experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false }, getSortedPlugins: [Function: getSortedPlugins], getSortedPluginHooks: [Function: getSortedPluginHooks] } vite v5.2.11 building for production... transforming... ✓ 616 modules transformed. rendering chunks... computing gzip size... dist/assets/batchSamplersUniformGroup-esTw4NqZ.js 0.23 kB dist/index.html 0.38 kB │ gzip: 0.27 kB dist/assets/CanvasPool-DAAltsjf.js 0.69 kB dist/assets/colorToUniform-PMjxk6y4.js 24.37 kB dist/assets/WebGPURenderer-C4GTSOc9.js 35.19 kB dist/assets/browserAll-s_Odv2Zz.js 37.24 kB dist/assets/SharedSystems-Dmf2ic5s.js 43.80 kB dist/assets/WebGLRenderer-DSs9dsMu.js 59.35 kB dist/assets/webworkerAll-CBdqNP-U.js 77.34 kB dist/assets/worker-wXglRUk2.js 228.69 kB dist/assets/batchSamplersUniformGroup-BJBcGol3.js 0.23 kB │ gzip: 0.21 kB dist/assets/CanvasPool-P9anc0rq.js 0.69 kB │ gzip: 0.38 kB dist/assets/colorToUniform-DdNNl6bf.js 24.37 kB │ gzip: 7.84 kB dist/assets/WebGPURenderer-D2rAnSo4.js 35.19 kB │ gzip: 9.73 kB dist/assets/browserAll-Qg6UHUQs.js 37.24 kB │ gzip: 9.96 kB dist/assets/SharedSystems-DviRLSqg.js 43.79 kB │ gzip: 12.25 kB dist/assets/WebGLRenderer-D69Oodqk.js 59.35 kB │ gzip: 16.33 kB dist/assets/webworkerAll-B3O_29JZ.js 77.34 kB │ gzip: 22.81 kB dist/assets/index-DaWpJUK9.js 174.57 kB │ gzip: 55.57 kB ✓ built in 3.09s ```Validations
The text was updated successfully, but these errors were encountered: