From 62f81fcfd0c5c1eb750e3cec7932dabf768a6217 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 13 Nov 2024 15:09:41 +0100 Subject: [PATCH 1/6] add failing test --- integrations/upgrade/index.test.ts | 133 +++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index 469291390e61..beeb36e15cdf 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -1467,6 +1467,139 @@ test( }, ) +test( + 'injecting `@config` in the shared root, when a tailwind.config.{js,ts,…} is detected', + { + fs: { + 'package.json': json` + { + "dependencies": { + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': js` + export default { + content: ['./src/**/*.{html,js}'], + plugins: [ + () => { + // custom stuff which is too complicated to migrate to CSS + }, + ], + } + `, + 'src/index.html': html` +
+ `, + 'src/index.css': css`@import './tailwind-setup.css';`, + 'src/tailwind-setup.css': css` + @import './base.css'; + @import './components.css'; + @import './utilities.css'; + `, + 'src/base.css': css` + html { + color: red; + } + @tailwind base; + `, + 'src/components.css': css` + @import './typography.css'; + @layer components { + .foo { + color: red; + } + } + @tailwind components; + `, + 'src/typography.css': css` + .typography { + color: red; + } + `, + 'src/utilities.css': css` + @layer utilities { + .bar { + color: red; + } + } + @tailwind utilities; + `, + }, + }, + async ({ exec, fs }) => { + await exec('npx @tailwindcss/upgrade --force') + + expect(await fs.dumpFiles('./src/**/*.{html,css}')).toMatchInlineSnapshot(` + " + --- ./src/index.html --- +
+ + --- ./src/index.css --- + @import './tailwind-setup.css'; + + --- ./src/base.css --- + @import 'tailwindcss/theme' layer(theme); + @import 'tailwindcss/preflight' layer(base); + + /* + The default border color has changed to \`currentColor\` in Tailwind CSS v4, + so we've added these compatibility styles to make sure everything still + looks the same as it did with Tailwind CSS v3. + + If we ever want to remove these styles, we need to add an explicit border + color utility to any element that depends on these defaults. + */ + @layer base { + *, + ::after, + ::before, + ::backdrop, + ::file-selector-button { + border-color: var(--color-gray-200, currentColor); + } + } + + @layer base { + html { + color: red; + } + } + + --- ./src/components.css --- + @import './typography.css'; + + @utility foo { + color: red; + } + + --- ./src/tailwind-setup.css --- + @import './base.css'; + @import './components.css'; + @import './utilities.css'; + + @config '../tailwind.config.ts'; + + --- ./src/typography.css --- + .typography { + color: red; + } + + --- ./src/utilities.css --- + @import 'tailwindcss/utilities' layer(utilities); + + @utility bar { + color: red; + } + " + `) + }, +) + test( 'relative imports without a relative path prefix are migrated to include a relative path prefix', { From fb97717208f1af6393736aa11da46017e003fddf Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 13 Nov 2024 15:04:13 +0100 Subject: [PATCH 2/6] break once we found common parent Once we found a common parent between two sheets, we can stop finding the parent and continue to the next sheets. --- packages/@tailwindcss-upgrade/src/migrate.ts | 26 ++++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/@tailwindcss-upgrade/src/migrate.ts b/packages/@tailwindcss-upgrade/src/migrate.ts index e75dd3328d65..5b481335aab4 100644 --- a/packages/@tailwindcss-upgrade/src/migrate.ts +++ b/packages/@tailwindcss-upgrade/src/migrate.ts @@ -253,22 +253,38 @@ export async function analyze(stylesheets: Stylesheet[]) { for (let [sheetB, childrenB] of commonParents) { if (sheetA === sheetB) continue - for (let parentA of sheetA.ancestors()) { - for (let parentB of sheetB.ancestors()) { + // Ancestors from self to root. Reversed order so we find the + // nearest common parent first + // + // Including self because if you compare a sheet with its parent, + // then the parent is still the common sheet between the two. In + // this case, the parent is the root file. + let ancestorsA = [sheetA].concat(Array.from(sheetA.ancestors()).reverse()) + let ancestorsB = [sheetB].concat(Array.from(sheetB.ancestors()).reverse()) + + for (let parentA of ancestorsA) { + for (let parentB of ancestorsB) { if (parentA !== parentB) continue + // Found the parent + let parent = parentA + commonParents.delete(sheetA) commonParents.delete(sheetB) for (let child of childrenA) { - commonParents.get(parentA).add(child) + commonParents.get(parent).add(child) } for (let child of childrenB) { - commonParents.get(parentA).add(child) + commonParents.get(parent).add(child) } - repeat = true + repeat = parent !== sheetA && parent !== sheetB + + // Found a common parent between sheet A and sheet B. We can + // stop looking for more common parents between A and B, and + // continue with the next sheet. break outer } } From 36bceb0b567859c386288f1e71b08e7b80b28d78 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 13 Nov 2024 16:14:57 +0100 Subject: [PATCH 3/6] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd3b69192809..ef368bca4f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Ensure that CSS inside Svelte `