Skip to content

Commit 42d79e0

Browse files
committed
Place @utility rules into separate stylesheets as needed
Now that we convert layered, imported rules into `@utility` where needed we need to hoist these rules outside of their imported layer since `@utility` MUST be root-level.
1 parent 3bd0221 commit 42d79e0

File tree

4 files changed

+503
-2
lines changed

4 files changed

+503
-2
lines changed

integrations/upgrade/index.test.ts

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,234 @@ test(
577577
`)
578578
},
579579
)
580+
581+
test(
582+
'migrate utilities in an imported file',
583+
{
584+
fs: {
585+
'package.json': json`
586+
{
587+
"dependencies": {
588+
"tailwindcss": "workspace:^",
589+
"@tailwindcss/upgrade": "workspace:^"
590+
}
591+
}
592+
`,
593+
'tailwind.config.js': js`module.exports = {}`,
594+
'src/index.css': css`
595+
@import 'tailwindcss';
596+
@import './utilities.css' layer(utilities);
597+
`,
598+
'src/utilities.css': css`
599+
.no-scrollbar::-webkit-scrollbar {
600+
display: none;
601+
}
602+
603+
.no-scrollbar {
604+
-ms-overflow-style: none;
605+
scrollbar-width: none;
606+
}
607+
`,
608+
},
609+
},
610+
async ({ fs, exec }) => {
611+
await exec('npx @tailwindcss/upgrade --force')
612+
613+
expect(await fs.dumpFiles('./src/**/*.css')).toMatchInlineSnapshot(`
614+
"
615+
--- ./src/index.css ---
616+
@import 'tailwindcss';
617+
@import './utilities.css';
618+
619+
--- ./src/utilities.css ---
620+
@utility no-scrollbar {
621+
&::-webkit-scrollbar {
622+
display: none;
623+
}
624+
-ms-overflow-style: none;
625+
scrollbar-width: none;
626+
}"
627+
`)
628+
},
629+
)
630+
631+
test(
632+
'migrate utilities in deep import trees',
633+
{
634+
fs: {
635+
'package.json': json`
636+
{
637+
"dependencies": {
638+
"tailwindcss": "workspace:^",
639+
"@tailwindcss/cli": "workspace:^",
640+
"@tailwindcss/upgrade": "workspace:^"
641+
}
642+
}
643+
`,
644+
'tailwind.config.js': js`module.exports = {}`,
645+
'src/index.html': html`
646+
<div class="hover:thing"></div>
647+
`,
648+
'src/index.css': css`
649+
@import 'tailwindcss/utilities';
650+
@import './a.1.css' layer(utilities);
651+
@import './b.1.css' layer(components);
652+
@import './c.1.css';
653+
@import './d.1.css';
654+
`,
655+
'src/a.1.css': css`
656+
@import './a.1.utilities.css';
657+
658+
.foo-from-a {
659+
color: red;
660+
}
661+
`,
662+
'src/a.1.utilities.css': css`
663+
#foo {
664+
--keep: me;
665+
}
666+
667+
.foo-from-import {
668+
color: blue;
669+
}
670+
`,
671+
'src/b.1.css': css`
672+
@import './b.1.components.css';
673+
674+
.bar-from-b {
675+
color: red;
676+
}
677+
`,
678+
'src/b.1.components.css': css`
679+
.bar-from-import {
680+
color: blue;
681+
}
682+
`,
683+
'src/c.1.css': css`
684+
@import './c.2.css' layer(utilities);
685+
.baz-from-c {
686+
color: green;
687+
}
688+
`,
689+
'src/c.2.css': css`
690+
@import './c.3.css';
691+
#baz {
692+
--keep: me;
693+
}
694+
.baz-from-import {
695+
color: yellow;
696+
}
697+
`,
698+
'src/c.3.css': css`
699+
#baz {
700+
--keep: me;
701+
}
702+
.baz-from-import {
703+
color: yellow;
704+
}
705+
`,
706+
707+
// This is a super deep import chain
708+
// And no `*.utilities.css` files should be created for these
709+
// because there are no rules that need to be separated
710+
'src/d.1.css': css`@import './d.2.css' layer(utilities);`,
711+
'src/d.2.css': css`@import './d.3.css';`,
712+
'src/d.3.css': css`@import './d.4.css';`,
713+
'src/d.4.css': css`
714+
.from-a-4 {
715+
color: blue;
716+
}
717+
`,
718+
},
719+
},
720+
async ({ fs, exec }) => {
721+
await exec('npx @tailwindcss/upgrade --force')
722+
723+
expect(await fs.dumpFiles('./src/**/*.css')).toMatchInlineSnapshot(`
724+
"
725+
--- ./src/index.css ---
726+
@import 'tailwindcss/utilities' layer(utilities);
727+
@import './a.1.css' layer(utilities);
728+
@import './a.1.utilities.1.css';
729+
@import './b.1.css';
730+
@import './c.1.css' layer(utilities);
731+
@import './c.1.utilities.css';
732+
@import './d.1.css';
733+
734+
--- ./src/a.1.css ---
735+
@import './a.1.utilities.css'
736+
737+
--- ./src/a.1.utilities.1.css ---
738+
@import './a.1.utilities.utilities.css';
739+
@utility foo-from-a {
740+
color: red;
741+
}
742+
743+
--- ./src/a.1.utilities.css ---
744+
#foo {
745+
--keep: me;
746+
}
747+
748+
--- ./src/a.1.utilities.utilities.css ---
749+
@utility foo-from-import {
750+
color: blue;
751+
}
752+
753+
--- ./src/b.1.components.css ---
754+
@utility bar-from-import {
755+
color: blue;
756+
}
757+
758+
--- ./src/b.1.css ---
759+
@import './b.1.components.css';
760+
@utility bar-from-b {
761+
color: red;
762+
}
763+
764+
--- ./src/c.1.css ---
765+
@import './c.2.css' layer(utilities);
766+
.baz-from-c {
767+
color: green;
768+
}
769+
770+
--- ./src/c.1.utilities.css ---
771+
@import './c.2.utilities.css'
772+
773+
--- ./src/c.2.css ---
774+
@import './c.3.css';
775+
#baz {
776+
--keep: me;
777+
}
778+
779+
--- ./src/c.2.utilities.css ---
780+
@import './c.3.utilities.css';
781+
@utility baz-from-import {
782+
color: yellow;
783+
}
784+
785+
--- ./src/c.3.css ---
786+
#baz {
787+
--keep: me;
788+
}
789+
790+
--- ./src/c.3.utilities.css ---
791+
@utility baz-from-import {
792+
color: yellow;
793+
}
794+
795+
--- ./src/d.1.css ---
796+
@import './d.2.css'
797+
798+
--- ./src/d.2.css ---
799+
@import './d.3.css'
800+
801+
--- ./src/d.3.css ---
802+
@import './d.4.css'
803+
804+
--- ./src/d.4.css ---
805+
@utility from-a-4 {
806+
color: blue;
807+
}"
808+
`)
809+
},
810+
)

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@ import path from 'node:path'
66
import postcss from 'postcss'
77
import { formatNodes } from './codemods/format-nodes'
88
import { help } from './commands/help'
9-
import { analyze as analyzeStylesheets, migrate as migrateStylesheet } from './migrate'
9+
import {
10+
analyze as analyzeStylesheets,
11+
migrate as migrateStylesheet,
12+
split as splitStylesheets,
13+
} from './migrate'
1014
import { migratePostCSSConfig } from './migrate-postcss'
1115
import { Stylesheet } from './stylesheet'
1216
import { migrate as migrateTemplate } from './template/migrate'
@@ -130,6 +134,13 @@ async function run() {
130134
}
131135
}
132136

137+
// Split up stylesheets (as needed)
138+
try {
139+
await splitStylesheets(stylesheets)
140+
} catch (e: unknown) {
141+
error(`${e}`)
142+
}
143+
133144
// Format nodes
134145
for (let sheet of stylesheets) {
135146
await postcss([formatNodes()]).process(sheet.root!, { from: sheet.file! })

0 commit comments

Comments
 (0)