Skip to content

Commit 89cbfc7

Browse files
benfaceclaudethecrypticaceRobinMalfait
authored
Add optimize option to @tailwindcss/vite plugin (#19131)
Adds an `optimize` option to the Vite plugin that matches the API and behavior of the PostCSS plugin. Supports three formats: - `optimize: false` - disable optimization - `optimize: true` - enable optimization with minification - `optimize: { minify: false }` - enable optimization without minification 🤖 Generated with [Claude Code](https://claude.ai/code) --------- Co-authored-by: Claude <[email protected]> Co-authored-by: Jordan Pittman <[email protected]> Co-authored-by: Robin Malfait <[email protected]>
1 parent acb27ef commit 89cbfc7

File tree

3 files changed

+182
-9
lines changed

3 files changed

+182
-9
lines changed

integrations/vite/index.test.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,3 +914,112 @@ test(
914914
function firstLine(str: string) {
915915
return str.split('\n')[0]
916916
}
917+
918+
test(
919+
'optimize option: disabled',
920+
{
921+
fs: {
922+
'package.json': json`
923+
{
924+
"type": "module",
925+
"dependencies": {
926+
"@tailwindcss/vite": "workspace:^",
927+
"tailwindcss": "workspace:^"
928+
},
929+
"devDependencies": {
930+
"vite": "^7"
931+
}
932+
}
933+
`,
934+
'vite.config.ts': ts`
935+
import tailwindcss from '@tailwindcss/vite'
936+
import { defineConfig } from 'vite'
937+
938+
export default defineConfig({
939+
build: { cssMinify: false },
940+
plugins: [tailwindcss({ optimize: false })],
941+
})
942+
`,
943+
'index.html': html`
944+
<head>
945+
<link rel="stylesheet" href="./src/index.css" />
946+
</head>
947+
<body>
948+
<div class="hover:flex">Hello, world!</div>
949+
</body>
950+
`,
951+
'src/index.css': css`
952+
@reference 'tailwindcss/theme';
953+
@import 'tailwindcss/utilities';
954+
`,
955+
},
956+
},
957+
async ({ exec, expect, fs }) => {
958+
await exec('pnpm vite build')
959+
960+
let files = await fs.glob('dist/**/*.css')
961+
expect(files).toHaveLength(1)
962+
let [filename] = files[0]
963+
964+
// Should not be minified when optimize is disabled
965+
let content = await fs.read(filename)
966+
expect(content).toContain('.hover\\:flex {')
967+
expect(content).toContain('&:hover {')
968+
expect(content).toContain('@media (hover: hover) {')
969+
expect(content).toContain('display: flex;')
970+
},
971+
)
972+
973+
test(
974+
'optimize option: enabled with minify disabled',
975+
{
976+
fs: {
977+
'package.json': json`
978+
{
979+
"type": "module",
980+
"dependencies": {
981+
"@tailwindcss/vite": "workspace:^",
982+
"tailwindcss": "workspace:^"
983+
},
984+
"devDependencies": {
985+
"vite": "^7"
986+
}
987+
}
988+
`,
989+
'vite.config.ts': ts`
990+
import tailwindcss from '@tailwindcss/vite'
991+
import { defineConfig } from 'vite'
992+
993+
export default defineConfig({
994+
build: { cssMinify: false },
995+
plugins: [tailwindcss({ optimize: { minify: false } })],
996+
})
997+
`,
998+
'index.html': html`
999+
<head>
1000+
<link rel="stylesheet" href="./src/index.css" />
1001+
</head>
1002+
<body>
1003+
<div class="hover:flex">Hello, world!</div>
1004+
</body>
1005+
`,
1006+
'src/index.css': css`
1007+
@reference 'tailwindcss/theme';
1008+
@import 'tailwindcss/utilities';
1009+
`,
1010+
},
1011+
},
1012+
async ({ exec, expect, fs }) => {
1013+
await exec('pnpm vite build')
1014+
1015+
let files = await fs.glob('dist/**/*.css')
1016+
expect(files).toHaveLength(1)
1017+
let [filename] = files[0]
1018+
1019+
// Should be optimized but not minified
1020+
let content = await fs.read(filename)
1021+
expect(content).toContain('@media (hover: hover) {')
1022+
expect(content).toContain('.hover\\:flex:hover {')
1023+
expect(content).toContain('display: flex;')
1024+
},
1025+
)

packages/@tailwindcss-vite/README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,43 @@ For help, discussion about best practices, or feature ideas:
3434
## Contributing
3535

3636
If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**.
37+
38+
---
39+
40+
## `@tailwindcss/vite` plugin API
41+
42+
### Enabling or disabling Lightning CSS
43+
44+
By default, this plugin detects whether or not the CSS is being built for production by checking the `NODE_ENV` environment variable. When building for production Lightning CSS will be enabled otherwise it is disabled.
45+
46+
If you want to always enable or disable Lightning CSS the `optimize` option may be used:
47+
48+
```js
49+
import tailwindcss from '@tailwindcss/vite'
50+
import { defineConfig } from 'vite'
51+
52+
export default defineConfig({
53+
plugins: [
54+
tailwindcss({
55+
// Disable Lightning CSS optimization
56+
optimize: false,
57+
}),
58+
],
59+
})
60+
```
61+
62+
It's also possible to keep Lightning CSS enabled but disable minification:
63+
64+
```js
65+
import tailwindcss from '@tailwindcss/vite'
66+
import { defineConfig } from 'vite'
67+
68+
export default defineConfig({
69+
plugins: [
70+
tailwindcss({
71+
// Enable Lightning CSS but disable minification
72+
optimize: { minify: false },
73+
}),
74+
],
75+
})
76+
```

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

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,20 @@ const SPECIAL_QUERY_RE = /[?&](?:worker|sharedworker|raw|url)\b/
1818
const COMMON_JS_PROXY_RE = /\?commonjs-proxy/
1919
const INLINE_STYLE_ID_RE = /[?&]index\=\d+\.css$/
2020

21-
export default function tailwindcss(): Plugin[] {
21+
export type PluginOptions = {
22+
/**
23+
* Optimize and minify the output CSS.
24+
*/
25+
optimize?: boolean | { minify?: boolean }
26+
}
27+
28+
export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
2229
let servers: ViteDevServer[] = []
2330
let config: ResolvedConfig | null = null
2431

2532
let isSSR = false
26-
let minify = false
33+
let shouldOptimize = true
34+
let minify = true
2735

2836
let roots: DefaultMap<string, Root> = new DefaultMap((id) => {
2937
let cssResolver = config!.createResolver({
@@ -65,8 +73,22 @@ export default function tailwindcss(): Plugin[] {
6573

6674
async configResolved(_config) {
6775
config = _config
68-
minify = config.build.cssMinify !== false
6976
isSSR = config.build.ssr !== false && config.build.ssr !== undefined
77+
78+
// By default we optimize CSS during the build phase but if the user
79+
// provides explicit options we'll use those instead
80+
if (opts.optimize !== undefined) {
81+
shouldOptimize = opts.optimize !== false
82+
}
83+
84+
// Minification is also performed when optimizing as long as it's also
85+
// enabled in Vite
86+
minify = shouldOptimize && config.build.cssMinify !== false
87+
88+
// But again, the user can override that choice explicitly
89+
if (typeof opts.optimize === 'object') {
90+
minify = opts.optimize.minify !== false
91+
}
7092
},
7193
},
7294

@@ -116,12 +138,14 @@ export default function tailwindcss(): Plugin[] {
116138
}
117139
DEBUG && I.end('[@tailwindcss/vite] Generate CSS (build)')
118140

119-
DEBUG && I.start('[@tailwindcss/vite] Optimize CSS')
120-
result = optimize(result.code, {
121-
minify,
122-
map: result.map,
123-
})
124-
DEBUG && I.end('[@tailwindcss/vite] Optimize CSS')
141+
if (shouldOptimize) {
142+
DEBUG && I.start('[@tailwindcss/vite] Optimize CSS')
143+
result = optimize(result.code, {
144+
minify,
145+
map: result.map,
146+
})
147+
DEBUG && I.end('[@tailwindcss/vite] Optimize CSS')
148+
}
125149

126150
return result
127151
},

0 commit comments

Comments
 (0)