You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ensure @utility is processed before using them (#15542)
This PR fixes an issue where using an `@utility` before it is defined,
and _if_ that `@utility` contains `@apply`, that it won't result in the
expected output. But results in an `@apply` rule that is not
substituted. Additionally, if you have multiple levels of `@apply`, we
have to make sure that everything is applied (no pun intended) in the
right order.
Right now, the following steps are taken:
1. Collect all the `@utility` at-rules (and register them in the system
as utilities).
2. Substitute `@apply` on the AST (including `@utility`'s ASTs) with the
content of the utility.
3. Delete the `@utility` at-rules such that they are removed from the
CSS output itself.
The reason we do it in this order is because handling `@apply` during
`@utility`
handling means that we could rely on another `@utility` that is defined
later
and therefore the order of the utilities starts to matter. This is not a
bad
thing, but the moment you import multiple CSS files or plugins, this
could
become hard to manage.
Another important step is that when using `@utility foo`, the
implementation creates a `structuredClone` from its AST when first using
the utility. The reason we do that is because `foo` and `foo!` generate
different output and we don't want to accidentally mutate the same AST.
This structured clone is the start of the problem in the linked issue
(#15501).
If we don't do the structured clone, then substituting the `@apply`
rules would work, but then `foo` and `foo!` will generate the same
output, which is bad.
The linked issue has this structure:
```css
.foo {
@apply bar;
}
@Utility bar {
@apply flex;
}
```
If we follow the steps above, this would substitute `@apply bar` first,
which
results in:
```css
.foo {
@apply flex;
}
```
But the `bar` utility, was already cloned (and cached) so now we end up
with an `@apply` rule that is not substituted.
To properly solve this problem, we have to make sure that we collect all
the `@apply` at-rules, and apply them in the correct order. To do this,
we run a topological sort on them which ensures that all the
dependencies are applied before substituting the current `@apply`.
This means that in the above example, in order to process `@apply bar`,
we have to process the `bar` utility first.
If we run into a circular dependency, then we will throw an error like
before. You'll notice that the error message in this PR is updated to a
different spot. This one is a bit easier to grasp because it shows the
error where the circular dependency _starts_ not where it _ends_ (and
completes the circle). The previous message was not wrong (since it's a
circle), but now it's a bit easier to reason about.
Fixes: #15501
Copy file name to clipboardExpand all lines: CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
19
- Fix `inset-shadow-*` suggestions in IntelliSense ([#15471](https://github.com/tailwindlabs/tailwindcss/pull/15471))
20
20
- Only compile arbitrary values ending in `]` ([#15503](https://github.com/tailwindlabs/tailwindcss/pull/15503))
21
21
- Improve performance and memory usage ([#15529](https://github.com/tailwindlabs/tailwindcss/pull/15529))
22
+
- Ensure `@apply` rules are processed in the correct order ([#15542](https://github.com/tailwindlabs/tailwindcss/pull/15542))
22
23
-_Upgrade (experimental)_: Do not extract class names from functions (e.g. `shadow` in `filter: 'drop-shadow(…)'`) ([#15566](https://github.com/tailwindlabs/tailwindcss/pull/15566))
0 commit comments