diff --git a/CHANGELOG.md b/CHANGELOG.md index 479b3cc41aad..aac350634493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure third-party plugins with `exports` in their `package.json` are resolved correctly ([#14775](https://github.com/tailwindlabs/tailwindcss/pull/14775)) - Ensure underscores in the `url()` function are never unescaped ([#14776](https://github.com/tailwindlabs/tailwindcss/pull/14776)) - _Upgrade (experimental)_: Ensure `@import` statements for relative CSS files are actually migrated to use relative path syntax ([#14769](https://github.com/tailwindlabs/tailwindcss/pull/14769)) +- _Upgrade (experimental)_: Only generate Preflight compatibility styles when Preflight is used ([#14773](https://github.com/tailwindlabs/tailwindcss/pull/14773)) - _Upgrade (experimental)_: Don't escape underscores when printing theme values migrated to CSS variables in arbitrary values (e.g. `m-[var(--spacing-1_5)]` instead of `m-[var(--spacing-1\_5)]`) ([#14778](https://github.com/tailwindlabs/tailwindcss/pull/14778)) ## [4.0.0-alpha.29] - 2024-10-23 diff --git a/integrations/upgrade/index.test.ts b/integrations/upgrade/index.test.ts index 56767178606a..9d1e4230e23d 100644 --- a/integrations/upgrade/index.test.ts +++ b/integrations/upgrade/index.test.ts @@ -912,39 +912,6 @@ test( @import 'tailwindcss/utilities' layer(utilities); @import './utilities.css'; - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/utilities.css --- @utility no-scrollbar { &::-webkit-scrollbar { @@ -1056,82 +1023,13 @@ test( @import 'tailwindcss/utilities' layer(utilities); @import './a.1.css' layer(utilities); @import './a.1.utilities.1.css'; - @import './b.1.css' layer(components); - @import './b.1.utilities.css'; + @import './b.1.css'; @import './c.1.css'; @import './c.1.utilities.css'; @import './d.1.css'; - @import './d.1.utilities.css'; - - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } --- ./src/a.1.css --- - @import './a.1.utilities.css'; - - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } + @import './a.1.utilities.css' --- ./src/a.1.utilities.1.css --- @import './a.1.utilities.utilities.css'; @@ -1155,41 +1053,6 @@ test( } --- ./src/b.1.css --- - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - - --- ./src/b.1.utilities.css --- @import './b.1.components.css'; @utility bar-from-b { color: red; @@ -1197,40 +1060,6 @@ test( --- ./src/c.1.css --- @import './c.2.css' layer(utilities); - - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } .baz-from-c { color: green; } @@ -1240,40 +1069,6 @@ test( --- ./src/c.2.css --- @import './c.3.css'; - - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } #baz { --keep: me; } @@ -1295,121 +1090,12 @@ test( } --- ./src/d.1.css --- - @import './d.2.css' layer(utilities); - - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - - --- ./src/d.1.utilities.css --- - @import './d.2.utilities.css' + @import './d.2.css' --- ./src/d.2.css --- - @import './d.3.css'; - - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - - --- ./src/d.2.utilities.css --- - @import './d.3.utilities.css' + @import './d.3.css' --- ./src/d.3.css --- - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - - --- ./src/d.3.utilities.css --- @import './d.4.css' --- ./src/d.4.css --- @@ -1475,112 +1161,13 @@ test( @import 'tailwindcss/utilities' layer(utilities); @import './a.1.css' layer(utilities); - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/root.2.css --- @import 'tailwindcss/utilities' layer(utilities); @import './a.1.css' layer(components); - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/root.3.css --- @import 'tailwindcss/utilities' layer(utilities); @import './a.1.css' layer(utilities); - - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } " `) }, @@ -1796,76 +1383,9 @@ test( @import './root.4/utilities.css'; @config '../tailwind.config.ts'; - /* - 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); - } - } - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/root.5.css --- @import './root.5/tailwind.css'; - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/root.4/base.css --- @import 'tailwindcss/theme' layer(theme); @import 'tailwindcss/preflight' layer(base); @@ -1907,40 +1427,6 @@ test( --- ./src/root.4/utilities.css --- @import 'tailwindcss/utilities' layer(utilities); - /* - 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); - } - } - - /* - Form elements have a 1px border by default 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 \`border-0\` to - any form elements that shouldn't have a border. - */ - @layer base { - input:where(:not([type='button'], [type='reset'], [type='submit'])), - select, - textarea { - border-width: 0; - } - } - --- ./src/root.5/tailwind.css --- /* Inject missing @config in this file, due to full import */ @import 'tailwindcss'; diff --git a/integrations/upgrade/js-config.test.ts b/integrations/upgrade/js-config.test.ts index 41fd83073264..592ced85aff9 100644 --- a/integrations/upgrade/js-config.test.ts +++ b/integrations/upgrade/js-config.test.ts @@ -993,4 +993,178 @@ describe('border compatibility', () => { `) }, ) + + test( + 'migrate border compatibility in the file that uses the `@import "tailwindcss"` import', + { + fs: { + 'package.json': json` + { + "dependencies": { + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': ts` + import { type Config } from 'tailwindcss' + + export default { + theme: {}, + } satisfies Config + `, + 'src/input.css': css`@import './tailwind.css';`, + 'src/tailwind.css': css` + @tailwind base; + @tailwind components; + @tailwind utilities; + `, + }, + }, + async ({ exec, fs }) => { + await exec('npx @tailwindcss/upgrade') + + expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` + " + --- src/input.css --- + @import './tailwind.css'; + + --- src/tailwind.css --- + @import 'tailwindcss'; + + /* + 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); + } + } + + /* + Form elements have a 1px border by default 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 \`border-0\` to + any form elements that shouldn't have a border. + */ + @layer base { + input:where(:not([type='button'], [type='reset'], [type='submit'])), + select, + textarea { + border-width: 0; + } + } + " + `) + }, + ) + + test( + 'migrate border compatibility in the file that uses the `@import "tailwindcss/preflight"` import', + { + fs: { + 'package.json': json` + { + "dependencies": { + "@tailwindcss/upgrade": "workspace:^" + } + } + `, + 'tailwind.config.ts': ts` + import { type Config } from 'tailwindcss' + + export default { + theme: {}, + } satisfies Config + `, + 'src/input.css': css` + @import './base.css'; + @import './my-base.css'; + @import './utilities.css'; + `, + 'src/base.css': css`@tailwind base;`, + 'src/utilities.css': css` + @tailwind components; + @tailwind utilities; + `, + 'src/my-base.css': css` + @layer base { + html { + color: black; + } + } + `, + }, + }, + async ({ exec, fs }) => { + await exec('npx @tailwindcss/upgrade') + + expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` + " + --- 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); + } + } + + /* + Form elements have a 1px border by default 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 \`border-0\` to + any form elements that shouldn't have a border. + */ + @layer base { + input:where(:not([type='button'], [type='reset'], [type='submit'])), + select, + textarea { + border-width: 0; + } + } + + --- src/input.css --- + @import './base.css'; + @import './my-base.css'; + @import './utilities.css'; + + --- src/my-base.css --- + @layer base { + html { + color: black; + } + } + + --- src/utilities.css --- + @import 'tailwindcss/utilities' layer(utilities); + " + `) + }, + ) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.test.ts index df633df5f75d..65bbaac3dbc0 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.test.ts @@ -69,14 +69,14 @@ it("should add compatibility CSS after the `@import 'tailwindcss'`", async () => it('should add the compatibility CSS after the last `@import`', async () => { expect( await migrate(css` - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + @import 'tailwindcss'; + @import './foo.css'; + @import './bar.css'; `), ).toMatchInlineSnapshot(` - "@import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + "@import 'tailwindcss'; + @import './foo.css'; + @import './bar.css'; /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -117,27 +117,91 @@ it('should add the compatibility CSS after the last import, even if a body-less expect( await migrate(css` @charset "UTF-8"; - @layer foo, bar, baz; + @layer foo, bar, baz, base; /**! * License header */ - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + @import 'tailwindcss'; + @import './foo.css'; + @import './bar.css'; `), ).toMatchInlineSnapshot(` "@charset "UTF-8"; - @layer foo, bar, baz; + @layer foo, bar, baz, base; /**! * License header */ - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + @import 'tailwindcss'; + @import './foo.css'; + @import './bar.css'; + + /* + 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); + } + } + /* + Form elements have a 1px border by default 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 \`border-0\` to + any form elements that shouldn't have a border. + */ + @layer base { + input:where(:not([type='button'], [type='reset'], [type='submit'])), + select, + textarea { + border-width: 0; + } + }" + `) +}) + +it('should add the compatibility CSS before the first `@layer base` (if the "tailwindcss" import exists)', async () => { + expect( + await migrate(css` + @import 'tailwindcss'; + + @variant foo { + } + + @utility bar { + } + + @layer base { + } + + @utility baz { + } + + @layer base { + } + `), + ).toMatchInlineSnapshot(` + "@import 'tailwindcss'; + + @variant foo { + } + + @utility bar { + } /* The default border color has changed to \`currentColor\` in Tailwind CSS v4, @@ -147,6 +211,7 @@ it('should add the compatibility CSS after the last import, even if a body-less 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, @@ -156,6 +221,7 @@ it('should add the compatibility CSS after the last import, even if a body-less border-color: var(--color-gray-200, currentColor); } } + /* Form elements have a 1px border by default in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the @@ -170,16 +236,23 @@ it('should add the compatibility CSS after the last import, even if a body-less textarea { border-width: 0; } + } + + @layer base { + } + + @utility baz { + } + + @layer base { }" `) }) -it('should add the compatibility CSS before the first `@layer base`', async () => { +it('should add the compatibility CSS before the first `@layer base` (if the "tailwindcss/preflight" import exists)', async () => { expect( await migrate(css` - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + @import 'tailwindcss/preflight'; @variant foo { } @@ -197,9 +270,7 @@ it('should add the compatibility CSS before the first `@layer base`', async () = } `), ).toMatchInlineSnapshot(` - "@import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; + "@import 'tailwindcss/preflight'; @variant foo { } @@ -252,3 +323,79 @@ it('should add the compatibility CSS before the first `@layer base`', async () = }" `) }) + +it('should not add the backwards compatibility CSS when no `@import "tailwindcss"` or `@import "tailwindcss/preflight"` exists', async () => { + expect( + await migrate(css` + @variant foo { + } + + @utility bar { + } + + @layer base { + } + + @utility baz { + } + + @layer base { + } + `), + ).toMatchInlineSnapshot(` + "@variant foo { + } + + @utility bar { + } + + @layer base { + } + + @utility baz { + } + + @layer base { + }" + `) +}) + +it('should not add the backwards compatibility CSS when another `@import "tailwindcss"` import exists such as theme or utilities', async () => { + expect( + await migrate(css` + @import 'tailwindcss/theme'; + + @variant foo { + } + + @utility bar { + } + + @layer base { + } + + @utility baz { + } + + @layer base { + } + `), + ).toMatchInlineSnapshot(` + "@import 'tailwindcss/theme'; + + @variant foo { + } + + @utility bar { + } + + @layer base { + } + + @utility baz { + } + + @layer base { + }" + `) +}) diff --git a/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.ts index a81465d9cedf..f6e7b1e38246 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-border-compatibility.ts @@ -64,6 +64,19 @@ export function migrateBorderCompatibility({ } function migrate(root: Root) { + let isTailwindRoot = false + root.walkAtRules('import', (node) => { + if ( + /['"]tailwindcss['"]/.test(node.params) || + /['"]tailwindcss\/preflight['"]/.test(node.params) + ) { + isTailwindRoot = true + return false + } + }) + + if (!isTailwindRoot) return + let targetNode = null as AtRule | null root.walkAtRules((node) => {