Skip to content

Commit aa343a9

Browse files
Fix @apply and CSS functions inside imported files (#14576)
Part-of #14558 After handling `@import` of stylesheets in core, we can no longer gate out features based on finding a specific sequence in the input CSS, as this string will not contain contents from other stylesheets. So, consider the following input CSS: ```css @import "tailwindcsss"; @import "./styles.css"; ``` We can't opt-out of the traversal to search for `@apply` based on it because it, of course, does not contain the contents of `./styles.css` yet. --------- Co-authored-by: Adam Wathan <[email protected]>
1 parent e4308da commit aa343a9

File tree

5 files changed

+69
-10
lines changed

5 files changed

+69
-10
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424

2525
- Use the right import base path when using the CLI to reading files from stdin ([#14522](https://github.com/tailwindlabs/tailwindcss/pull/14522))
2626
- Ensure that `@utility` is top-level and cannot be nested ([#14525](https://github.com/tailwindlabs/tailwindcss/pull/14525))
27-
- Editing imported CSS files should trigger a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
27+
- Ensure editing imported CSS files triggers a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
28+
- Ensure `@apply` and CSS functions work inside imported stylesheets ([#14576](https://github.com/tailwindlabs/tailwindcss/pull/14576))
2829
- _Experimental_: Improve codemod output, keep CSS after last Tailwind directive unlayered ([#14512](https://github.com/tailwindlabs/tailwindcss/pull/14512))
2930
- _Experimental_: Fix incorrect empty `layer()` at the end of `@import` at-rules when running codemods ([#14513](https://github.com/tailwindlabs/tailwindcss/pull/14513))
3031
- _Experimental_: Do not wrap comment nodes in `@layer` when running codemods ([#14517](https://github.com/tailwindlabs/tailwindcss/pull/14517))

packages/tailwindcss/src/css-functions.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,3 +901,37 @@ describe('in JS config files', () => {
901901
`)
902902
})
903903
})
904+
905+
test('replaces CSS theme() function with values inside imported stylesheets', async () => {
906+
expect(
907+
await compileCss(
908+
css`
909+
@theme {
910+
--color-red-500: #f00;
911+
}
912+
@import './bar.css';
913+
`,
914+
[],
915+
{
916+
async loadStylesheet() {
917+
return {
918+
base: '/bar.css',
919+
content: css`
920+
.red {
921+
color: theme(colors.red.500);
922+
}
923+
`,
924+
}
925+
},
926+
},
927+
),
928+
).toMatchInlineSnapshot(`
929+
":root {
930+
--color-red-500: red;
931+
}
932+
933+
.red {
934+
color: red;
935+
}"
936+
`)
937+
})

packages/tailwindcss/src/index.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,34 @@ describe('@apply', () => {
254254
`)
255255
})
256256

257+
it('should replace @apply with the correct result inside imported stylesheets', async () => {
258+
expect(
259+
await compileCss(
260+
css`
261+
@import './bar.css';
262+
@tailwind utilities;
263+
`,
264+
[],
265+
{
266+
async loadStylesheet() {
267+
return {
268+
base: '/bar.css',
269+
content: css`
270+
.foo {
271+
@apply underline;
272+
}
273+
`,
274+
}
275+
},
276+
},
277+
),
278+
).toMatchInlineSnapshot(`
279+
".foo {
280+
text-decoration-line: underline;
281+
}"
282+
`)
283+
})
284+
257285
it('should @apply in order the utilities would be sorted in if they were used in HTML', async () => {
258286
expect(
259287
await compileCss(css`

packages/tailwindcss/src/index.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import { applyCompatibilityHooks } from './compat/apply-compat-hooks'
1616
import type { UserConfig } from './compat/config/types'
1717
import { type Plugin } from './compat/plugin-api'
1818
import { compileCandidates } from './compile'
19-
import { substituteFunctions, THEME_FUNCTION_INVOCATION } from './css-functions'
19+
import { substituteFunctions } from './css-functions'
2020
import * as CSS from './css-parser'
2121
import { buildDesignSystem, type DesignSystem } from './design-system'
2222
import { Theme, ThemeOptions } from './theme'
@@ -341,13 +341,9 @@ async function parseCss(
341341
}
342342

343343
// Replace `@apply` rules with the actual utility classes.
344-
if (css.includes('@apply')) {
345-
substituteAtApply(ast, designSystem)
346-
}
344+
substituteAtApply(ast, designSystem)
347345

348-
if (css.includes(THEME_FUNCTION_INVOCATION)) {
349-
substituteFunctions(ast, designSystem.resolveThemeValue)
350-
}
346+
substituteFunctions(ast, designSystem.resolveThemeValue)
351347

352348
// Remove `@utility`, we couldn't replace it before yet because we had to
353349
// handle the nested `@apply` at-rules first.

packages/tailwindcss/src/test-utils/run.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Features, transform } from 'lightningcss'
22
import { compile } from '..'
33

4-
export async function compileCss(css: string, candidates: string[] = []) {
5-
let { build } = await compile(css)
4+
export async function compileCss(css: string, candidates: string[] = [], options = {}) {
5+
let { build } = await compile(css, options)
66
return optimizeCss(build(candidates)).trim()
77
}
88

0 commit comments

Comments
 (0)