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 <noreply@anthropic.com>
Co-authored-by: Jordan Pittman <jordan@cryptica.me>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
This commit is contained in:
Benoît Rouleau 2025-10-17 11:00:25 -04:00 committed by GitHub
parent acb27ef9e9
commit 89cbfc7b2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 182 additions and 9 deletions

View File

@ -914,3 +914,112 @@ test(
function firstLine(str: string) {
return str.split('\n')[0]
}
test(
'optimize option: disabled',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^7"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
build: { cssMinify: false },
plugins: [tailwindcss({ optimize: false })],
})
`,
'index.html': html`
<head>
<link rel="stylesheet" href="./src/index.css" />
</head>
<body>
<div class="hover:flex">Hello, world!</div>
</body>
`,
'src/index.css': css`
@reference 'tailwindcss/theme';
@import 'tailwindcss/utilities';
`,
},
},
async ({ exec, expect, fs }) => {
await exec('pnpm vite build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
let [filename] = files[0]
// Should not be minified when optimize is disabled
let content = await fs.read(filename)
expect(content).toContain('.hover\\:flex {')
expect(content).toContain('&:hover {')
expect(content).toContain('@media (hover: hover) {')
expect(content).toContain('display: flex;')
},
)
test(
'optimize option: enabled with minify disabled',
{
fs: {
'package.json': json`
{
"type": "module",
"dependencies": {
"@tailwindcss/vite": "workspace:^",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"vite": "^7"
}
}
`,
'vite.config.ts': ts`
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
build: { cssMinify: false },
plugins: [tailwindcss({ optimize: { minify: false } })],
})
`,
'index.html': html`
<head>
<link rel="stylesheet" href="./src/index.css" />
</head>
<body>
<div class="hover:flex">Hello, world!</div>
</body>
`,
'src/index.css': css`
@reference 'tailwindcss/theme';
@import 'tailwindcss/utilities';
`,
},
},
async ({ exec, expect, fs }) => {
await exec('pnpm vite build')
let files = await fs.glob('dist/**/*.css')
expect(files).toHaveLength(1)
let [filename] = files[0]
// Should be optimized but not minified
let content = await fs.read(filename)
expect(content).toContain('@media (hover: hover) {')
expect(content).toContain('.hover\\:flex:hover {')
expect(content).toContain('display: flex;')
},
)

View File

@ -34,3 +34,43 @@ For help, discussion about best practices, or feature ideas:
## Contributing
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**.
---
## `@tailwindcss/vite` plugin API
### Enabling or disabling Lightning CSS
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.
If you want to always enable or disable Lightning CSS the `optimize` option may be used:
```js
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
tailwindcss({
// Disable Lightning CSS optimization
optimize: false,
}),
],
})
```
It's also possible to keep Lightning CSS enabled but disable minification:
```js
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
tailwindcss({
// Enable Lightning CSS but disable minification
optimize: { minify: false },
}),
],
})
```

View File

@ -18,12 +18,20 @@ const SPECIAL_QUERY_RE = /[?&](?:worker|sharedworker|raw|url)\b/
const COMMON_JS_PROXY_RE = /\?commonjs-proxy/
const INLINE_STYLE_ID_RE = /[?&]index\=\d+\.css$/
export default function tailwindcss(): Plugin[] {
export type PluginOptions = {
/**
* Optimize and minify the output CSS.
*/
optimize?: boolean | { minify?: boolean }
}
export default function tailwindcss(opts: PluginOptions = {}): Plugin[] {
let servers: ViteDevServer[] = []
let config: ResolvedConfig | null = null
let isSSR = false
let minify = false
let shouldOptimize = true
let minify = true
let roots: DefaultMap<string, Root> = new DefaultMap((id) => {
let cssResolver = config!.createResolver({
@ -65,8 +73,22 @@ export default function tailwindcss(): Plugin[] {
async configResolved(_config) {
config = _config
minify = config.build.cssMinify !== false
isSSR = config.build.ssr !== false && config.build.ssr !== undefined
// By default we optimize CSS during the build phase but if the user
// provides explicit options we'll use those instead
if (opts.optimize !== undefined) {
shouldOptimize = opts.optimize !== false
}
// Minification is also performed when optimizing as long as it's also
// enabled in Vite
minify = shouldOptimize && config.build.cssMinify !== false
// But again, the user can override that choice explicitly
if (typeof opts.optimize === 'object') {
minify = opts.optimize.minify !== false
}
},
},
@ -116,12 +138,14 @@ export default function tailwindcss(): Plugin[] {
}
DEBUG && I.end('[@tailwindcss/vite] Generate CSS (build)')
DEBUG && I.start('[@tailwindcss/vite] Optimize CSS')
result = optimize(result.code, {
minify,
map: result.map,
})
DEBUG && I.end('[@tailwindcss/vite] Optimize CSS')
if (shouldOptimize) {
DEBUG && I.start('[@tailwindcss/vite] Optimize CSS')
result = optimize(result.code, {
minify,
map: result.map,
})
DEBUG && I.end('[@tailwindcss/vite] Optimize CSS')
}
return result
},