Skip to content

Commit 52012d9

Browse files
thecrypticacephilipp-spiessadamwathanRobinMalfait
authored
Support loading config files via @config (#14239)
In Tailwind v4 the CSS file is the main entry point to your project and is generally configured via `@theme`. However, given that all v3 projects were configured via a `tailwind.config.js` file we definitely need to support those. This PR adds support for loading existing Tailwind config files by adding an `@config` directive to the CSS — similar to how v3 supported multiple config files except that this is now _required_ to use a config file. You can load a config file like so: ``` @import "tailwindcss"; @config "./path/to/tailwind.config.js"; ``` A few notes: - Both CommonJS and ESM config files are supported (loaded directly via `import()` in Node) - This is not yet supported in Intellisense or Prettier — should hopefully land next week - TypeScript is **not yet** supported in the config file — this will be handled in a future PR. --------- Co-authored-by: Philipp Spiess <[email protected]> Co-authored-by: Adam Wathan <[email protected]> Co-authored-by: Robin Malfait <[email protected]>
1 parent de3c696 commit 52012d9

32 files changed

+1887
-139
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- Add new standalone builds of Tailwind CSS v4 ([#14270](https://github.com/tailwindlabs/tailwindcss/pull/14270))
13+
- Support JavaScript configuration files using `@config` ([#14239](https://github.com/tailwindlabs/tailwindcss/pull/14239))
1314

1415
### Fixed
1516

integrations/cli/config.test.ts

+191
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
import { candidate, css, html, js, json, test } from '../utils'
2+
3+
test(
4+
'Config files (CJS)',
5+
{
6+
fs: {
7+
'package.json': json`
8+
{
9+
"dependencies": {
10+
"tailwindcss": "workspace:^",
11+
"@tailwindcss/cli": "workspace:^"
12+
}
13+
}
14+
`,
15+
'index.html': html`
16+
<div class="text-primary"></div>
17+
`,
18+
'tailwind.config.js': js`
19+
module.exports = {
20+
theme: {
21+
extend: {
22+
colors: {
23+
primary: 'blue',
24+
},
25+
},
26+
},
27+
}
28+
`,
29+
'src/index.css': css`
30+
@import 'tailwindcss';
31+
@config '../tailwind.config.js';
32+
`,
33+
},
34+
},
35+
async ({ fs, exec }) => {
36+
await exec('pnpm tailwindcss --input src/index.css --output dist/out.css')
37+
38+
await fs.expectFileToContain('dist/out.css', [
39+
//
40+
candidate`text-primary`,
41+
])
42+
},
43+
)
44+
45+
test(
46+
'Config files (ESM)',
47+
{
48+
fs: {
49+
'package.json': json`
50+
{
51+
"dependencies": {
52+
"tailwindcss": "workspace:^",
53+
"@tailwindcss/cli": "workspace:^"
54+
}
55+
}
56+
`,
57+
'index.html': html`
58+
<div class="text-primary"></div>
59+
`,
60+
'tailwind.config.mjs': js`
61+
export default {
62+
theme: {
63+
extend: {
64+
colors: {
65+
primary: 'blue',
66+
},
67+
},
68+
},
69+
}
70+
`,
71+
'src/index.css': css`
72+
@import 'tailwindcss';
73+
@config '../tailwind.config.mjs';
74+
`,
75+
},
76+
},
77+
async ({ fs, exec }) => {
78+
await exec('pnpm tailwindcss --input src/index.css --output dist/out.css')
79+
80+
await fs.expectFileToContain('dist/out.css', [
81+
//
82+
candidate`text-primary`,
83+
])
84+
},
85+
)
86+
87+
test(
88+
'Config files (CJS, watch mode)',
89+
{
90+
fs: {
91+
'package.json': json`
92+
{
93+
"dependencies": {
94+
"tailwindcss": "workspace:^",
95+
"@tailwindcss/cli": "workspace:^"
96+
}
97+
}
98+
`,
99+
'index.html': html`
100+
<div class="text-primary"></div>
101+
`,
102+
'tailwind.config.js': js`
103+
const myColor = require('./my-color')
104+
module.exports = {
105+
theme: {
106+
extend: {
107+
colors: {
108+
primary: myColor,
109+
},
110+
},
111+
},
112+
}
113+
`,
114+
'my-color.js': js`module.exports = 'blue'`,
115+
'src/index.css': css`
116+
@import 'tailwindcss';
117+
@config '../tailwind.config.js';
118+
`,
119+
},
120+
},
121+
async ({ fs, spawn }) => {
122+
await spawn('pnpm tailwindcss --input src/index.css --output dist/out.css --watch')
123+
124+
await fs.expectFileToContain('dist/out.css', [
125+
//
126+
candidate`text-primary`,
127+
'color: blue',
128+
])
129+
130+
await fs.write('my-color.js', js`module.exports = 'red'`)
131+
132+
await fs.expectFileToContain('dist/out.css', [
133+
//
134+
candidate`text-primary`,
135+
'color: red',
136+
])
137+
},
138+
)
139+
140+
test(
141+
'Config files (MJS, watch mode)',
142+
{
143+
fs: {
144+
'package.json': json`
145+
{
146+
"dependencies": {
147+
"tailwindcss": "workspace:^",
148+
"@tailwindcss/cli": "workspace:^"
149+
}
150+
}
151+
`,
152+
'index.html': html`
153+
<div class="text-primary"></div>
154+
`,
155+
'tailwind.config.mjs': js`
156+
import myColor from './my-color.mjs'
157+
export default {
158+
theme: {
159+
extend: {
160+
colors: {
161+
primary: myColor,
162+
},
163+
},
164+
},
165+
}
166+
`,
167+
'my-color.mjs': js`export default 'blue'`,
168+
'src/index.css': css`
169+
@import 'tailwindcss';
170+
@config '../tailwind.config.mjs';
171+
`,
172+
},
173+
},
174+
async ({ fs, spawn }) => {
175+
await spawn('pnpm tailwindcss --input src/index.css --output dist/out.css --watch')
176+
177+
await fs.expectFileToContain('dist/out.css', [
178+
//
179+
candidate`text-primary`,
180+
'color: blue',
181+
])
182+
183+
await fs.write('my-color.mjs', js`export default 'red'`)
184+
185+
await fs.expectFileToContain('dist/out.css', [
186+
//
187+
candidate`text-primary`,
188+
'color: red',
189+
])
190+
},
191+
)

0 commit comments

Comments
 (0)