Skip to content

Commit

Permalink
perf(css): only run postcss when needed (#19061)
Browse files Browse the repository at this point in the history
Co-authored-by: Bjorn Lu <[email protected]>
  • Loading branch information
sapphi-red and bluwy authored Jan 24, 2025
1 parent 1992f68 commit 30194fa
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 36 deletions.
72 changes: 40 additions & 32 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1275,7 +1275,6 @@ async function compileCSS(
): Promise<{
code: string
map?: SourceMapInput
ast?: PostCSS.Result
modules?: Record<string, string>
deps?: Set<string>
}> {
Expand All @@ -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<string>()

// 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<string, string> | undefined
const deps = new Set<string>()

// 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) {
Expand Down Expand Up @@ -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,
Expand All @@ -1400,6 +1403,8 @@ async function compileCSS(
)
}

let modules: Record<string, string> | undefined

if (isModule) {
postcssPlugins.unshift(
(await importPostcssModules()).default({
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -1514,7 +1524,6 @@ async function compileCSS(

if (!devSourcemap) {
return {
ast: postcssResult,
code: postcssResult.css,
map: { mappings: '' },
modules,
Expand All @@ -1532,7 +1541,6 @@ async function compileCSS(
)

return {
ast: postcssResult,
code: postcssResult.css,
map: combineSourcemapsIfExists(cleanUrl(id), postcssMap, preprocessorMap),
modules,
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 4 additions & 4 deletions playground/css-sourcemap/__tests__/css-sourcemap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -186,7 +186,7 @@ describe.runIf(isServe)('serve', () => {
expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
{
"ignoreList": [],
"mappings": "AACE;EACE",
"mappings": "AACE,SAAC;EACC",
"sources": [
"/root/imported.less",
],
Expand All @@ -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",
],
Expand Down

0 comments on commit 30194fa

Please sign in to comment.