diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 8068e0ec5c53ca..c088bbb4f7963a 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1275,7 +1275,6 @@ async function compileCSS( ): Promise<{ code: string map?: SourceMapInput - ast?: PostCSS.Result modules?: Record deps?: Set }> { @@ -1284,51 +1283,49 @@ async function compileCSS( return compileLightningCSS(id, code, environment, urlResolver) } + const lang = CSS_LANGS_RE.exec(id)?.[1] as CssLang | undefined + const deps = new Set() + + // pre-processors: sass etc. + let preprocessorMap: ExistingRawSourceMap | undefined + if (isPreProcessor(lang)) { + const preprocessorResult = await compileCSSPreprocessors( + environment, + id, + lang, + code, + workerController, + ) + code = preprocessorResult.code + preprocessorMap = preprocessorResult.map + preprocessorResult.deps?.forEach((dep) => deps.add(dep)) + } + const { modules: modulesOptions, devSourcemap } = config.css 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. const needInlineImport = code.includes('@import') const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code) - const lang = CSS_LANGS_RE.exec(id)?.[1] as CssLang | undefined const postcssConfig = await resolvePostcssConfig( environment.getTopLevelConfig(), ) - // 1. plain css that needs no processing + // postcss processing is not needed if ( - lang === 'css' && + lang !== 'sss' && !postcssConfig && !isModule && !needInlineImport && !hasUrl ) { - return { code, map: null } - } - - let modules: Record | undefined - const deps = new Set() - - // 2. pre-processors: sass etc. - let preprocessorMap: ExistingRawSourceMap | undefined - if (isPreProcessor(lang)) { - const preprocessorResult = await compileCSSPreprocessors( - environment, - id, - lang, - code, - workerController, - ) - code = preprocessorResult.code - preprocessorMap = preprocessorResult.map - preprocessorResult.deps?.forEach((dep) => deps.add(dep)) + return { code, map: preprocessorMap ?? null, deps } } - // 3. postcss + // postcss const atImportResolvers = getAtImportResolvers( environment.getTopLevelConfig(), ) - const postcssOptions = postcssConfig?.options ?? {} const postcssPlugins = postcssConfig?.plugins.slice() ?? [] if (needInlineImport) { @@ -1390,7 +1387,13 @@ async function compileCSS( ) } - if (urlResolver) { + if ( + urlResolver && + // if there's an @import, we need to add this plugin + // regradless of whether it contains url() or image-set(), + // because we don't know the content referenced by @import + (needInlineImport || hasUrl) + ) { postcssPlugins.push( UrlRewritePostcssPlugin({ resolver: urlResolver, @@ -1400,6 +1403,8 @@ async function compileCSS( ) } + let modules: Record | undefined + if (isModule) { postcssPlugins.unshift( (await importPostcssModules()).default({ @@ -1433,7 +1438,11 @@ async function compileCSS( ) } - if (!postcssPlugins.length) { + const postcssOptions = postcssConfig?.options ?? {} + const postcssParser = + lang === 'sss' ? loadSss(config.root) : postcssOptions.parser + + if (!postcssPlugins.length && !postcssParser) { return { code, map: preprocessorMap, @@ -1445,10 +1454,11 @@ async function compileCSS( try { const source = removeDirectQuery(id) const postcss = await importPostcss() + // postcss is an unbundled dep and should be lazy imported postcssResult = await postcss.default(postcssPlugins).process(code, { ...postcssOptions, - parser: lang === 'sss' ? loadSss(config.root) : postcssOptions.parser, + parser: postcssParser, to: source, from: source, ...(devSourcemap @@ -1514,7 +1524,6 @@ async function compileCSS( if (!devSourcemap) { return { - ast: postcssResult, code: postcssResult.css, map: { mappings: '' }, modules, @@ -1532,7 +1541,6 @@ async function compileCSS( ) return { - ast: postcssResult, code: postcssResult.css, map: combineSourcemapsIfExists(cleanUrl(id), postcssMap, preprocessorMap), modules, @@ -2182,8 +2190,8 @@ function loadSassPackage(root: string): { } } -let cachedSss: any -function loadSss(root: string) { +let cachedSss: PostCSS.Syntax +function loadSss(root: string): PostCSS.Syntax { if (cachedSss) return cachedSss const sssPath = loadPreprocessorPath(PostCssDialectLang.sss, root) diff --git a/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts b/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts index 40bef704173384..f943143187ee51 100644 --- a/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts +++ b/playground/css-sourcemap/__tests__/css-sourcemap.spec.ts @@ -138,8 +138,8 @@ describe.runIf(isServe)('serve', () => { const map = extractSourcemap(css) expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(` { - "ignoreList": [], - "mappings": "AAGE;EACE,UCJM", + "mappings": "AAGE;EACE,OCJM", + "sourceRoot": "", "sources": [ "/root/imported.sass", "/root/imported-nested.sass", @@ -186,7 +186,7 @@ describe.runIf(isServe)('serve', () => { expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(` { "ignoreList": [], - "mappings": "AACE;EACE", + "mappings": "AACE,SAAC;EACC", "sources": [ "/root/imported.less", ], @@ -209,7 +209,7 @@ describe.runIf(isServe)('serve', () => { expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(` { "ignoreList": [], - "mappings": "AACE;EACE,cAAM", + "mappings": "AACE;EACE,OAAM,QAAN", "sources": [ "/root/imported.styl", ],