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 <adam.wathan@gmail.com>
This commit is contained in:
parent
e4308da604
commit
aa343a9445
5 changed files with 69 additions and 10 deletions
|
|
@ -24,7 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
- Use the right import base path when using the CLI to reading files from stdin ([#14522](https://github.com/tailwindlabs/tailwindcss/pull/14522))
|
||||
- Ensure that `@utility` is top-level and cannot be nested ([#14525](https://github.com/tailwindlabs/tailwindcss/pull/14525))
|
||||
- Editing imported CSS files should trigger a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
|
||||
- Ensure editing imported CSS files triggers a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
|
||||
- Ensure `@apply` and CSS functions work inside imported stylesheets ([#14576](https://github.com/tailwindlabs/tailwindcss/pull/14576))
|
||||
- _Experimental_: Improve codemod output, keep CSS after last Tailwind directive unlayered ([#14512](https://github.com/tailwindlabs/tailwindcss/pull/14512))
|
||||
- _Experimental_: Fix incorrect empty `layer()` at the end of `@import` at-rules when running codemods ([#14513](https://github.com/tailwindlabs/tailwindcss/pull/14513))
|
||||
- _Experimental_: Do not wrap comment nodes in `@layer` when running codemods ([#14517](https://github.com/tailwindlabs/tailwindcss/pull/14517))
|
||||
|
|
|
|||
|
|
@ -901,3 +901,37 @@ describe('in JS config files', () => {
|
|||
`)
|
||||
})
|
||||
})
|
||||
|
||||
test('replaces CSS theme() function with values inside imported stylesheets', async () => {
|
||||
expect(
|
||||
await compileCss(
|
||||
css`
|
||||
@theme {
|
||||
--color-red-500: #f00;
|
||||
}
|
||||
@import './bar.css';
|
||||
`,
|
||||
[],
|
||||
{
|
||||
async loadStylesheet() {
|
||||
return {
|
||||
base: '/bar.css',
|
||||
content: css`
|
||||
.red {
|
||||
color: theme(colors.red.500);
|
||||
}
|
||||
`,
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
":root {
|
||||
--color-red-500: red;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: red;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -254,6 +254,34 @@ describe('@apply', () => {
|
|||
`)
|
||||
})
|
||||
|
||||
it('should replace @apply with the correct result inside imported stylesheets', async () => {
|
||||
expect(
|
||||
await compileCss(
|
||||
css`
|
||||
@import './bar.css';
|
||||
@tailwind utilities;
|
||||
`,
|
||||
[],
|
||||
{
|
||||
async loadStylesheet() {
|
||||
return {
|
||||
base: '/bar.css',
|
||||
content: css`
|
||||
.foo {
|
||||
@apply underline;
|
||||
}
|
||||
`,
|
||||
}
|
||||
},
|
||||
},
|
||||
),
|
||||
).toMatchInlineSnapshot(`
|
||||
".foo {
|
||||
text-decoration-line: underline;
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
it('should @apply in order the utilities would be sorted in if they were used in HTML', async () => {
|
||||
expect(
|
||||
await compileCss(css`
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { applyCompatibilityHooks } from './compat/apply-compat-hooks'
|
|||
import type { UserConfig } from './compat/config/types'
|
||||
import { type Plugin } from './compat/plugin-api'
|
||||
import { compileCandidates } from './compile'
|
||||
import { substituteFunctions, THEME_FUNCTION_INVOCATION } from './css-functions'
|
||||
import { substituteFunctions } from './css-functions'
|
||||
import * as CSS from './css-parser'
|
||||
import { buildDesignSystem, type DesignSystem } from './design-system'
|
||||
import { Theme, ThemeOptions } from './theme'
|
||||
|
|
@ -341,13 +341,9 @@ async function parseCss(
|
|||
}
|
||||
|
||||
// Replace `@apply` rules with the actual utility classes.
|
||||
if (css.includes('@apply')) {
|
||||
substituteAtApply(ast, designSystem)
|
||||
}
|
||||
substituteAtApply(ast, designSystem)
|
||||
|
||||
if (css.includes(THEME_FUNCTION_INVOCATION)) {
|
||||
substituteFunctions(ast, designSystem.resolveThemeValue)
|
||||
}
|
||||
substituteFunctions(ast, designSystem.resolveThemeValue)
|
||||
|
||||
// Remove `@utility`, we couldn't replace it before yet because we had to
|
||||
// handle the nested `@apply` at-rules first.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Features, transform } from 'lightningcss'
|
||||
import { compile } from '..'
|
||||
|
||||
export async function compileCss(css: string, candidates: string[] = []) {
|
||||
let { build } = await compile(css)
|
||||
export async function compileCss(css: string, candidates: string[] = [], options = {}) {
|
||||
let { build } = await compile(css, options)
|
||||
return optimizeCss(build(candidates)).trim()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue