From b28cc04ee9cf655fa6343f3d7c51c902b73250f2 Mon Sep 17 00:00:00 2001 From: frank Date: Fri, 24 Jun 2022 22:03:19 +0800 Subject: [PATCH 1/5] fix(css):url() with variable or relative path in sass/scss is broken (fix:#7651) --- packages/vite/src/node/plugins/css.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index ad46e5ba738f37..b8234c749fdf7b 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1209,10 +1209,17 @@ UrlRewritePostcssPlugin.postcss = true function rewriteCssUrls( css: string, - replacer: CssUrlReplacer + replacer: CssUrlReplacer, + file?: string ): Promise { return asyncReplace(css, cssUrlRE, async (match) => { const [matched, rawUrl] = match + const inLess = file?.endsWith('.less') + const inSass = file?.endsWith('.sass') + const inScss = file?.endsWith('.scss') + if (inLess && rawUrl.startsWith('@') || (inSass || inScss) && rawUrl.startsWith('$')) { + return `url('${rawUrl}')` + } return await doUrlReplace(rawUrl, matched, replacer) }) } @@ -1621,7 +1628,7 @@ async function rebaseUrls( } if (hasUrls) { - rebased = await rewriteCssUrls(rebased || content, rebaseFn) + rebased = await rewriteCssUrls(rebased || content, rebaseFn, file) } if (hasDataUris) { From 4ac0fba581ace57fd6711bf32262e4b4fea56509 Mon Sep 17 00:00:00 2001 From: frank Date: Fri, 24 Jun 2022 22:39:38 +0800 Subject: [PATCH 2/5] chore:prettier --- packages/vite/src/node/plugins/css.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index b8234c749fdf7b..6c7a5ad14dc608 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1217,7 +1217,10 @@ function rewriteCssUrls( const inLess = file?.endsWith('.less') const inSass = file?.endsWith('.sass') const inScss = file?.endsWith('.scss') - if (inLess && rawUrl.startsWith('@') || (inSass || inScss) && rawUrl.startsWith('$')) { + if ( + (inLess && rawUrl.startsWith('@')) || + ((inSass || inScss) && rawUrl.startsWith('$')) + ) { return `url('${rawUrl}')` } return await doUrlReplace(rawUrl, matched, replacer) From d80a02769127df9fbff9df7a223c9e11b4d62a58 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Mon, 31 Oct 2022 22:24:49 +0900 Subject: [PATCH 3/5] refactor: variablePrefix --- packages/vite/src/node/plugins/css.ts | 28 +++++++++++++-------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 6c7a5ad14dc608..d107b13ed60017 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -1209,20 +1209,10 @@ UrlRewritePostcssPlugin.postcss = true function rewriteCssUrls( css: string, - replacer: CssUrlReplacer, - file?: string + replacer: CssUrlReplacer ): Promise { return asyncReplace(css, cssUrlRE, async (match) => { const [matched, rawUrl] = match - const inLess = file?.endsWith('.less') - const inSass = file?.endsWith('.sass') - const inScss = file?.endsWith('.scss') - if ( - (inLess && rawUrl.startsWith('@')) || - ((inSass || inScss) && rawUrl.startsWith('$')) - ) { - return `url('${rawUrl}')` - } return await doUrlReplace(rawUrl, matched, replacer) }) } @@ -1503,7 +1493,7 @@ const scss: SassStylePreprocessor = async ( const internalImporter: Sass.Importer = (url, importer, done) => { resolvers.sass(url, importer).then((resolved) => { if (resolved) { - rebaseUrls(resolved, options.filename, options.alias) + rebaseUrls(resolved, options.filename, options.alias, '$') .then((data) => done?.(data)) .catch((data) => done?.(data)) } else { @@ -1587,7 +1577,8 @@ const sass: SassStylePreprocessor = (source, root, options, aliasResolver) => async function rebaseUrls( file: string, rootFile: string, - alias: Alias[] + alias: Alias[], + variablePrefix: string ): Promise { file = path.resolve(file) // ensure os-specific flashes // in the same dir, no need to rebase @@ -1612,6 +1603,8 @@ async function rebaseUrls( let rebased const rebaseFn = (url: string) => { if (url.startsWith('/')) return url + // ignore url's starting with variable + if (url.startsWith(variablePrefix)) return url // match alias, no need to rewrite for (const { find } of alias) { const matches = @@ -1631,7 +1624,7 @@ async function rebaseUrls( } if (hasUrls) { - rebased = await rewriteCssUrls(rebased || content, rebaseFn, file) + rebased = await rewriteCssUrls(rebased || content, rebaseFn) } if (hasDataUris) { @@ -1744,7 +1737,12 @@ function createViteLessPlugin( path.join(dir, '*') ) if (resolved) { - const result = await rebaseUrls(resolved, this.rootFile, this.alias) + const result = await rebaseUrls( + resolved, + this.rootFile, + this.alias, + '@' + ) let contents: string if (result && 'contents' in result) { contents = result.contents From f68b907ad5331eef57eb258028ab0d9f82a8b1b0 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Tue, 1 Nov 2022 00:16:11 +0900 Subject: [PATCH 4/5] refactor: replace alias from @ to = --- playground/css/composes-path-resolving.module.css | 6 +++--- playground/css/less.less | 2 +- playground/css/linked.css | 2 +- playground/css/nested/_index.scss | 2 +- playground/css/nested/nested.less | 2 +- playground/css/nested/nested.sss | 2 +- playground/css/nested/nested.styl | 2 +- playground/css/sass.scss | 8 ++++---- playground/css/sugarss.sss | 2 +- playground/css/vite.config.js | 2 +- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/playground/css/composes-path-resolving.module.css b/playground/css/composes-path-resolving.module.css index 4fe7cdbad42136..a5a5172eb4104c 100644 --- a/playground/css/composes-path-resolving.module.css +++ b/playground/css/composes-path-resolving.module.css @@ -1,11 +1,11 @@ .path-resolving-css { - composes: apply-color from '@/composed.module.css'; + composes: apply-color from '=/composed.module.css'; } .path-resolving-sass { - composes: apply-color from '@/composed.module.scss'; + composes: apply-color from '=/composed.module.scss'; } .path-resolving-less { - composes: apply-color from '@/composed.module.less'; + composes: apply-color from '=/composed.module.less'; } diff --git a/playground/css/less.less b/playground/css/less.less index 49cbd3c3bb336e..f5f6fa52b36740 100644 --- a/playground/css/less.less +++ b/playground/css/less.less @@ -1,4 +1,4 @@ -@import '@/nested/nested'; +@import '=/nested/nested'; @import './nested/css-in-less.less'; // Test data-uri calls with relative images. diff --git a/playground/css/linked.css b/playground/css/linked.css index ff38b8bc9345ba..55b11f672fc500 100644 --- a/playground/css/linked.css +++ b/playground/css/linked.css @@ -1,4 +1,4 @@ -@import '@/linked-at-import.css'; +@import '=/linked-at-import.css'; /* test postcss nesting */ .wrapper { diff --git a/playground/css/nested/_index.scss b/playground/css/nested/_index.scss index 48d630b573ae1b..192e9de3b0e203 100644 --- a/playground/css/nested/_index.scss +++ b/playground/css/nested/_index.scss @@ -7,5 +7,5 @@ .sass-at-import-alias { color: olive; - background: url(@/nested/icon.png) 10px no-repeat; + background: url(=/nested/icon.png) 10px no-repeat; } diff --git a/playground/css/nested/nested.less b/playground/css/nested/nested.less index e4ce110ab73679..f5a40a69d88839 100644 --- a/playground/css/nested/nested.less +++ b/playground/css/nested/nested.less @@ -5,5 +5,5 @@ .less-at-import-alias { color: darkslateblue; - background: url(@/nested/icon.png) 10px no-repeat; + background: url(=/nested/icon.png) 10px no-repeat; } diff --git a/playground/css/nested/nested.sss b/playground/css/nested/nested.sss index 2de4c96564a100..9dc685cb3e50c3 100644 --- a/playground/css/nested/nested.sss +++ b/playground/css/nested/nested.sss @@ -5,4 +5,4 @@ .sugarss-at-import-alias color: darkslateblue - background: url(@/nested/icon.png) 10px no-repeat + background: url(=/nested/icon.png) 10px no-repeat diff --git a/playground/css/nested/nested.styl b/playground/css/nested/nested.styl index 72e6f7a5074685..8a371948538de0 100644 --- a/playground/css/nested/nested.styl +++ b/playground/css/nested/nested.styl @@ -3,4 +3,4 @@ .stylus-import-alias color darkslateblue - background url('@/nested/icon.png') 10px no-repeat + background url('=/nested/icon.png') 10px no-repeat diff --git a/playground/css/sass.scss b/playground/css/sass.scss index 1db47622b016ad..721e6b9bfbca6c 100644 --- a/playground/css/sass.scss +++ b/playground/css/sass.scss @@ -1,9 +1,9 @@ -@import '@/nested'; // alias + custom index resolving -> /nested/_index.scss -@import '@/nested/partial'; // sass convention: omitting leading _ for partials +@import '=/nested'; // alias + custom index resolving -> /nested/_index.scss +@import '=/nested/partial'; // sass convention: omitting leading _ for partials @import 'css-dep'; // package w/ sass entry points @import 'virtual-dep'; // virtual file added through importer -@import '@/pkg-dep'; // package w/out sass field -@import '@/weapp.wxss'; // wxss file +@import '=/pkg-dep'; // package w/out sass field +@import '=/weapp.wxss'; // wxss file .sass { /* injected via vite.config.js */ diff --git a/playground/css/sugarss.sss b/playground/css/sugarss.sss index cd393b10519041..80cfc3861b9417 100644 --- a/playground/css/sugarss.sss +++ b/playground/css/sugarss.sss @@ -1,4 +1,4 @@ -@import '@/nested/nested.sss' +@import '=/nested/nested.sss' .sugarss color: blue diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 221c2a75187f35..40ca1a186e58da 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -14,7 +14,7 @@ module.exports = { }, resolve: { alias: { - '@': __dirname, + '=': __dirname, spacefolder: __dirname + '/folder with space', '#alias': __dirname + '/aliased/foo.css', '#alias-module': __dirname + '/aliased/bar.module.css' From ef8d9b86c79f2e8594424b0796f50a9790076f95 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Mon, 31 Oct 2022 23:06:19 +0900 Subject: [PATCH 5/5] test: add test --- playground/css/__tests__/css.spec.ts | 9 +++++++++ playground/css/index.html | 2 ++ playground/css/nested/_index.scss | 6 ++++++ playground/css/nested/nested.less | 6 ++++++ 4 files changed, 23 insertions(+) diff --git a/playground/css/__tests__/css.spec.ts b/playground/css/__tests__/css.spec.ts index 833063f61c7497..e2f41d893021c3 100644 --- a/playground/css/__tests__/css.spec.ts +++ b/playground/css/__tests__/css.spec.ts @@ -10,6 +10,7 @@ import { removeFile, serverLogs, untilUpdated, + viteTestUrl, withRetry } from '~utils' @@ -78,6 +79,7 @@ test('sass', async () => { const imported = await page.$('.sass') const atImport = await page.$('.sass-at-import') const atImportAlias = await page.$('.sass-at-import-alias') + const urlStartsWithVariable = await page.$('.sass-url-starts-with-variable') const partialImport = await page.$('.sass-partial') expect(await getColor(imported)).toBe('orange') @@ -87,6 +89,9 @@ test('sass', async () => { expect(await getBg(atImportAlias)).toMatch( isBuild ? /base64/ : '/nested/icon.png' ) + expect(await getBg(urlStartsWithVariable)).toMatch( + isBuild ? /ok\.\w+\.png/ : `${viteTestUrl}/ok.png` + ) expect(await getColor(partialImport)).toBe('orchid') editFile('sass.scss', (code) => @@ -109,6 +114,7 @@ test('less', async () => { const imported = await page.$('.less') const atImport = await page.$('.less-at-import') const atImportAlias = await page.$('.less-at-import-alias') + const urlStartsWithVariable = await page.$('.less-url-starts-with-variable') expect(await getColor(imported)).toBe('blue') expect(await getColor(atImport)).toBe('darkslateblue') @@ -117,6 +123,9 @@ test('less', async () => { expect(await getBg(atImportAlias)).toMatch( isBuild ? /base64/ : '/nested/icon.png' ) + expect(await getBg(urlStartsWithVariable)).toMatch( + isBuild ? /ok\.\w+\.png/ : `${viteTestUrl}/ok.png` + ) editFile('less.less', (code) => code.replace('@color: blue', '@color: red')) await untilUpdated(() => getColor(imported), 'red') diff --git a/playground/css/index.html b/playground/css/index.html index 799cfebf7adbe3..93f77dfa2eb970 100644 --- a/playground/css/index.html +++ b/playground/css/index.html @@ -32,6 +32,7 @@

CSS

contains alias

@import from SASS _partial: This should be orchid

+

url starts with variable

Imported SASS string:


   

@@ -46,6 +47,7 @@

CSS

@import from Less: This should be darkslateblue and have bg image which url contains alias

+

url starts with variable

Imported Less string:


 
diff --git a/playground/css/nested/_index.scss b/playground/css/nested/_index.scss
index 192e9de3b0e203..fee2eb88b168f2 100644
--- a/playground/css/nested/_index.scss
+++ b/playground/css/nested/_index.scss
@@ -9,3 +9,9 @@
   color: olive;
   background: url(=/nested/icon.png) 10px no-repeat;
 }
+
+$var: '/ok.png';
+.sass-url-starts-with-variable {
+  background: url($var);
+  background-position: center;
+}
diff --git a/playground/css/nested/nested.less b/playground/css/nested/nested.less
index f5a40a69d88839..25aa1944d32c14 100644
--- a/playground/css/nested/nested.less
+++ b/playground/css/nested/nested.less
@@ -7,3 +7,9 @@
   color: darkslateblue;
   background: url(=/nested/icon.png) 10px no-repeat;
 }
+
+@var: '/ok.png';
+.less-url-starts-with-variable {
+  background: url('@{var}');
+  background-position: center;
+}