Skip to content

Commit ac528a4

Browse files
fix(css): skip resolving resolved paths in sass (#20300)
Co-authored-by: graphite-app[bot] <96075541+graphite-app[bot]@users.noreply.github.com>
1 parent 08ef74c commit ac528a4

File tree

6 files changed

+53
-26
lines changed

6 files changed

+53
-26
lines changed

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

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2433,23 +2433,31 @@ const makeScssWorker = (
24332433
return unquotedUrl.startsWith('#{')
24342434
}
24352435

2436-
const internalImporter: Sass.Importer<'async'> = {
2436+
const createInternalImporter = (
2437+
isForRelative: boolean,
2438+
): Sass.Importer<'async'> => ({
24372439
async canonicalize(url, context) {
2438-
const importer = context.containingUrl
2439-
? fileURLToPath(context.containingUrl)
2440-
: options.filename
2441-
const resolved = await resolvers.sass(
2442-
environment,
2443-
url,
2444-
cleanScssBugUrl(importer),
2445-
)
2446-
if (
2447-
resolved &&
2448-
(resolved.endsWith('.css') ||
2449-
resolved.endsWith('.scss') ||
2450-
resolved.endsWith('.sass'))
2451-
) {
2452-
return pathToFileURL(resolved)
2440+
if (isForRelative) {
2441+
// sass passes resolved paths for importer passed to `importer` option
2442+
const resolved = new URL(url, context.containingUrl ?? undefined)
2443+
if (fs.existsSync(resolved)) return resolved
2444+
} else {
2445+
const importer = context.containingUrl
2446+
? fileURLToPath(context.containingUrl)
2447+
: options.filename
2448+
const resolved = await resolvers.sass(
2449+
environment,
2450+
url,
2451+
cleanScssBugUrl(importer),
2452+
)
2453+
if (
2454+
resolved &&
2455+
(resolved.endsWith('.css') ||
2456+
resolved.endsWith('.scss') ||
2457+
resolved.endsWith('.sass'))
2458+
) {
2459+
return pathToFileURL(resolved)
2460+
}
24532461
}
24542462
return null
24552463
},
@@ -2472,12 +2480,13 @@ const makeScssWorker = (
24722480
result.contents ?? (await fsp.readFile(result.file, 'utf-8'))
24732481
return { contents, syntax, sourceMapUrl: canonicalUrl }
24742482
},
2475-
}
2483+
})
2484+
24762485
sassOptions.importers = [
24772486
...(sassOptions.importers ?? []),
2478-
internalImporter,
2487+
createInternalImporter(false),
24792488
]
2480-
sassOptions.importer ??= internalImporter
2489+
sassOptions.importer ??= createInternalImporter(true)
24812490

24822491
const result = await compiler.compileStringAsync(data, sassOptions)
24832492
return {

playground/css/__tests__/sass-tests.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export const sassTest = () => {
77
const atImport = await page.$('.sass-at-import')
88
const atImportAlias = await page.$('.sass-at-import-alias')
99
const atImportRelative = await page.$('.sass-at-import-relative')
10+
const atImportReplacementAlias = await page.$(
11+
'.sass-at-import-replacement-alias',
12+
)
1013
const urlStartsWithVariable = await page.$('.sass-url-starts-with-variable')
1114
const urlStartsWithVariableInterpolation1 = await page.$(
1215
'.sass-url-starts-with-interpolation1',
@@ -35,6 +38,7 @@ export const sassTest = () => {
3538
expect(await getBg(atImportRelative)).toMatch(
3639
isBuild ? /base64/ : '/nested/icon.png',
3740
)
41+
expect(await getColor(atImportReplacementAlias)).toBe('olive')
3842
expect(await getBg(urlStartsWithVariable)).toMatch(
3943
isBuild ? /ok-[-\w]+\.png/ : `${viteTestUrl}/ok.png`,
4044
)

playground/css/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ <h1>CSS</h1>
3636
<p class="sass-at-import-relative">
3737
@import from SASS relative: This should be olive and have bg image
3838
</p>
39+
<p class="sass-at-import-replacement-alias">
40+
@import with replacement alias from SASS: This should be olive
41+
</p>
3942
<p class="sass-partial">@import from SASS _partial: This should be orchid</p>
4043
<p class="sass-url-starts-with-variable">url starts with variable</p>
4144
<p class="sass-url-starts-with-interpolation1">
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.sass-at-import-replacement-alias {
2+
color: olive;
3+
}

playground/css/sass.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
@use '=/weapp.wxss'; // wxss file
1010
@use 'virtual-file-absolute';
1111
@use '=/scss-dir/main.scss'; // "./dir" reference from vite custom importer
12+
@use '=replace/nested/replacement-alias.scss';
1213

1314
.sass {
1415
/* injected via vite.config.js */

playground/css/vite.config.js

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,20 @@ export default defineConfig({
6262
},
6363
},
6464
resolve: {
65-
alias: {
66-
'=': __dirname,
67-
spacefolder: __dirname + '/folder with space',
68-
'#alias': __dirname + '/aliased/foo.css',
69-
'#alias?inline': __dirname + '/aliased/foo.css?inline',
70-
'#alias-module': __dirname + '/aliased/bar.module.css',
71-
},
65+
alias: [
66+
{ find: '=', replacement: __dirname },
67+
{ find: /=replace\/(.*)/, replacement: `${__dirname}/$1` },
68+
{ find: 'spacefolder', replacement: __dirname + '/folder with space' },
69+
{ find: '#alias', replacement: __dirname + '/aliased/foo.css' },
70+
{
71+
find: '#alias?inline',
72+
replacement: __dirname + '/aliased/foo.css?inline',
73+
},
74+
{
75+
find: '#alias-module',
76+
replacement: __dirname + '/aliased/bar.module.css',
77+
},
78+
],
7279
},
7380
css: {
7481
modules: {

0 commit comments

Comments
 (0)