From 1bee8a63f1733d04a950816e1f76fc3dfa92c8e2 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 18 Oct 2022 17:08:54 +0800 Subject: [PATCH 1/5] fix(css): clean id for postcss process --- packages/vite/src/node/plugins/css.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index dad328164d476b..34573220683a0f 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -753,6 +753,7 @@ async function compileCSS( preprocessorOptions, devSourcemap } = config.css || {} + const fileName = cleanUrl(id) const isModule = modulesOptions !== false && cssModuleRE.test(id) // although at serve time it can work without processing, we do need to // crawl them in order to register watch dependencies. @@ -800,7 +801,7 @@ async function compileCSS( } } // important: set this for relative import resolving - opts.filename = cleanUrl(id) + opts.filename = fileName opts.enableSourcemap = devSourcemap ?? false const preprocessResult = await preProcessor( @@ -919,8 +920,8 @@ async function compileCSS( .default(postcssPlugins) .process(code, { ...postcssOptions, - to: id, - from: id, + to: fileName, + from: fileName, ...(devSourcemap ? { map: { @@ -990,13 +991,13 @@ async function compileCSS( // version property of rawPostcssMap is declared as string // but actually it is a number rawPostcssMap as Omit as ExistingRawSourceMap, - cleanUrl(id) + fileName ) return { ast: postcssResult, code: postcssResult.css, - map: combineSourcemapsIfExists(cleanUrl(id), postcssMap, preprocessorMap), + map: combineSourcemapsIfExists(fileName, postcssMap, preprocessorMap), modules, deps } From 1530680d0abaeb88ea062f2694cce71c9a5f6805 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 18 Oct 2022 17:52:14 +0800 Subject: [PATCH 2/5] chore: add test --- .../src/node/__tests__/plugins/css.spec.ts | 134 +++++++++++------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index efad549a30102f..fb391e3d303439 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -2,6 +2,7 @@ import fs from 'node:fs' import path from 'node:path' import { describe, expect, test, vi } from 'vitest' import { resolveConfig } from '../../config' +import type { InlineConfig } from '../../config' import { cssPlugin, cssUrlRE, hoistAtRules } from '../../plugins/css' describe('search css url function', () => { @@ -46,13 +47,17 @@ describe('search css url function', () => { }) }) -describe('css path resolutions', () => { - const mockedProjectPath = path.join(process.cwd(), '/foo/bar/project') - const mockedBarCssRelativePath = '/css/bar.module.css' - const mockedFooCssRelativePath = '/css/foo.module.css' - - test('cssmodule compose/from path resolutions', async () => { - const config = await resolveConfig( +describe('css modules', () => { + test('css module compose/from path resolutions', async () => { + const mockedProjectPath = path.join(process.cwd(), '/foo/bar/project') + const { transform, resetMock } = await createCssPluginTransform( + { + [path.join(mockedProjectPath, '/css/bar.module.css')]: `\ +.bar { +display: block; +background: #f0f; +}` + }, { resolve: { alias: [ @@ -62,57 +67,48 @@ describe('css path resolutions', () => { } ] } - }, - 'serve' + } ) - const { transform, buildStart } = cssPlugin(config) - - await buildStart.call({}) - - const mockFs = vi - .spyOn(fs, 'readFile') - // @ts-ignore vi.spyOn not recognize override `fs.readFile` definition. - .mockImplementationOnce((p, encoding, callback) => { - expect(p).toBe(path.join(mockedProjectPath, mockedBarCssRelativePath)) - expect(encoding).toBe('utf-8') - callback( - null, - Buffer.from(` -.bar { - display: block; - background: #f0f; -} - `) - ) - }) - - const { code } = await transform.call( - { - addWatchFile() { - return - } - }, - ` + const result = await transform( + `\ .foo { - position: fixed; - composes: bar from '@${mockedBarCssRelativePath}'; -} - `, - path.join(mockedProjectPath, mockedFooCssRelativePath) +position: fixed; +composes: bar from '@/css/bar.module.css'; +}`, + '/css/foo.module.css' ) - expect(code).toBe(` -._bar_soicv_2 { - display: block; - background: #f0f; -} -._foo_sctn3_2 { - position: fixed; + expect(result.code).toBe( + `\ +._bar_1csqm_1 { +display: block; +background: #f0f; } - `) +._foo_86148_1 { +position: fixed; +}` + ) + + resetMock() + }) - mockFs.mockReset() + test('custom generateScopedName', async () => { + const { transform, resetMock } = await createCssPluginTransform(undefined, { + css: { + modules: { + generateScopedName: 'custom__[hash:base64:5]' + } + } + }) + const css = `\ +.foo { + color: red; +}` + const result1 = await transform(css, '/foo.module.css') + const result2 = await transform(css, '/foo.module.css?direct') + expect(result1.code).toBe(result2.code) + resetMock() }) }) @@ -205,3 +201,39 @@ describe('hoist @ rules', () => { `) }) }) + +async function createCssPluginTransform( + files?: Record, + inlineConfig: InlineConfig = {} +) { + const config = await resolveConfig(inlineConfig, 'serve') + const { transform, buildStart } = cssPlugin(config) + + // @ts-expect-error + await buildStart.call({}) + + const mockFs = vi + .spyOn(fs, 'readFile') + // @ts-expect-error vi.spyOn not recognize override `fs.readFile` definition. + .mockImplementationOnce((p, encoding, callback) => { + callback(null, Buffer.from(files?.[p] ?? '')) + }) + + return { + async transform(code: string, id: string) { + // @ts-expect-error + return await transform.call( + { + addWatchFile() { + return + } + }, + code, + id + ) + }, + resetMock() { + mockFs.mockReset() + } + } +} From acfa0473390e3f4e34c9ef44d4ce082a78e9767b Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 18 Oct 2022 17:53:40 +0800 Subject: [PATCH 3/5] docs: add note --- packages/vite/src/node/__tests__/plugins/css.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index fb391e3d303439..d951178783073b 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -105,8 +105,8 @@ position: fixed; .foo { color: red; }` - const result1 = await transform(css, '/foo.module.css') - const result2 = await transform(css, '/foo.module.css?direct') + const result1 = await transform(css, '/foo.module.css') // server + const result2 = await transform(css, '/foo.module.css?direct') // client expect(result1.code).toBe(result2.code) resetMock() }) From cbd40f94048ad46ebb413a46b1f3da39889ef074 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 19 Oct 2022 12:56:49 +0800 Subject: [PATCH 4/5] chore: remove direct query only --- packages/vite/src/node/plugins/css.ts | 13 +++++++------ packages/vite/src/node/utils.ts | 4 ++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 34573220683a0f..194259ba0e6c96 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -42,6 +42,7 @@ import { normalizePath, parseRequest, processSrcSet, + removeDirectQuery, requireResolveFromRootWithFallback } from '../utils' import type { Logger } from '../logger' @@ -753,7 +754,6 @@ async function compileCSS( preprocessorOptions, devSourcemap } = config.css || {} - const fileName = cleanUrl(id) const isModule = modulesOptions !== false && cssModuleRE.test(id) // although at serve time it can work without processing, we do need to // crawl them in order to register watch dependencies. @@ -801,7 +801,7 @@ async function compileCSS( } } // important: set this for relative import resolving - opts.filename = fileName + opts.filename = cleanUrl(id) opts.enableSourcemap = devSourcemap ?? false const preprocessResult = await preProcessor( @@ -915,13 +915,14 @@ async function compileCSS( let postcssResult: PostCSS.Result try { + const source = removeDirectQuery(id) // postcss is an unbundled dep and should be lazy imported postcssResult = await (await import('postcss')) .default(postcssPlugins) .process(code, { ...postcssOptions, - to: fileName, - from: fileName, + to: source, + from: source, ...(devSourcemap ? { map: { @@ -991,13 +992,13 @@ async function compileCSS( // version property of rawPostcssMap is declared as string // but actually it is a number rawPostcssMap as Omit as ExistingRawSourceMap, - fileName + cleanUrl(id) ) return { ast: postcssResult, code: postcssResult.css, - map: combineSourcemapsIfExists(fileName, postcssMap, preprocessorMap), + map: combineSourcemapsIfExists(cleanUrl(id), postcssMap, preprocessorMap), modules, deps } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 2711a29b7eb703..a6c341ec05df7e 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -303,6 +303,7 @@ export function getPotentialTsSrcPaths(filePath: string): string[] { } const importQueryRE = /(\?|&)import=?(?:&|$)/ +const directRequestRE = /(\?|&)direct(?:&|$)/ const internalPrefixes = [ FS_PREFIX, VALID_ID_PREFIX, @@ -318,6 +319,9 @@ export const isInternalRequest = (url: string): boolean => export function removeImportQuery(url: string): string { return url.replace(importQueryRE, '$1').replace(trailingSeparatorRE, '') } +export function removeDirectQuery(url: string): string { + return url.replace(directRequestRE, '$1').replace(trailingSeparatorRE, '') +} export function injectQuery(url: string, queryToInject: string): string { // encode percents for consistent behavior with pathToFileURL From 5169f2e2ed4727e8ca2f980cdda278e08fb71397 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Thu, 20 Oct 2022 15:21:22 +0800 Subject: [PATCH 5/5] chore: guard equals Co-authored-by: patak --- packages/vite/src/node/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index a6c341ec05df7e..47028cc9d8889f 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -303,7 +303,7 @@ export function getPotentialTsSrcPaths(filePath: string): string[] { } const importQueryRE = /(\?|&)import=?(?:&|$)/ -const directRequestRE = /(\?|&)direct(?:&|$)/ +const directRequestRE = /(\?|&)direct=?(?:&|$)/ const internalPrefixes = [ FS_PREFIX, VALID_ID_PREFIX,