tailwindcss/packages/@tailwindcss-upgrade
Philipp Spiess e4308da604
Template migrations: Add variant order codemods (#14524)
One of the breaking changes of v4 is the [inversion of variant order
application](https://github.com/tailwindlabs/tailwindcss/pull/13478). In
v3, variants are applied "inside-out".


For example a candidate like `*:first:underline` would produce the
following CSS in v3:

```css
.\*\:first\:underline:first-child > * {
  text-decoration-line: underline;
}
```

To get the same behavior in v4, you would need to invert the candidate
order to `first:*:underline`. This would generate the following CSS in
v4:

```css
:where(.first\:\*\:underline:first-child > *) {
  text-decoration-line: underline;
}
```

## The Migration

The most naive approach would be to invert the variants for every
candidate with at least two variants. This, however, runs into one issue
and some unexpected inconsistencies. I have identified the following
areas:

1. Some pseudo class variants _must appear at the end of the selector_.
v3 was patching over this by doing some manual reordering in for these
variants. For example, in v3, both of these variants create the same
output CSS: `hover:before:underline` and `before:hover:underline`. In v4
we simplified this system though and no longer generate the same output
in both cases. Instead, you'd always want to write
`hover:before:underline`, ensuring that these variants will appear at
the end.
   
For an exact list of which variants these affect, take a look [at this
diff](https://github.com/tailwindlabs/tailwindcss/pull/13478/files#diff-7779a0eebf6b980dd3abd63b39729b3023cf9a31c91594f5a25ea020b066e1c0L228-L246).

2. The `dark` variant and other at-rule variants are usually written
before other variants. This is more of a recommendation to make it
easier to read candidates rather than a difference in behavior as
`@media` queries are hoisted by the engine. For this reason, both of
these variants are _correct_ yet in real applications we prefer the
first one: `lg:hover:underline`, `hover:lg:underline`.
   
To avoid shuffling these rules across all candidates during the
migration, we bucket `dark` and other at-rule variants into a special
bucket that will not have their order changed (since people wrote stacks
like `sm:max-lg:` before and we want to keep them as-is) and appear
before all other variants.

3. For some variant stacks, the order does not matter. E.g.:
`focus:hover:underline` and `hover:focus:underline` will be the same. We
don't want to needlessly shuffle their order if we have to.

With these considerations, the migration now works as follows:

- If there is less then two variants, we do not need to migrate the
candidate
- If _every_ variant in the stack is an order-independent variant, we do
not need to migrate the candidate
- _Note that this is currently hardcoded to only support `&:hover` and
`&:focus`._
- Otherwise, we loop over the candidates and put them into three
buckets:
- `mediaVariants` hold variants that only contribute `@media` rules
_and_ the `dark` variant.
- `pseudoElementVariants` hold variants that _must appear at the end of
the selector_. This is based on the allow list from v3/early v4.
  - `regularVariants` contains the rest.
- We now compute if any of the variants inside `regularVariants` is
order dependent.
- With this list of variants, we now construct the new order of variants
as:
   
   ```ts
   [
     ...atRuleVariants,
...(anyRegularVariantOrderDependent ? regularVariants.reverse() :
regularVariants),
     ...pseudoElementVariants,
   ]
   ```

---------

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2024-10-03 09:15:19 -04:00
..
2024-09-18 16:45:43 +02:00

Tailwind CSS

A utility-first CSS framework for rapidly building custom user interfaces.

Build Status Total Downloads Latest Release License


Documentation

For full documentation, visit tailwindcss.com.

Community

For help, discussion about best practices, or any other conversation that would benefit from being searchable:

Discuss Tailwind CSS on GitHub

For chatting with others using the framework:

Join the Tailwind CSS Discord Server

Contributing

If you're interested in contributing to Tailwind CSS, please read our contributing docs before submitting a pull request.