Skip to content

Commit 08e39b7

Browse files
authored
fix(less): handles rewriting relative paths passed Less's data-uri function. (#7400)
1 parent ace6e93 commit 08e39b7

File tree

6 files changed

+45
-3
lines changed

6 files changed

+45
-3
lines changed

packages/playground/css/__tests__/css.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,3 +388,11 @@ test('import css in less', async () => {
388388
expect(await getColor('.css-in-less')).toBe('yellow')
389389
expect(await getColor('.css-in-less-2')).toBe('blue')
390390
})
391+
392+
test("relative path rewritten in Less's data-uri", async () => {
393+
// relative path passed to Less's data-uri is rewritten to absolute,
394+
// the Less inlines it
395+
expect(await getBg('.form-box-data-uri')).toMatch(
396+
/^url\("data:image\/svg\+xml,%3Csvg/
397+
)
398+
})

packages/playground/css/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ <h1>CSS</h1>
4949
<p>Imported Less string:</p>
5050
<pre class="imported-less"></pre>
5151

52+
<div class="form-box-data-uri">
53+
tests Less's `data-uri()` function with relative image paths
54+
</div>
55+
5256
<p class="stylus">Stylus: This should be blue</p>
5357
<p class="stylus-additional-data">
5458
Stylus additionalData: This should be orange

packages/playground/css/less.less

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
@import '@/nested/nested';
22
@import './nested/css-in-less.less';
33

4+
// Test data-uri calls with relative images.
5+
@import './less/components/form.less';
6+
47
@color: blue;
58

69
.less {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.form-box-data-uri {
2+
// data-uri() calls with relative paths should be replaced just like urls.
3+
background-image: data-uri('../images/backgrounds/form-select.svg');
4+
}
Lines changed: 4 additions & 0 deletions
Loading

packages/vite/src/node/plugins/css.ts

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,8 @@ type CssUrlReplacer = (
965965
// https://drafts.csswg.org/css-syntax-3/#identifier-code-point
966966
export const cssUrlRE =
967967
/(?<=^|[^\w\-\u0080-\uffff])url\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
968+
export const cssDataUriRE =
969+
/(?<=^|[^\w\-\u0080-\uffff])data-uri\(\s*('[^']+'|"[^"]+"|[^'")]+)\s*\)/
968970
export const importCssRE = /@import ('[^']+\.css'|"[^"]+\.css"|[^'")]+\.css)/
969971
const cssImageSetRE = /image-set\(([^)]+)\)/
970972

@@ -1015,6 +1017,16 @@ function rewriteCssUrls(
10151017
})
10161018
}
10171019

1020+
function rewriteCssDataUris(
1021+
css: string,
1022+
replacer: CssUrlReplacer
1023+
): Promise<string> {
1024+
return asyncReplace(css, cssDataUriRE, async (match) => {
1025+
const [matched, rawUrl] = match
1026+
return await doUrlReplace(rawUrl, matched, replacer, 'data-uri')
1027+
})
1028+
}
1029+
10181030
function rewriteImportCss(
10191031
css: string,
10201032
replacer: CssUrlReplacer
@@ -1040,7 +1052,8 @@ function rewriteCssImageSet(
10401052
async function doUrlReplace(
10411053
rawUrl: string,
10421054
matched: string,
1043-
replacer: CssUrlReplacer
1055+
replacer: CssUrlReplacer,
1056+
funcName: string = 'url'
10441057
) {
10451058
let wrap = ''
10461059
const first = rawUrl[0]
@@ -1057,7 +1070,7 @@ async function doUrlReplace(
10571070
// The new url might need wrapping even if the original did not have it, e.g. if a space was added during replacement
10581071
wrap = "'"
10591072
}
1060-
return `url(${wrap}${newUrl}${wrap})`
1073+
return `${funcName}(${wrap}${newUrl}${wrap})`
10611074
}
10621075

10631076
async function doImportCSSReplace(
@@ -1307,10 +1320,12 @@ async function rebaseUrls(
13071320
const content = fs.readFileSync(file, 'utf-8')
13081321
// no url()
13091322
const hasUrls = cssUrlRE.test(content)
1323+
// data-uri() calls
1324+
const hasDataUris = cssDataUriRE.test(content)
13101325
// no @import xxx.css
13111326
const hasImportCss = importCssRE.test(content)
13121327

1313-
if (!hasUrls && !hasImportCss) {
1328+
if (!hasUrls && !hasDataUris && !hasImportCss) {
13141329
return { file }
13151330
}
13161331

@@ -1339,6 +1354,10 @@ async function rebaseUrls(
13391354
rebased = await rewriteCssUrls(rebased || content, rebaseFn)
13401355
}
13411356

1357+
if (hasDataUris) {
1358+
rebased = await rewriteCssDataUris(rebased || content, rebaseFn)
1359+
}
1360+
13421361
return {
13431362
file,
13441363
contents: rebased

0 commit comments

Comments
 (0)