diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 1948c169b83774..707345a55bfb21 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -600,7 +600,9 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { js = `import "${modulePreloadPolyfillId}";\n${js}` } - return js + // Force rollup to keep this module from being shared between other entry points. + // If the resulting chunk is empty, it will be removed in generateBundle. + return { code: js, moduleSideEffects: 'no-treeshake' } } }, diff --git a/playground/css-codesplit/__tests__/css-codesplit.spec.ts b/playground/css-codesplit/__tests__/css-codesplit.spec.ts index 99d1f2d7040506..2f7d5ab5fc5fba 100644 --- a/playground/css-codesplit/__tests__/css-codesplit.spec.ts +++ b/playground/css-codesplit/__tests__/css-codesplit.spec.ts @@ -43,6 +43,14 @@ describe.runIf(isBuild)('build', () => { expect(findAssetFile(/async.*\.js$/)).toBe('') }) + test('should remove empty chunk, HTML without JS', async () => { + const sharedCSSWithJSChunk = findAssetFile('shared-css-with-js.*.js$') + expect(sharedCSSWithJSChunk).toMatch(`/* empty css`) + // there are functions and modules in the src code that should be tree-shaken + expect(sharedCSSWithJSChunk).not.toMatch('function') + expect(sharedCSSWithJSChunk).not.toMatch(/import(?!".\/modulepreload)/) + }) + test('should generate correct manifest', async () => { const manifest = readManifest() expect(manifest['index.html'].css.length).toBe(2) diff --git a/playground/css-codesplit/shared-css-empty-1.js b/playground/css-codesplit/shared-css-empty-1.js new file mode 100644 index 00000000000000..80636d362c52d5 --- /dev/null +++ b/playground/css-codesplit/shared-css-empty-1.js @@ -0,0 +1,4 @@ +function shouldBeTreeshaken_1() { + // This function should be treeshaken, even if { moduleSideEffects: 'no-treeshake' } + // was used in the JS corresponding to the HTML entrypoint. +} diff --git a/playground/css-codesplit/shared-css-empty-2.js b/playground/css-codesplit/shared-css-empty-2.js new file mode 100644 index 00000000000000..7ce6d30628268d --- /dev/null +++ b/playground/css-codesplit/shared-css-empty-2.js @@ -0,0 +1,4 @@ +export default function shouldBeTreeshaken_2() { + // This function should be treeshaken, even if { moduleSideEffects: 'no-treeshake' } + // was used in the JS corresponding to the HTML entrypoint. +} diff --git a/playground/css-codesplit/shared-css-main.js b/playground/css-codesplit/shared-css-main.js new file mode 100644 index 00000000000000..639861b66321f9 --- /dev/null +++ b/playground/css-codesplit/shared-css-main.js @@ -0,0 +1,10 @@ +import shouldTreeshake from './shared-css-empty-2.js' +document.querySelector('#app').innerHTML = ` +