diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts index 19dd52f71e114a..f1075f6fe1cb39 100644 --- a/packages/playground/assets/__tests__/assets.spec.ts +++ b/packages/playground/assets/__tests__/assets.spec.ts @@ -104,6 +104,29 @@ describe('css url() references', () => { }) }) + test('image-set with var', async () => { + const imageSet = await getBg('.css-image-set-with-var') + imageSet.split(', ').forEach((s) => { + expect(s).toMatch(assetMatch) + }) + }) + + test('image-set with mix', async () => { + const imageSet = await getBg('.css-image-set-mix-url-var') + imageSet.split(', ').forEach((s) => { + expect(s).toMatch(assetMatch) + }) + }) + + // not supported in browser now + // https://drafts.csswg.org/css-images-4/#image-set-notation + // test('image-set with multiple descriptor', async () => { + // const imageSet = await getBg('.css-image-set-multiple-descriptor') + // imageSet.split(', ').forEach((s) => { + // expect(s).toMatch(assetMatch) + // }) + // }) + test('relative in @import', async () => { expect(await getBg('.css-url-relative-at-imported')).toMatch(assetMatch) }) diff --git a/packages/playground/assets/css/css-url.css b/packages/playground/assets/css/css-url.css index 8a3f00dee17bd9..9047cd384e7d38 100644 --- a/packages/playground/assets/css/css-url.css +++ b/packages/playground/assets/css/css-url.css @@ -26,6 +26,29 @@ background-size: 10px; } +.css-image-set-with-var { + --bg-img: url('../nested/asset.png'); + background-image: -webkit-image-set(var(--bg-img) 1x, var(--bg-img) 2x); + background-size: 10px; +} + +.css-image-set-mix-url-var { + --bg-img: url('../nested/asset.png'); + background-image: -webkit-image-set( + var(--bg-img) 1x, + url('../nested/asset.png') 2x + ); + background-size: 10px; +} + +.css-image-set-multiple-descriptor { + background-image: -webkit-image-set( + '../nested/asset.png' type('image/png') 1x, + '../nested/asset.png' type('image/png') 2x + ); + background-size: 10px; +} + .css-url-public { background: url('/icon.png'); background-size: 10px; diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html index 99c2c2fe69ae70..43eed55236abd3 100644 --- a/packages/playground/assets/index.html +++ b/packages/playground/assets/index.html @@ -46,6 +46,34 @@

CSS url references

>CSS background with image-set() (relative) +
+ + CSS background image-set() (relative in var) + +
+
+ + CSS background image-set() (mix var and url) + +
+
+ + CSS background image-set() (with multiple descriptor) + +
+
+ + CSS background image-set() (with multiple descriptor) + +
CSS background (relative from @imported file in different dir) { @@ -1054,11 +1057,15 @@ function rewriteCssImageSet( replacer: CssUrlReplacer ): Promise { return asyncReplace(css, cssImageSetRE, async (match) => { - const [matched, rawUrl] = match - const url = await processSrcSet(rawUrl, ({ url }) => - doUrlReplace(url, matched, replacer) - ) - return `image-set(${url})` + const [, rawUrl] = match + const url = await processSrcSet(rawUrl, async ({ url }) => { + // the url maybe url(...) + if (cssUrlRE.test(url)) { + return await rewriteCssUrls(url, replacer) + } + return await doUrlReplace(url, url, replacer) + }) + return url }) } async function doUrlReplace( @@ -1073,7 +1080,13 @@ async function doUrlReplace( wrap = first rawUrl = rawUrl.slice(1, -1) } - if (isExternalUrl(rawUrl) || isDataUrl(rawUrl) || rawUrl.startsWith('#')) { + + if ( + isExternalUrl(rawUrl) || + isDataUrl(rawUrl) || + rawUrl.startsWith('#') || + varRE.test(rawUrl) + ) { return matched } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index e7a20afbdd5ae7..32b783974dacaf 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -545,6 +545,7 @@ interface ImageCandidate { descriptor: string } const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g +const imageSetUrlRE = /^(?:[\w\-]+\(.*?\)|'.*?'|".*?"|\S*)/ export async function processSrcSet( srcs: string, replacer: (arg: ImageCandidate) => Promise @@ -552,11 +553,13 @@ export async function processSrcSet( const imageCandidates: ImageCandidate[] = srcs .split(',') .map((s) => { - const [url, descriptor] = s - .replace(escapedSpaceCharacters, ' ') - .trim() - .split(' ', 2) - return { url, descriptor } + const src = s.replace(escapedSpaceCharacters, ' ').trim() + const [url] = imageSetUrlRE.exec(src) || [] + + return { + url, + descriptor: src?.slice(url.length).trim() + } }) .filter(({ url }) => !!url)