diff --git a/.changeset/fix-sass-baseurl-resolution.md b/.changeset/fix-sass-baseurl-resolution.md new file mode 100644 index 000000000000..e96d0a9f2fcf --- /dev/null +++ b/.changeset/fix-sass-baseurl-resolution.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes Sass/SCSS `@use` and `@import` not resolving bare specifiers against `baseUrl` in `tsconfig.json`. Projects using `@use "colors.scss"` with `"baseUrl": "src"` now resolve correctly. diff --git a/package.json b/package.json index 08ec341971c9..1dc0d42c5d7c 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "prettier-plugin-astro": "^0.14.1", "publint": "^0.3.17", "tinyglobby": "^0.2.15", - "turbo": "^2.8.11", + "turbo": "^2.8.15", "typescript": "~5.9.3", "typescript-eslint": "^8.56.1", "valibot": "^1.2.0" diff --git a/packages/astro/src/vite-plugin-config-alias/index.ts b/packages/astro/src/vite-plugin-config-alias/index.ts index 57d518da3079..795156a1abef 100644 --- a/packages/astro/src/vite-plugin-config-alias/index.ts +++ b/packages/astro/src/vite-plugin-config-alias/index.ts @@ -91,7 +91,7 @@ const getViteResolveAlias = (settings: AstroSettings) => { for (const resolvedValue of resolvedValues) { const resolved = resolvedValue.replace('*', id); const stats = fs.statSync(resolved, { throwIfNoEntry: false }); - if (stats && stats.isFile()) { + if (stats?.isFile()) { return normalizePath(resolved); } } @@ -110,6 +110,25 @@ const getViteResolveAlias = (settings: AstroSettings) => { } } + // Add baseUrl alias for CSS/Sass bare specifiers (e.g. `@use "colors.scss"`). + // This mirrors the baseUrl handling in getConfigAlias() but is scoped to + // style file extensions to avoid intercepting JS/npm package imports, + // which are handled by the resolveId hook instead. + if (baseUrl) { + aliases.push({ + find: /^(?!\.*\/|\.*$|\w:)(.+\.(?:css|scss|sass|less|styl|stylus))$/, + replacement: '$1', + customResolver(id: string) { + const resolved = path.resolve(resolvedBaseUrl, id); + const stats = fs.statSync(resolved, { throwIfNoEntry: false }); + if (stats?.isFile()) { + return normalizePath(resolved); + } + return null; + }, + }); + } + return aliases; }; diff --git a/packages/astro/test/alias-tsconfig.test.js b/packages/astro/test/alias-tsconfig.test.js index 66ddc7bff82d..c026c3a32603 100644 --- a/packages/astro/test/alias-tsconfig.test.js +++ b/packages/astro/test/alias-tsconfig.test.js @@ -88,6 +88,12 @@ describe('Aliases with tsconfig.json', () => { assert.equal($('#alias').text(), 'foo'); }); + it('resolves Sass @use via baseUrl', async () => { + const html = await fixture.fetch('/').then((res) => res.text()); + // The Sass variable $accent: green should be applied via baseUrl resolution + assert.ok(html.includes('green')); + }); + it('works for import.meta.glob', async () => { const html = await fixture.fetch('/').then((res) => res.text()); const $ = cheerio.load(html); @@ -144,6 +150,14 @@ describe('Aliases with tsconfig.json', () => { assert.equal($('#alias').text(), 'foo'); }); + it('resolves Sass @use via baseUrl', async () => { + const html = await fixture.readFile('/index.html'); + const content = await Promise.all(getLinks(html).map((href) => getLinkContent(href))); + const allCss = content.map(({ css }) => css).join(''); + // The Sass variable $accent: green should be compiled into the CSS + assert.ok(allCss.includes('green')); + }); + it('handles multiple replacements in one alias', async () => { const html = await fixture.readFile('/index.html'); const $ = cheerio.load(html); diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/colors.scss b/packages/astro/test/fixtures/alias-tsconfig/src/colors.scss new file mode 100644 index 000000000000..0a9308d87bec --- /dev/null +++ b/packages/astro/test/fixtures/alias-tsconfig/src/colors.scss @@ -0,0 +1 @@ +$accent: green; diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/components/SassBaseUrl.astro b/packages/astro/test/fixtures/alias-tsconfig/src/components/SassBaseUrl.astro new file mode 100644 index 000000000000..4d7527a2438a --- /dev/null +++ b/packages/astro/test/fixtures/alias-tsconfig/src/components/SassBaseUrl.astro @@ -0,0 +1,11 @@ +--- +--- +
sass-baseurl
+ + diff --git a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro index be6eaf50a402..ff297fbbcca3 100644 --- a/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro +++ b/packages/astro/test/fixtures/alias-tsconfig/src/pages/index.astro @@ -10,6 +10,7 @@ import Baz from "@short/Baz" import StyleComp from 'src/components/Style.astro'; import { foo, index } from 'src/utils/constants'; import { doNothing } from '@pages'; +import SassBaseUrl from '@components/SassBaseUrl.astro'; const globResult = Object.keys(import.meta.glob('@components/glob/*.js')).join(', ') @@ -37,6 +38,7 @@ doNothing()style-red
style-blue
{globResult}
+