Skip to content

Commit f19afd9

Browse files
authored
Improve root file detection (#15048)
This PR fixes an issue where the Tailwind root file detection was wrong. Whenever a CSS file contains any of the `@tailwind` directives or an `@import` to any of the Tailwind files, the file is considered a Tailwind root file. If multiple CSS files are part of the same tree, then we make the nearest common parent the root file. This root file will be the file where we add `@config` and/or inject other changes during the migration process. However, if your folder structure looked like this: ```css /* index.css */ @import "./base.css"; @import "./typography.css"; @import "tailwindcss/components"; /* This makes index.css a root file */ @import "./utilities.css"; /* base.css */ @tailwind base; /* This makes base.css a root file */ /* utilities.css */ @tailwind utilities; /* This makes utilities.css a root file */ ``` Then we computed that `index.css` nad `base.css` were considered root files even though they belong to the same tree (because `base.css` is imported by `index.css`). This PR fixes that behaviour by essentially being less smart, and just checking again if any sheets are part of the same tree. # Test plan: Added an integration test that covers this scenario and fails before the fix. Also ran it on our tailwindcss.com codebase. | Before | After | | --- | --- | | <img width="1072" alt="image" src="https://github.com/user-attachments/assets/8ee99a59-335e-4221-b368-a8cd81e85191"> | <img width="1072" alt="image" src="https://github.com/user-attachments/assets/fe5acae4-d3fc-43a4-bd31-eee768a3a6a5"> | (Yes, I know the migration still fails, but that's a different issue.)
1 parent 7b19b00 commit f19afd9

File tree

3 files changed

+106
-5
lines changed

3 files changed

+106
-5
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3131
- _Upgrade (experimental)_: Ignore analyzing imports with external URLs (e.g.: `@import "https://fonts.google.com"`) ([#15040](https://github.com/tailwindlabs/tailwindcss/pull/15040))
3232
- _Upgrade (experimental)_: Ignore analyzing imports with `url(…)` (e.g.: `@import url("https://fonts.google.com")`) ([#15040](https://github.com/tailwindlabs/tailwindcss/pull/15040))
3333
- _Upgrade (experimental)_: Use `resolveJsId` when resolving `tailwindcss/package.json` ([#15041](https://github.com/tailwindlabs/tailwindcss/pull/15041))
34+
- _Upgrade (experimental)_: Ensure children of Tailwind root file are not considered Tailwind root files ([#15048](https://github.com/tailwindlabs/tailwindcss/pull/15048))
3435

3536
### Changed
3637

integrations/upgrade/index.test.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,107 @@ test(
19701970
},
19711971
)
19721972

1973+
test(
1974+
'finds the correct root Tailwind CSS file',
1975+
{
1976+
fs: {
1977+
'package.json': json`
1978+
{
1979+
"dependencies": {
1980+
"tailwindcss": "^3",
1981+
"@tailwindcss/upgrade": "workspace:^"
1982+
}
1983+
}
1984+
`,
1985+
'tailwind.config.ts': js`export default {}`,
1986+
1987+
/* Considered a Tailwind root because of: `@import 'tailwindcss/components'` */
1988+
'src/index.css': css`
1989+
@import 'base.css';
1990+
@import 'other.css';
1991+
@import 'tailwindcss/components';
1992+
@import 'utilities.css';
1993+
`,
1994+
1995+
/* Considered a Tailwind root because of: `@tailwind base` */
1996+
'src/base.css': css`
1997+
html {
1998+
color: red;
1999+
}
2000+
@tailwind base;
2001+
`,
2002+
'src/other.css': css`
2003+
.typography {
2004+
color: red;
2005+
}
2006+
`,
2007+
2008+
/* Considered a Tailwind root because of: `@tailwind utilities` */
2009+
'src/utilities.css': css`
2010+
@layer utilities {
2011+
.foo {
2012+
color: red;
2013+
}
2014+
}
2015+
2016+
@tailwind utilities;
2017+
`,
2018+
},
2019+
},
2020+
async ({ exec, fs }) => {
2021+
await exec('npx @tailwindcss/upgrade --force')
2022+
2023+
expect(await fs.dumpFiles('./src/**/*.{html,css}')).toMatchInlineSnapshot(`
2024+
"
2025+
--- ./src/index.css ---
2026+
@import './base.css' layer(components);
2027+
@import './other.css' layer(components);
2028+
@import './utilities.css';
2029+
2030+
--- ./src/base.css ---
2031+
@import 'tailwindcss/theme' layer(theme);
2032+
@import 'tailwindcss/preflight' layer(base);
2033+
2034+
/*
2035+
The default border color has changed to \`currentColor\` in Tailwind CSS v4,
2036+
so we've added these compatibility styles to make sure everything still
2037+
looks the same as it did with Tailwind CSS v3.
2038+
2039+
If we ever want to remove these styles, we need to add an explicit border
2040+
color utility to any element that depends on these defaults.
2041+
*/
2042+
@layer base {
2043+
*,
2044+
::after,
2045+
::before,
2046+
::backdrop,
2047+
::file-selector-button {
2048+
border-color: var(--color-gray-200, currentColor);
2049+
}
2050+
}
2051+
2052+
@layer base {
2053+
html {
2054+
color: red;
2055+
}
2056+
}
2057+
2058+
--- ./src/other.css ---
2059+
.typography {
2060+
color: red;
2061+
}
2062+
2063+
--- ./src/utilities.css ---
2064+
@import 'tailwindcss/utilities' layer(utilities);
2065+
2066+
@utility foo {
2067+
color: red;
2068+
}
2069+
"
2070+
`)
2071+
},
2072+
)
2073+
19732074
test(
19742075
'relative imports without a relative path prefix are migrated to include a relative path prefix',
19752076
{

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,10 @@ export async function analyze(stylesheets: Stylesheet[]) {
282282
// parent A and parent B will be moved to the parent of parent A and
283283
// parent B. Parent A and parent B will be removed.
284284
let repeat = true
285-
while (repeat) {
285+
repeat: while (repeat) {
286286
repeat = false
287287

288-
outer: for (let [sheetA, childrenA] of commonParents) {
288+
for (let [sheetA, childrenA] of commonParents) {
289289
for (let [sheetB, childrenB] of commonParents) {
290290
if (sheetA === sheetB) continue
291291

@@ -316,12 +316,11 @@ export async function analyze(stylesheets: Stylesheet[]) {
316316
commonParents.get(parent).add(child)
317317
}
318318

319-
repeat = parent !== sheetA && parent !== sheetB
320-
321319
// Found a common parent between sheet A and sheet B. We can
322320
// stop looking for more common parents between A and B, and
323321
// continue with the next sheet.
324-
break outer
322+
repeat = true
323+
continue repeat
325324
}
326325
}
327326
}

0 commit comments

Comments
 (0)