From d6c4e7235114f01edd8c719f2465d974068f236e Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 7 Jan 2025 16:41:43 +0100 Subject: [PATCH] =?UTF-8?q?Add=20`@reference=20"=E2=80=A6"`=20(#15565)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds a new `@reference "…"` API as an replacement for the previously added [`@import "…" reference`](https://github.com/tailwindlabs/tailwindcss/pull/15228). The motivation for a distinct at rule is that `@import` is already handled outside of Tailwind in some scenarios (e.g. when using in combination with postcss-import, other pre-processors, or frameworks like Svelte). While our implementation of hijacking the `media` attribute _works in this cases_, it can cause annoying linter issues because tooling build around `@import` does not know about our behavior. To fix this, we've decided to move this mode into a separate at rule that is passed-through in the other tooling. Here's an example of how this would look like in Svelte: ```svelte

Hello world!

``` With this change, the Svelte linter would not be detecting unused CSS from the `theme.css` file as it would if we'd rely on `@import`. --- CHANGELOG.md | 1 + packages/tailwindcss/src/at-import.test.ts | 33 ++++++++++++++++++++++ packages/tailwindcss/src/at-import.ts | 5 +++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63ae55988543..5330bffd728e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `@tailwindcss/browser` package to run Tailwind CSS in the browser ([#15558](https://github.com/tailwindlabs/tailwindcss/pull/15558)) +- Add `@reference "…"` API as a replacement for the previous `@import "…" reference` option ([#15565](https://github.com/tailwindlabs/tailwindcss/pull/15565)) ### Fixed diff --git a/packages/tailwindcss/src/at-import.test.ts b/packages/tailwindcss/src/at-import.test.ts index dafb8af07fd5..108498216d9a 100644 --- a/packages/tailwindcss/src/at-import.test.ts +++ b/packages/tailwindcss/src/at-import.test.ts @@ -553,3 +553,36 @@ test('it crashes when inside a cycle', async () => { `[Error: Exceeded maximum recursion depth while resolving \`foo.css\` in \`/root\`)]`, ) }) + +test('resolves @reference as `@import "…" reference`', async () => { + let loadStylesheet = async (id: string, base: string) => { + expect(base).toBe('/root') + expect(id).toBe('./foo/bar.css') + return { + content: css` + @theme { + --color-red-500: red; + } + .foo { + color: red; + } + `, + base: '/root/foo', + } + } + + await expect( + run( + css` + @reference './foo/bar.css'; + @tailwind utilities; + `, + { loadStylesheet, candidates: ['text-red-500'] }, + ), + ).resolves.toMatchInlineSnapshot(` + ".text-red-500 { + color: var(--color-red-500); + } + " + `) +}) diff --git a/packages/tailwindcss/src/at-import.ts b/packages/tailwindcss/src/at-import.ts index 4a585202d531..effd33e5b203 100644 --- a/packages/tailwindcss/src/at-import.ts +++ b/packages/tailwindcss/src/at-import.ts @@ -15,9 +15,12 @@ export async function substituteAtImports( let promises: Promise[] = [] walk(ast, (node, { replaceWith }) => { - if (node.kind === 'at-rule' && node.name === '@import') { + if (node.kind === 'at-rule' && (node.name === '@import' || node.name === '@reference')) { let parsed = parseImportParams(ValueParser.parse(node.params)) if (parsed === null) return + if (node.name === '@reference') { + parsed.media = 'reference' + } features |= Features.AtImport