From 319e9855c8cfff1f3f1a68147875b3f373205734 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Fri, 10 Nov 2023 23:15:00 +0900 Subject: [PATCH 1/7] refactor: simplify original name logic --- packages/vite/src/node/plugins/css.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 842daf68710a18..3a962e8438e9cf 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -616,9 +616,6 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { : chunk.name, ) - const lang = path.extname(cssAssetName).slice(1) - const cssFileName = ensureFileExt(cssAssetName, '.css') - chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssAssetName) const previousTask = emitTasks[emitTasks.length - 1] @@ -638,15 +635,15 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { await thisTask // emit corresponding css file + const cssFileName = ensureFileExt(cssAssetName, '.css') const referenceId = this.emitFile({ name: path.basename(cssFileName), type: 'asset', source: chunkCSS, }) - const originalName = isPreProcessor(lang) ? cssAssetName : cssFileName generatedAssets .get(config)! - .set(referenceId, { originalName, isEntry }) + .set(referenceId, { originalName: cssAssetName, isEntry }) chunk.viteMetadata!.importedCss.add(this.getFileName(referenceId)) if (emitTasksLength === emitTasks.length) { From b16ed8eaaf241eee22eaf84e35c7c7c5b7c36c7c Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Fri, 10 Nov 2023 23:24:46 +0900 Subject: [PATCH 2/7] fix: correctly set CSS originalFileName --- packages/vite/src/node/plugins/css.ts | 8 ++++- packages/vite/src/node/plugins/manifest.ts | 39 ++++++++++++++-------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 3a962e8438e9cf..8344ba26f88fd2 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -70,6 +70,7 @@ import { renderAssetUrlInJS, } from './asset' import type { ESBuildOptions } from './esbuild' +import { getChunkOriginalFileName } from './manifest' // const debug = createDebugger('vite:css') @@ -615,6 +616,11 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { ? path.relative(config.root, chunk.facadeModuleId) : chunk.name, ) + const originalFilename = getChunkOriginalFileName( + chunk, + config.root, + opts.format, + ) chunkCSS = resolveAssetUrlsInCss(chunkCSS, cssAssetName) @@ -643,7 +649,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { }) generatedAssets .get(config)! - .set(referenceId, { originalName: cssAssetName, isEntry }) + .set(referenceId, { originalName: originalFilename, isEntry }) chunk.viteMetadata!.importedCss.add(this.getFileName(referenceId)) if (emitTasksLength === emitTasks.length) { diff --git a/packages/vite/src/node/plugins/manifest.ts b/packages/vite/src/node/plugins/manifest.ts index 7f7484c1a7ae5e..023d1f264f0cf4 100644 --- a/packages/vite/src/node/plugins/manifest.ts +++ b/packages/vite/src/node/plugins/manifest.ts @@ -1,5 +1,10 @@ import path from 'node:path' -import type { OutputAsset, OutputChunk } from 'rollup' +import type { + InternalModuleFormat, + OutputAsset, + OutputChunk, + RenderedChunk, +} from 'rollup' import jsonStableStringify from 'json-stable-stringify' import type { ResolvedConfig } from '..' import type { Plugin } from '../plugin' @@ -34,19 +39,7 @@ export function manifestPlugin(config: ResolvedConfig): Plugin { generateBundle({ format }, bundle) { function getChunkName(chunk: OutputChunk) { - if (chunk.facadeModuleId) { - let name = normalizePath( - path.relative(config.root, chunk.facadeModuleId), - ) - if (format === 'system' && !chunk.name.includes('-legacy')) { - const ext = path.extname(name) - const endPos = ext.length !== 0 ? -ext.length : undefined - name = name.slice(0, endPos) + `-legacy` + ext - } - return name.replace(/\0/g, '') - } else { - return `_` + path.basename(chunk.fileName) - } + return getChunkOriginalFileName(chunk, config.root, format) } function getInternalImports(imports: string[]): string[] { @@ -165,3 +158,21 @@ export function manifestPlugin(config: ResolvedConfig): Plugin { }, } } + +export function getChunkOriginalFileName( + chunk: OutputChunk | RenderedChunk, + root: string, + format: InternalModuleFormat, +): string { + if (chunk.facadeModuleId) { + let name = normalizePath(path.relative(root, chunk.facadeModuleId)) + if (format === 'system' && !chunk.name.includes('-legacy')) { + const ext = path.extname(name) + const endPos = ext.length !== 0 ? -ext.length : undefined + name = name.slice(0, endPos) + `-legacy` + ext + } + return name.replace(/\0/g, '') + } else { + return `_` + path.basename(chunk.fileName) + } +} From c2a750da6f8c3119b4cae70b8a3f4ea78698af85 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Fri, 10 Nov 2023 23:26:01 +0900 Subject: [PATCH 3/7] fix: correctly emit CSS file --- packages/vite/src/node/plugins/css.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 8344ba26f88fd2..c7c5bd4bf9cacd 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -611,11 +611,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { } if (opts.format === 'es' || opts.format === 'cjs') { const isEntry = chunk.isEntry && isPureCssChunk - const cssAssetName = normalizePath( - !isEntry && chunk.facadeModuleId - ? path.relative(config.root, chunk.facadeModuleId) - : chunk.name, - ) + const cssAssetName = ensureFileExt(chunk.name, '.css') const originalFilename = getChunkOriginalFileName( chunk, config.root, @@ -641,9 +637,8 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { await thisTask // emit corresponding css file - const cssFileName = ensureFileExt(cssAssetName, '.css') const referenceId = this.emitFile({ - name: path.basename(cssFileName), + name: cssAssetName, type: 'asset', source: chunkCSS, }) From f1b6f67109d517219953fc4f0d7e2fae58e01a7e Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:08:31 +0900 Subject: [PATCH 4/7] test: fix filename test and manifest windows path test --- .../__tests__/backend-integration.spec.ts | 7 +++---- playground/backend-integration/dir/foo.css | 2 +- playground/backend-integration/frontend/dynamic/foo.css | 3 --- playground/backend-integration/frontend/dynamic/foo.ts | 1 - .../backend-integration/frontend/entrypoints/main.ts | 1 - 5 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 playground/backend-integration/frontend/dynamic/foo.css delete mode 100644 playground/backend-integration/frontend/dynamic/foo.ts diff --git a/playground/backend-integration/__tests__/backend-integration.spec.ts b/playground/backend-integration/__tests__/backend-integration.spec.ts index 7356d8eff15c8c..07558d67ec54ea 100644 --- a/playground/backend-integration/__tests__/backend-integration.spec.ts +++ b/playground/backend-integration/__tests__/backend-integration.spec.ts @@ -37,7 +37,7 @@ describe.runIf(isBuild)('build', () => { const cssAssetEntry = manifest['global.css'] const scssAssetEntry = manifest['nested/blue.scss'] const imgAssetEntry = manifest['../images/logo.png'] - const dirFooAssetEntry = manifest['../dynamic/foo.css'] // '\\' should not be used even on windows + const dirFooAssetEntry = manifest['../../dir/foo.css'] expect(htmlEntry.css.length).toEqual(1) expect(htmlEntry.assets.length).toEqual(1) expect(cssAssetEntry?.file).not.toBeUndefined() @@ -47,10 +47,9 @@ describe.runIf(isBuild)('build', () => { expect(scssAssetEntry?.isEntry).toEqual(true) expect(imgAssetEntry?.file).not.toBeUndefined() expect(imgAssetEntry?.isEntry).toBeUndefined() - expect(dirFooAssetEntry).not.toBeUndefined() + expect(dirFooAssetEntry).not.toBeUndefined() // '\\' should not be used even on windows // use the entry name - expect(manifest['bar.css']).not.toBeUndefined() - expect(manifest['foo.css']).toBeUndefined() + expect(dirFooAssetEntry.file).toMatch('assets/bar-') }) }) diff --git a/playground/backend-integration/dir/foo.css b/playground/backend-integration/dir/foo.css index 1e31c585bebc9c..c2fad7486d3ab6 100644 --- a/playground/backend-integration/dir/foo.css +++ b/playground/backend-integration/dir/foo.css @@ -1,3 +1,3 @@ -.entry-name-foo { +.windows-path-foo { color: blue; } diff --git a/playground/backend-integration/frontend/dynamic/foo.css b/playground/backend-integration/frontend/dynamic/foo.css deleted file mode 100644 index c2fad7486d3ab6..00000000000000 --- a/playground/backend-integration/frontend/dynamic/foo.css +++ /dev/null @@ -1,3 +0,0 @@ -.windows-path-foo { - color: blue; -} diff --git a/playground/backend-integration/frontend/dynamic/foo.ts b/playground/backend-integration/frontend/dynamic/foo.ts deleted file mode 100644 index c2441c49231d80..00000000000000 --- a/playground/backend-integration/frontend/dynamic/foo.ts +++ /dev/null @@ -1 +0,0 @@ -import './foo.css' diff --git a/playground/backend-integration/frontend/entrypoints/main.ts b/playground/backend-integration/frontend/entrypoints/main.ts index d63a57a023847e..f5a332191dd9e4 100644 --- a/playground/backend-integration/frontend/entrypoints/main.ts +++ b/playground/backend-integration/frontend/entrypoints/main.ts @@ -1,5 +1,4 @@ import 'vite/modulepreload-polyfill' -import('../dynamic/foo') // should be dynamic import to split chunks export const colorClass = 'text-black' From 61c19bfc8a3f54877a15c301e6c7ef2c48184037 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:31:21 +0900 Subject: [PATCH 5/7] test: add case for #12009 --- .../backend-integration/__tests__/backend-integration.spec.ts | 3 +++ playground/backend-integration/frontend/entrypoints/foo.pcss | 3 +++ 2 files changed, 6 insertions(+) create mode 100644 playground/backend-integration/frontend/entrypoints/foo.pcss diff --git a/playground/backend-integration/__tests__/backend-integration.spec.ts b/playground/backend-integration/__tests__/backend-integration.spec.ts index 07558d67ec54ea..eb017f4498b507 100644 --- a/playground/backend-integration/__tests__/backend-integration.spec.ts +++ b/playground/backend-integration/__tests__/backend-integration.spec.ts @@ -35,6 +35,7 @@ describe.runIf(isBuild)('build', () => { const manifest = readManifest('dev') const htmlEntry = manifest['index.html'] const cssAssetEntry = manifest['global.css'] + const pcssAssetEntry = manifest['foo.pcss'] const scssAssetEntry = manifest['nested/blue.scss'] const imgAssetEntry = manifest['../images/logo.png'] const dirFooAssetEntry = manifest['../../dir/foo.css'] @@ -42,6 +43,8 @@ describe.runIf(isBuild)('build', () => { expect(htmlEntry.assets.length).toEqual(1) expect(cssAssetEntry?.file).not.toBeUndefined() expect(cssAssetEntry?.isEntry).toEqual(true) + expect(pcssAssetEntry?.file).not.toBeUndefined() + expect(pcssAssetEntry?.isEntry).toEqual(true) expect(scssAssetEntry?.file).not.toBeUndefined() expect(scssAssetEntry?.src).toEqual('nested/blue.scss') expect(scssAssetEntry?.isEntry).toEqual(true) diff --git a/playground/backend-integration/frontend/entrypoints/foo.pcss b/playground/backend-integration/frontend/entrypoints/foo.pcss new file mode 100644 index 00000000000000..a49e02c1cc73bf --- /dev/null +++ b/playground/backend-integration/frontend/entrypoints/foo.pcss @@ -0,0 +1,3 @@ +.foo_pcss { + color: blue; +} From ed2be42932333f561f31f7f46c70c781efb1a3d1 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 11 Nov 2023 00:40:09 +0900 Subject: [PATCH 6/7] test: add case for #12072 --- playground/css/__tests__/css.spec.ts | 7 +++++++ playground/css/main.js | 1 + playground/css/manual-chunk.css | 3 +++ playground/css/vite.config.js | 9 +++++++++ 4 files changed, 20 insertions(+) create mode 100644 playground/css/manual-chunk.css diff --git a/playground/css/__tests__/css.spec.ts b/playground/css/__tests__/css.spec.ts index b424faace62b81..8b4f498430e099 100644 --- a/playground/css/__tests__/css.spec.ts +++ b/playground/css/__tests__/css.spec.ts @@ -508,3 +508,10 @@ test('async css order with css modules', async () => { test('@import scss', async () => { expect(await getColor('.at-import-scss')).toBe('red') }) + +test.runIf(isBuild)('manual chunk path', async () => { + // assert that the manual-chunk css is output in the directory specified in manualChunk (#12072) + expect( + findAssetFile(/dir\/dir2\/manual-chunk-[-\w]{8}\.css$/), + ).not.toBeUndefined() +}) diff --git a/playground/css/main.js b/playground/css/main.js index 62fc9f4d2fe8ff..b0b405a96a7baf 100644 --- a/playground/css/main.js +++ b/playground/css/main.js @@ -4,6 +4,7 @@ import './sugarss.sss' import './sass.scss' import './less.less' import './stylus.styl' +import './manual-chunk.css' import rawCss from './raw-imported.css?raw' text('.raw-imported-css', rawCss) diff --git a/playground/css/manual-chunk.css b/playground/css/manual-chunk.css new file mode 100644 index 00000000000000..dc41883115cc1d --- /dev/null +++ b/playground/css/manual-chunk.css @@ -0,0 +1,3 @@ +.manual-chunk { + color: blue; +} diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 0cce195572a584..3d301ae03bec3e 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -12,6 +12,15 @@ globalThis.location = new URL('http://localhost/') export default defineConfig({ build: { cssTarget: 'chrome61', + rollupOptions: { + output: { + manualChunks(id) { + if (id.includes('manual-chunk.css')) { + return 'dir/dir2/manual-chunk' + } + }, + }, + }, }, esbuild: { logOverride: { From 1376a34787e3b81f3e0751a1e4b74533e6372ca0 Mon Sep 17 00:00:00 2001 From: sapphi-red <49056869+sapphi-red@users.noreply.github.com> Date: Sat, 11 Nov 2023 12:32:22 +0900 Subject: [PATCH 7/7] fix: prioritize JS chunk in manifest --- packages/vite/src/node/plugins/manifest.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/vite/src/node/plugins/manifest.ts b/packages/vite/src/node/plugins/manifest.ts index 023d1f264f0cf4..eff3212d2fc06c 100644 --- a/packages/vite/src/node/plugins/manifest.ts +++ b/packages/vite/src/node/plugins/manifest.ts @@ -126,6 +126,10 @@ export function manifestPlugin(config: ResolvedConfig): Plugin { const assetMeta = fileNameToAssetMeta.get(chunk.fileName) const src = assetMeta?.originalName ?? chunk.name const asset = createAsset(chunk, src, assetMeta?.isEntry) + + // If JS chunk and asset chunk are both generated from the same source file, + // prioritize JS chunk as it contains more information + if (manifest[src]?.file.endsWith('.js')) continue manifest[src] = asset fileNameToAsset.set(chunk.fileName, asset) }