diff --git a/packages/playground/css/postcss-caching/blue-app/imported.css b/packages/playground/css/postcss-caching/blue-app/imported.css
new file mode 100644
index 00000000000000..2db9597eed1011
--- /dev/null
+++ b/packages/playground/css/postcss-caching/blue-app/imported.css
@@ -0,0 +1,3 @@
+.postcss-a {
+ color: pink;
+}
diff --git a/packages/playground/css/postcss-caching/blue-app/index.html b/packages/playground/css/postcss-caching/blue-app/index.html
new file mode 100644
index 00000000000000..48bc3c24d3a262
--- /dev/null
+++ b/packages/playground/css/postcss-caching/blue-app/index.html
@@ -0,0 +1,12 @@
+
+
CSS
+
+
Imported css string:
+
+
+
This should be blue
+
+
This should be black
+
+
+
diff --git a/packages/playground/css/postcss-caching/blue-app/main.js b/packages/playground/css/postcss-caching/blue-app/main.js
new file mode 100644
index 00000000000000..53286e882053fa
--- /dev/null
+++ b/packages/playground/css/postcss-caching/blue-app/main.js
@@ -0,0 +1,6 @@
+import css from './imported.css'
+text('.imported-css', css)
+
+function text(el, text) {
+ document.querySelector(el).textContent = text
+}
diff --git a/packages/playground/css/postcss-caching/blue-app/package.json b/packages/playground/css/postcss-caching/blue-app/package.json
new file mode 100644
index 00000000000000..542b4f5711180e
--- /dev/null
+++ b/packages/playground/css/postcss-caching/blue-app/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "blue-app",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "debug": "node --inspect-brk ../../vite/bin/vite",
+ "serve": "vite preview"
+ }
+}
diff --git a/packages/playground/css/postcss-caching/blue-app/postcss.config.js b/packages/playground/css/postcss-caching/blue-app/postcss.config.js
new file mode 100644
index 00000000000000..2506cd535feef7
--- /dev/null
+++ b/packages/playground/css/postcss-caching/blue-app/postcss.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ plugins: [replacePinkWithBlue]
+}
+
+function replacePinkWithBlue() {
+ return {
+ postcssPlugin: 'replace-pink-with-blue',
+ Declaration(decl) {
+ if (decl.value === 'pink') {
+ decl.value = 'blue'
+ }
+ }
+ }
+}
+replacePinkWithBlue.postcss = true
diff --git a/packages/playground/css/postcss-caching/css.spec.ts b/packages/playground/css/postcss-caching/css.spec.ts
new file mode 100644
index 00000000000000..835538666db7bb
--- /dev/null
+++ b/packages/playground/css/postcss-caching/css.spec.ts
@@ -0,0 +1,29 @@
+import { getColor } from '../../testUtils'
+import { createServer } from 'vite'
+import path from 'path'
+
+test('postcss config', async () => {
+ const port = 5005
+ const blueAppDir = path.join(__dirname, 'blue-app')
+ const greenAppDir = path.join(__dirname, 'green-app')
+
+ process.chdir(blueAppDir)
+ const blueApp = await createServer()
+ await blueApp.listen(port)
+ await page.goto(`http://localhost:${port}`)
+ const blueA = await page.$('.postcss-a')
+ expect(await getColor(blueA)).toBe('blue')
+ const blueB = await page.$('.postcss-b')
+ expect(await getColor(blueB)).toBe('black')
+ await blueApp.close()
+
+ process.chdir(greenAppDir)
+ const greenApp = await createServer()
+ await greenApp.listen(port)
+ await page.goto(`http://localhost:${port}`)
+ const greenA = await page.$('.postcss-a')
+ expect(await getColor(greenA)).toBe('black')
+ const greenB = await page.$('.postcss-b')
+ expect(await getColor(greenB)).toBe('green')
+ await greenApp.close()
+})
diff --git a/packages/playground/css/postcss-caching/green-app/imported.css b/packages/playground/css/postcss-caching/green-app/imported.css
new file mode 100644
index 00000000000000..8fd68a56a7284d
--- /dev/null
+++ b/packages/playground/css/postcss-caching/green-app/imported.css
@@ -0,0 +1,3 @@
+.postcss-b {
+ color: pink;
+}
diff --git a/packages/playground/css/postcss-caching/green-app/index.html b/packages/playground/css/postcss-caching/green-app/index.html
new file mode 100644
index 00000000000000..4c0428b578e03e
--- /dev/null
+++ b/packages/playground/css/postcss-caching/green-app/index.html
@@ -0,0 +1,12 @@
+
+
CSS
+
+
Imported css string:
+
+
+
This should be black
+
+
This should be green
+
+
+
diff --git a/packages/playground/css/postcss-caching/green-app/main.js b/packages/playground/css/postcss-caching/green-app/main.js
new file mode 100644
index 00000000000000..53286e882053fa
--- /dev/null
+++ b/packages/playground/css/postcss-caching/green-app/main.js
@@ -0,0 +1,6 @@
+import css from './imported.css'
+text('.imported-css', css)
+
+function text(el, text) {
+ document.querySelector(el).textContent = text
+}
diff --git a/packages/playground/css/postcss-caching/green-app/package.json b/packages/playground/css/postcss-caching/green-app/package.json
new file mode 100644
index 00000000000000..1ac4969a18eccd
--- /dev/null
+++ b/packages/playground/css/postcss-caching/green-app/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "green-app",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "debug": "node --inspect-brk ../../vite/bin/vite",
+ "serve": "vite preview"
+ }
+}
diff --git a/packages/playground/css/postcss-caching/green-app/postcss.config.js b/packages/playground/css/postcss-caching/green-app/postcss.config.js
new file mode 100644
index 00000000000000..1367dfc1d27c7b
--- /dev/null
+++ b/packages/playground/css/postcss-caching/green-app/postcss.config.js
@@ -0,0 +1,15 @@
+module.exports = {
+ plugins: [replacePinkWithGreen]
+}
+
+function replacePinkWithGreen() {
+ return {
+ postcssPlugin: 'replace-pink-with-green',
+ Declaration(decl) {
+ if (decl.value === 'pink') {
+ decl.value = 'green'
+ }
+ }
+ }
+}
+replacePinkWithGreen.postcss = true
diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts
index f2d358d29133d0..8b3108ab8b6b80 100644
--- a/packages/vite/src/node/plugins/css.ts
+++ b/packages/vite/src/node/plugins/css.ts
@@ -115,6 +115,11 @@ export const chunkToEmittedCssFileMap = new WeakMap<
Set
>()
+const postcssConfigCache = new WeakMap<
+ ResolvedConfig,
+ PostCSSConfigResult | null
+>()
+
/**
* Plugin applied before user plugins
*/
@@ -729,37 +734,40 @@ interface PostCSSConfigResult {
plugins: Postcss.Plugin[]
}
-let cachedPostcssConfig: PostCSSConfigResult | null | undefined
-
async function resolvePostcssConfig(
config: ResolvedConfig
): Promise {
- if (cachedPostcssConfig !== undefined) {
- return cachedPostcssConfig
+ let result = postcssConfigCache.get(config)
+ if (result !== undefined) {
+ return result
}
// inline postcss config via vite config
const inlineOptions = config.css?.postcss
if (isObject(inlineOptions)) {
- const result = {
- options: { ...inlineOptions },
+ const options = { ...inlineOptions }
+
+ delete options.plugins
+ result = {
+ options,
plugins: inlineOptions.plugins || []
}
- delete result.options.plugins
- return (cachedPostcssConfig = result)
- }
-
- try {
- const searchPath =
- typeof inlineOptions === 'string' ? inlineOptions : config.root
- // @ts-ignore
- return (cachedPostcssConfig = await postcssrc({}, searchPath))
- } catch (e) {
- if (!/No PostCSS Config found/.test(e.message)) {
- throw e
+ } else {
+ try {
+ const searchPath =
+ typeof inlineOptions === 'string' ? inlineOptions : config.root
+ // @ts-ignore
+ result = await postcssrc({}, searchPath)
+ } catch (e) {
+ if (!/No PostCSS Config found/.test(e.message)) {
+ throw e
+ }
+ result = null
}
- return (cachedPostcssConfig = null)
}
+
+ postcssConfigCache.set(config, result)
+ return result
}
type CssUrlReplacer = (