Skip to content

Commit f5978b6

Browse files
committed
ensure @config "…" is added when tailwind.config.js is detected
1 parent 2d1aced commit f5978b6

File tree

4 files changed

+147
-3
lines changed

4 files changed

+147
-3
lines changed

integrations/upgrade/index.test.ts

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ test(
3939
<div class="flex! sm:block! bg-linear-to-t bg-[var(--my-red)]"></div>
4040
4141
--- ./src/input.css ---
42-
@import 'tailwindcss';"
42+
@import 'tailwindcss';
43+
@config "../tailwind.config.js";"
4344
`)
4445
},
4546
)
@@ -89,6 +90,8 @@ test(
8990
--- ./src/input.css ---
9091
@import 'tailwindcss' prefix(tw);
9192
93+
@config "../tailwind.config.js";
94+
9295
.btn {
9396
@apply tw:rounded-md! tw:px-2 tw:py-1 tw:bg-blue-500 tw:text-white;
9497
}"
@@ -134,6 +137,8 @@ test(
134137
--- ./src/index.css ---
135138
@import 'tailwindcss';
136139
140+
@config "../tailwind.config.js";
141+
137142
.a {
138143
@apply flex;
139144
}
@@ -187,6 +192,8 @@ test(
187192
--- ./src/index.css ---
188193
@import 'tailwindcss';
189194
195+
@config "../tailwind.config.js";
196+
190197
@layer base {
191198
html {
192199
color: #333;
@@ -245,6 +252,8 @@ test(
245252
--- ./src/index.css ---
246253
@import 'tailwindcss';
247254
255+
@config "../tailwind.config.js";
256+
248257
@utility btn {
249258
@apply rounded-md px-2 py-1 bg-blue-500 text-white;
250259
}
@@ -297,6 +306,7 @@ test(
297306
--- ./src/index.css ---
298307
@import 'tailwindcss';
299308
@import './utilities.css';
309+
@config "../tailwind.config.js";
300310
301311
--- ./src/utilities.css ---
302312
@utility no-scrollbar {
@@ -412,6 +422,7 @@ test(
412422
@import './c.1.css' layer(utilities);
413423
@import './c.1.utilities.css';
414424
@import './d.1.css';
425+
@config "../tailwind.config.js";
415426
416427
--- ./src/a.1.css ---
417428
@import './a.1.utilities.css'
@@ -544,14 +555,17 @@ test(
544555
--- ./src/root.1.css ---
545556
@import 'tailwindcss/utilities' layer(utilities);
546557
@import './a.1.css' layer(utilities);
558+
@config "../tailwind.config.js";
547559
548560
--- ./src/root.2.css ---
549561
@import 'tailwindcss/utilities' layer(utilities);
550562
@import './a.1.css' layer(components);
563+
@config "../tailwind.config.js";
551564
552565
--- ./src/root.3.css ---
553566
@import 'tailwindcss/utilities' layer(utilities);
554-
@import './a.1.css' layer(utilities);"
567+
@import './a.1.css' layer(utilities);
568+
@config "../tailwind.config.js";"
555569
`)
556570
},
557571
)
@@ -643,3 +657,50 @@ test(
643657
)
644658
},
645659
)
660+
661+
test(
662+
'injecting `@config` when a tailwind.config.{js,ts,…} is detected',
663+
{
664+
fs: {
665+
'package.json': json`
666+
{
667+
"dependencies": {
668+
"@tailwindcss/upgrade": "workspace:^"
669+
}
670+
}
671+
`,
672+
'tailwind.config.ts': js`
673+
export default {
674+
content: ['./src/**/*.{html,js}'],
675+
}
676+
`,
677+
'src/index.html': html`
678+
<h1>🤠👋</h1>
679+
<div class="!flex sm:!block bg-gradient-to-t bg-[--my-red]"></div>
680+
`,
681+
'src/input.css': css`
682+
@tailwind base;
683+
@tailwind components;
684+
@tailwind utilities;
685+
`,
686+
},
687+
},
688+
async ({ exec, fs }) => {
689+
await exec('npx @tailwindcss/upgrade --force')
690+
691+
await fs.expectFileToContain(
692+
'src/index.html',
693+
html`
694+
<h1>🤠👋</h1>
695+
<div class="flex! sm:block! bg-linear-to-t bg-[var(--my-red)]"></div>
696+
`,
697+
)
698+
699+
expect(await fs.dumpFiles('./src/**/*.css')).toMatchInlineSnapshot(`
700+
"
701+
--- ./src/input.css ---
702+
@import 'tailwindcss';
703+
@config "../tailwind.config.ts";"
704+
`)
705+
},
706+
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import path from 'node:path'
2+
import { AtRule, type Plugin, type Root } from 'postcss'
3+
import type { Stylesheet } from '../stylesheet'
4+
import { walk, WalkAction } from '../utils/walk'
5+
6+
export function migrateAtConfig(
7+
sheet: Stylesheet,
8+
{ configFilePath }: { configFilePath: string },
9+
): Plugin {
10+
function migrate(root: Root) {
11+
let hasConfig = false
12+
root.walkAtRules('config', () => {
13+
hasConfig = true
14+
return false
15+
})
16+
17+
// We already have a `@config`
18+
if (hasConfig) return
19+
20+
// We don't have a sheet with a file path
21+
// TODO: Why? Tests?
22+
if (!sheet.file) return
23+
24+
// Should this sheet have an `@config`?
25+
// 1. It should be a root CSS file
26+
if (sheet.parents.size > 0) return
27+
28+
// 2. It should include a `@import "tailwindcss"`
29+
let hasTailwindImport = false
30+
root.walkAtRules('import', (node) => {
31+
if (node.params.includes('tailwindcss')) {
32+
hasTailwindImport = true
33+
return false
34+
}
35+
})
36+
if (!hasTailwindImport) return
37+
38+
// Figure out the path to the config file
39+
let sheetPath = sheet.file
40+
let configPath = configFilePath
41+
42+
let relativePath = path.relative(path.dirname(sheetPath), configPath)
43+
if (relativePath[0] !== '.') {
44+
relativePath = `./${relativePath}`
45+
}
46+
47+
// Inject the `@config` in a sensible place
48+
let locationNode = null as AtRule | null
49+
50+
walk(root, (node) => {
51+
if (node.type === 'atrule' && (node.name === 'import' || node.name === 'theme')) {
52+
locationNode = node
53+
}
54+
55+
return WalkAction.Skip
56+
})
57+
58+
let configNode = new AtRule({ name: 'config', params: `"${relativePath}"` })
59+
60+
if (!locationNode) {
61+
root.prepend(configNode)
62+
} else if (locationNode.name === 'import') {
63+
locationNode.after(configNode)
64+
} else if (locationNode.name === 'theme') {
65+
locationNode.before(configNode)
66+
}
67+
}
68+
69+
return {
70+
postcssPlugin: '@tailwindcss/upgrade/migrate-at-config',
71+
OnceExit: migrate,
72+
}
73+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { DesignSystem } from '../../tailwindcss/src/design-system'
55
import { DefaultMap } from '../../tailwindcss/src/utils/default-map'
66
import { segment } from '../../tailwindcss/src/utils/segment'
77
import { migrateAtApply } from './codemods/migrate-at-apply'
8+
import { migrateAtConfig } from './codemods/migrate-at-config'
89
import { migrateAtLayerUtilities } from './codemods/migrate-at-layer-utilities'
910
import { migrateMissingLayers } from './codemods/migrate-missing-layers'
1011
import { migrateTailwindDirectives } from './codemods/migrate-tailwind-directives'
@@ -16,6 +17,7 @@ export interface MigrateOptions {
1617
newPrefix: string | null
1718
designSystem: DesignSystem
1819
userConfig: Config
20+
configFilePath: string
1921
}
2022

2123
export async function migrateContents(
@@ -33,6 +35,7 @@ export async function migrateContents(
3335
.use(migrateAtLayerUtilities(stylesheet))
3436
.use(migrateMissingLayers())
3537
.use(migrateTailwindDirectives(options))
38+
.use(migrateAtConfig(stylesheet, options))
3639
.process(stylesheet.root, { from: stylesheet.file ?? undefined })
3740
}
3841

packages/@tailwindcss-upgrade/src/template/prepare-config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export async function prepareConfig(
2222
designSystem: DesignSystem
2323
globs: { base: string; pattern: string }[]
2424
userConfig: Config
25+
configFilePath: string
2526

2627
newPrefix: string | null
2728
}> {
@@ -57,7 +58,13 @@ export async function prepareConfig(
5758
__unstable__loadDesignSystem(input, { base: __dirname }),
5859
])
5960

60-
return { designSystem, globs: compiler.globs, userConfig, newPrefix }
61+
return {
62+
designSystem,
63+
globs: compiler.globs,
64+
userConfig,
65+
newPrefix,
66+
configFilePath: fullConfigPath,
67+
}
6168
} catch (e: any) {
6269
error('Could not load the configuration file: ' + e.message)
6370
process.exit(1)

0 commit comments

Comments
 (0)