Skip to content

Commit bd52e6b

Browse files
Merge remote-tracking branch 'origin/next' into feat/improve-postcss-performance
2 parents 6ea41a6 + 2e87288 commit bd52e6b

File tree

21 files changed

+568
-69
lines changed

21 files changed

+568
-69
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Add support for prefixes ([#14501](https://github.com/tailwindlabs/tailwindcss/pull/14501))
1313
- Expose timing information in debug mode ([#14553](https://github.com/tailwindlabs/tailwindcss/pull/14553))
1414
- Add support for `blocklist` in config files ([#14556](https://github.com/tailwindlabs/tailwindcss/pull/14556))
15+
- Add `color-scheme` utilities ([#14567](https://github.com/tailwindlabs/tailwindcss/pull/14567))
1516
- _Experimental_: Migrate `@import "tailwindcss/tailwind.css"` to `@import "tailwindcss"` ([#14514](https://github.com/tailwindlabs/tailwindcss/pull/14514))
17+
- _Experimental_: Migrate `@apply` utilities with the template codemods ([#14574](https://github.com/tailwindlabs/tailwindcss/pull/14574))
18+
- _Experimental_: Add template codemods for migrating variant order ([#14524](https://github.com/tailwindlabs/tailwindcss/pull/14524]))
1619
- _Experimental_: Add template codemods for migrating `bg-gradient-*` utilities to `bg-linear-*` ([#14537](https://github.com/tailwindlabs/tailwindcss/pull/14537]))
1720
- _Experimental_: Add template codemods for migrating prefixes ([#14557](https://github.com/tailwindlabs/tailwindcss/pull/14557]))
1821
- _Experimental_: Add template codemods for removal of automatic `var(…)` injection ([#14526](https://github.com/tailwindlabs/tailwindcss/pull/14526))
@@ -24,6 +27,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2427
- Ensure that `@utility` is top-level and cannot be nested ([#14525](https://github.com/tailwindlabs/tailwindcss/pull/14525))
2528
- Editing imported CSS files should trigger a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
2629
- Only setup a single compiler in `@tailwindcss/postcss` for initial builds ([#14565](https://github.com/tailwindlabs/tailwindcss/pull/14565))
30+
- Ensure editing imported CSS files triggers a rebuild ([#14561](https://github.com/tailwindlabs/tailwindcss/pull/14561))
31+
- Ensure `@apply` and CSS functions work inside imported stylesheets ([#14576](https://github.com/tailwindlabs/tailwindcss/pull/14576))
2732
- _Experimental_: Improve codemod output, keep CSS after last Tailwind directive unlayered ([#14512](https://github.com/tailwindlabs/tailwindcss/pull/14512))
2833
- _Experimental_: Fix incorrect empty `layer()` at the end of `@import` at-rules when running codemods ([#14513](https://github.com/tailwindlabs/tailwindcss/pull/14513))
2934
- _Experimental_: Do not wrap comment nodes in `@layer` when running codemods ([#14517](https://github.com/tailwindlabs/tailwindcss/pull/14517))

crates/oxide/src/scanner/fixtures/binary-extensions.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ npx
135135
numbers
136136
nupkg
137137
o
138+
oa
138139
odp
139140
ods
140141
odt
@@ -151,6 +152,7 @@ pdf
151152
pea
152153
pgm
153154
pic
155+
plist
154156
png
155157
pnm
156158
pot
@@ -200,9 +202,11 @@ sqlite
200202
sqlite3
201203
sqlite3
202204
stl
205+
storedata
203206
sub
204207
suo
205208
swf
209+
symbolsarchive
206210
tar
207211
tbz
208212
tbz2

integrations/upgrade/index.test.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ test(
6969
@tailwind base;
7070
@tailwind components;
7171
@tailwind utilities;
72+
73+
.btn {
74+
@apply !tw__rounded-md tw__px-2 tw__py-1 tw__bg-blue-500 tw__text-white;
75+
}
7276
`,
7377
},
7478
},
@@ -83,7 +87,15 @@ test(
8387
`,
8488
)
8589

86-
await fs.expectFileToContain('src/input.css', css`@import 'tailwindcss' prefix(tw);`)
90+
await fs.expectFileToContain('src/input.css', css` @import 'tailwindcss' prefix(tw); `)
91+
await fs.expectFileToContain(
92+
'src/input.css',
93+
css`
94+
.btn {
95+
@apply tw:rounded-md! tw:px-2 tw:py-1 tw:bg-blue-500 tw:text-white;
96+
}
97+
`,
98+
)
8799
},
88100
)
89101

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"devDependencies": {
5151
"@playwright/test": "^1.47.1",
5252
"@types/node": "catalog:",
53-
"postcss": "8.4.41",
53+
"postcss": "8.4.47",
5454
"postcss-import": "^16.1.0",
5555
"prettier": "^3.3.3",
5656
"prettier-plugin-embed": "^0.4.15",

packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.test.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import { __unstable__loadDesignSystem } from '@tailwindcss/node'
12
import dedent from 'dedent'
23
import postcss from 'postcss'
34
import { expect, it } from 'vitest'
45
import { migrateAtApply } from './migrate-at-apply'
56

67
const css = dedent
78

8-
function migrate(input: string) {
9+
function migrateWithoutConfig(input: string) {
910
return postcss()
1011
.use(migrateAtApply())
1112
.process(input, { from: expect.getState().testPath })
@@ -14,7 +15,7 @@ function migrate(input: string) {
1415

1516
it('should not migrate `@apply`, when there are no issues', async () => {
1617
expect(
17-
await migrate(css`
18+
await migrateWithoutConfig(css`
1819
.foo {
1920
@apply flex flex-col items-center;
2021
}
@@ -28,7 +29,7 @@ it('should not migrate `@apply`, when there are no issues', async () => {
2829

2930
it('should append `!` to each utility, when using `!important`', async () => {
3031
expect(
31-
await migrate(css`
32+
await migrateWithoutConfig(css`
3233
.foo {
3334
@apply flex flex-col !important;
3435
}
@@ -43,7 +44,7 @@ it('should append `!` to each utility, when using `!important`', async () => {
4344
// TODO: Handle SCSS syntax
4445
it.skip('should append `!` to each utility, when using `#{!important}`', async () => {
4546
expect(
46-
await migrate(css`
47+
await migrateWithoutConfig(css`
4748
.foo {
4849
@apply flex flex-col #{!important};
4950
}
@@ -57,7 +58,7 @@ it.skip('should append `!` to each utility, when using `#{!important}`', async (
5758

5859
it('should move the legacy `!` prefix, to the new `!` postfix notation', async () => {
5960
expect(
60-
await migrate(css`
61+
await migrateWithoutConfig(css`
6162
.foo {
6263
@apply !flex flex-col! hover:!items-start items-center;
6364
}
@@ -68,3 +69,36 @@ it('should move the legacy `!` prefix, to the new `!` postfix notation', async (
6869
}"
6970
`)
7071
})
72+
73+
it('should apply all candidate migration when migrating with a config', async () => {
74+
async function migrateWithConfig(input: string) {
75+
return postcss()
76+
.use(
77+
migrateAtApply({
78+
designSystem: await __unstable__loadDesignSystem(
79+
css`
80+
@import 'tailwindcss' prefix(tw);
81+
`,
82+
{ base: __dirname },
83+
),
84+
userConfig: {
85+
prefix: 'tw_',
86+
},
87+
}),
88+
)
89+
.process(input, { from: expect.getState().testPath })
90+
.then((result) => result.css)
91+
}
92+
93+
expect(
94+
await migrateWithConfig(css`
95+
.foo {
96+
@apply !tw_flex [color:--my-color] tw_bg-gradient-to-t;
97+
}
98+
`),
99+
).toMatchInlineSnapshot(`
100+
".foo {
101+
@apply tw:flex! tw:[color:var(--my-color)] tw:bg-linear-to-t;
102+
}"
103+
`)
104+
})

packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import type { AtRule, Plugin } from 'postcss'
2+
import type { Config } from 'tailwindcss'
3+
import type { DesignSystem } from '../../../tailwindcss/src/design-system'
24
import { segment } from '../../../tailwindcss/src/utils/segment'
5+
import { migrateCandidate } from '../template/migrate'
36

4-
export function migrateAtApply(): Plugin {
7+
export function migrateAtApply({
8+
designSystem,
9+
userConfig,
10+
}: { designSystem?: DesignSystem; userConfig?: Config } = {}): Plugin {
511
function migrate(atRule: AtRule) {
612
let utilities = atRule.params.split(/(\s+)/)
713
let important =
@@ -30,6 +36,12 @@ export function migrateAtApply(): Plugin {
3036
return [...variants, utility].join(':')
3137
})
3238

39+
// If we have a valid designSystem and config setup, we can run all
40+
// candidate migrations on each utility
41+
if (designSystem && userConfig) {
42+
params = params.map((param) => migrateCandidate(designSystem, userConfig, param))
43+
}
44+
3345
atRule.params = params.join('').trim()
3446
}
3547

packages/@tailwindcss-upgrade/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ async function run() {
112112
// Migrate each file
113113
await Promise.allSettled(
114114
files.map((file) =>
115-
migrateStylesheet(file, { newPrefix: parsedConfig?.newPrefix ?? undefined }),
115+
migrateStylesheet(file, {
116+
newPrefix: parsedConfig?.newPrefix ?? undefined,
117+
designSystem: parsedConfig?.designSystem,
118+
userConfig: parsedConfig?.userConfig,
119+
}),
116120
),
117121
)
118122

packages/@tailwindcss-upgrade/src/migrate.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import fs from 'node:fs/promises'
22
import path from 'node:path'
33
import postcss from 'postcss'
4+
import type { Config } from 'tailwindcss'
5+
import type { DesignSystem } from '../../tailwindcss/src/design-system'
46
import { formatNodes } from './codemods/format-nodes'
57
import { migrateAtApply } from './codemods/migrate-at-apply'
68
import { migrateAtLayerUtilities } from './codemods/migrate-at-layer-utilities'
@@ -9,11 +11,13 @@ import { migrateTailwindDirectives } from './codemods/migrate-tailwind-directive
911

1012
export interface MigrateOptions {
1113
newPrefix?: string
14+
designSystem?: DesignSystem
15+
userConfig?: Config
1216
}
1317

1418
export async function migrateContents(contents: string, options: MigrateOptions, file?: string) {
1519
return postcss()
16-
.use(migrateAtApply())
20+
.use(migrateAtApply(options))
1721
.use(migrateAtLayerUtilities())
1822
.use(migrateMissingLayers())
1923
.use(migrateTailwindDirectives(options))
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { __unstable__loadDesignSystem } from '@tailwindcss/node'
2+
import dedent from 'dedent'
3+
import { expect, test } from 'vitest'
4+
import { variantOrder } from './variant-order'
5+
6+
let css = dedent
7+
8+
test.each([
9+
// Does nothing unless there are at least two variants
10+
['flex', 'flex'],
11+
['hover:flex', 'hover:flex'],
12+
['[color:red]', '[color:red]'],
13+
['[&:focus]:[color:red]', '[&:focus]:[color:red]'],
14+
15+
// Reorders simple variants that include combinators
16+
['*:first:flex', 'first:*:flex'],
17+
18+
// Does not reorder variants without combinators
19+
['data-[invalid]:data-[hover]:flex', 'data-[invalid]:data-[hover]:flex'],
20+
21+
// Does not reorder some known combinations where the order does not matter
22+
['hover:focus:flex', 'hover:focus:flex'],
23+
['focus:hover:flex', 'focus:hover:flex'],
24+
['[&:hover]:[&:focus]:flex', '[&:hover]:[&:focus]:flex'],
25+
['[&:focus]:[&:hover]:flex', '[&:focus]:[&:hover]:flex'],
26+
['data-[a]:data-[b]:flex', 'data-[a]:data-[b]:flex'],
27+
28+
// Handles pseudo-elements that cannot have anything after them
29+
// c.f. https://github.com/tailwindlabs/tailwindcss/pull/13478/files#diff-7779a0eebf6b980dd3abd63b39729b3023cf9a31c91594f5a25ea020b066e1c0
30+
['dark:before:flex', 'dark:before:flex'],
31+
['before:dark:flex', 'dark:before:flex'],
32+
33+
// Puts some pseudo-elements that must appear at the end of the selector at
34+
// the end of the candidate
35+
['dark:*:before:after:flex', 'dark:*:before:after:flex'],
36+
['dark:before:after:*:flex', 'dark:*:before:after:flex'],
37+
38+
// Some pseudo-elements are treated as regular variants
39+
['dark:*:hover:file:focus:underline', 'dark:focus:file:hover:*:underline'],
40+
41+
// Keeps at-rule-variants and the dark variant in the beginning and keeps their
42+
// order
43+
['sm:dark:hover:flex', 'sm:dark:hover:flex'],
44+
['[@media(print)]:group-hover:flex', '[@media(print)]:group-hover:flex'],
45+
['sm:max-xl:data-[a]:data-[b]:dark:hover:flex', 'sm:max-xl:dark:data-[a]:data-[b]:hover:flex'],
46+
[
47+
'sm:data-[root]:*:data-[a]:even:*:data-[b]:even:before:underline',
48+
'sm:even:data-[b]:*:even:data-[a]:*:data-[root]:before:underline',
49+
],
50+
['hover:[@supports(display:grid)]:flex', '[@supports(display:grid)]:hover:flex'],
51+
])('%s => %s', async (candidate, result) => {
52+
let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', {
53+
base: __dirname,
54+
})
55+
56+
expect(variantOrder(designSystem, {}, candidate)).toEqual(result)
57+
})
58+
59+
test('it works with custom variants', async () => {
60+
let designSystem = await __unstable__loadDesignSystem(
61+
css`
62+
@import 'tailwindcss';
63+
@variant atrule {
64+
@media (print) {
65+
@slot;
66+
}
67+
}
68+
69+
@variant combinator {
70+
> * {
71+
@slot;
72+
}
73+
}
74+
75+
@variant pseudo {
76+
&::before {
77+
@slot;
78+
}
79+
}
80+
`,
81+
{
82+
base: __dirname,
83+
},
84+
)
85+
86+
expect(variantOrder(designSystem, {}, 'combinator:pseudo:atrule:underline')).toEqual(
87+
'atrule:combinator:pseudo:underline',
88+
)
89+
})

0 commit comments

Comments
 (0)