diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 27f18bbac7f42e..1be8eadad7b65e 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1389,10 +1389,11 @@ async function compileCSS( 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) + // when a postcss plugin is used (including the internal postcss plugins), + // we need to add this plugin regardless of whether + // this file contains url() or image-set(), + // because we don't know the content injected by those plugins + (postcssPlugins.length > 0 || isModule || hasUrl) ) { postcssPlugins.push( UrlRewritePostcssPlugin({ diff --git a/playground/css/__tests__/css.spec.ts b/playground/css/__tests__/css.spec.ts index 251b595a8dfa12..7403418e114f75 100644 --- a/playground/css/__tests__/css.spec.ts +++ b/playground/css/__tests__/css.spec.ts @@ -76,6 +76,14 @@ test('postcss config', async () => { await untilUpdated(() => getColor(imported), 'red') }) +test('postcss plugin that injects url()', async () => { + const imported = await page.$('.postcss-inject-url') + // alias should be resolved + expect(await getBg(imported)).toMatch( + /localhost(?::\d+)?\/(?:assets\/)?ok.*\.png/, + ) +}) + sassTest() test('less', async () => { diff --git a/playground/css/index.html b/playground/css/index.html index 39f72fa61de440..edbcbd4f5fda23 100644 --- a/playground/css/index.html +++ b/playground/css/index.html @@ -21,6 +21,9 @@

CSS

PostCSS nesting plugin: this should be pink

+

+ PostCSS plugin: this should have a background image +

SASS: This should be orange

diff --git a/playground/css/main.js b/playground/css/main.js index 41140a5de5315c..d3e97a7d2525e9 100644 --- a/playground/css/main.js +++ b/playground/css/main.js @@ -6,6 +6,7 @@ import './less.less' import './less-plugin.less' import './stylus.styl' import './manual-chunk.css' +import './postcss-inject-url.css' import urlCss from './url-imported.css?url' appendLinkStylesheet(urlCss) diff --git a/playground/css/postcss-inject-url.css b/playground/css/postcss-inject-url.css new file mode 100644 index 00000000000000..766ccc8838bf3d --- /dev/null +++ b/playground/css/postcss-inject-url.css @@ -0,0 +1 @@ +@inject-url; diff --git a/playground/css/postcss.config.js b/playground/css/postcss.config.js index 54107e641abefb..5583e836006478 100644 --- a/playground/css/postcss.config.js +++ b/playground/css/postcss.config.js @@ -5,7 +5,7 @@ import { normalizePath } from 'vite' import postcssNested from 'postcss-nested' export default { - plugins: [postcssNested, testDirDep, testSourceInput], + plugins: [postcssNested, testDirDep, testSourceInput, testInjectUrl], } /** @@ -61,3 +61,25 @@ function testSourceInput() { } } testSourceInput.postcss = true + +function testInjectUrl() { + return { + postcssPlugin: 'inject-url', + Once(root, { Rule }) { + root.walkAtRules('inject-url', (atRule) => { + const rule = new Rule({ + selector: '.postcss-inject-url', + source: atRule.source, + }) + rule.append({ + prop: 'background', + value: "url('=/ok.png')", + source: atRule.source, + }) + atRule.after(rule) + atRule.remove() + }) + }, + } +} +testInjectUrl.postcss = true