Skip to content

Commit b17444f

Browse files
authored
feat: add build.cssTarget option (#5132)
fixes #4746 fixes #5070 fixes #4930
1 parent bbb4067 commit b17444f

File tree

8 files changed

+54
-1
lines changed

8 files changed

+54
-1
lines changed

docs/config/index.md

+11
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,17 @@ export default defineConfig({
674674

675675
If disabled, all CSS in the entire project will be extracted into a single CSS file.
676676

677+
### build.cssTarget
678+
679+
- **Type:** `string | string[]`
680+
- **Default:** the same as [`build.target`](/config/#build-target)
681+
682+
This options allows users to set a different browser target for CSS minification from the one used for JavaScript transpilation.
683+
684+
It should only be used when you are targeting a non-mainstream browser.
685+
One example is Android WeChat WebView, which supports most modern JavaScript features but not the [`#RGBA` hexadecimal color notation in CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value#rgb_colors).
686+
In this case, you need to set `build.cssTarget` to `chrome61` to prevent vite from transform `rgba()` colors into `#RGBA` hexadecimal notations.
687+
677688
### build.sourcemap
678689

679690
- **Type:** `boolean | 'inline' | 'hidden'`

packages/playground/css/__tests__/css.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -338,3 +338,14 @@ test('inlined', async () => {
338338
// should not insert css
339339
expect(await getColor('.inlined')).toBe('black')
340340
})
341+
342+
test('minify css', async () => {
343+
if (!isBuild) {
344+
return
345+
}
346+
347+
// should keep the rgba() syntax
348+
const cssFile = findAssetFile(/index\.\w+\.css$/)
349+
expect(cssFile).toMatch('rgba(')
350+
expect(cssFile).not.toMatch('#ffff00b3')
351+
})

packages/playground/css/main.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import './minify.css'
2+
13
import css from './imported.css'
24
text('.imported-css', css)
35

packages/playground/css/minify.css

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.test-minify {
2+
color: rgba(255, 255, 0, 0.7);
3+
}

packages/playground/css/vite.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ const path = require('path')
33
* @type {import('vite').UserConfig}
44
*/
55
module.exports = {
6+
build: {
7+
cssTarget: 'chrome61'
8+
},
69
resolve: {
710
alias: {
811
'@': __dirname

packages/plugin-legacy/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ function viteLegacyPlugin(options = {}) {
8686
if (!config.build) {
8787
config.build = {}
8888
}
89+
90+
if (!config.build.cssTarget) {
91+
// Hint for esbuild that we are targeting legacy browsers when minifying CSS.
92+
// Full CSS compat table available at https://github.com/evanw/esbuild/blob/78e04680228cf989bdd7d471e02bbc2c8d345dc9/internal/compat/css_table.go
93+
// But note that only the `HexRGBA` feature affects the minify outcome.
94+
// HSL & rebeccapurple values will be minified away regardless the target.
95+
// So targeting `chrome61` suffices to fix the compatiblity issue.
96+
config.build.cssTarget = 'chrome61'
97+
}
8998
}
9099
}
91100

packages/vite/src/node/build.ts

+14
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ export interface BuildOptions {
102102
* @default true
103103
*/
104104
cssCodeSplit?: boolean
105+
/**
106+
* An optional separate target for CSS minification.
107+
* As esbuild only supports configuring targets to mainstream
108+
* browsers, users may need this option when they are targeting
109+
* a niche browser that comes with most modern JavaScript features
110+
* but has poor CSS support, e.g. Android WeChat WebView, which
111+
* doesn't support the #RGBA syntax.
112+
*/
113+
cssTarget?: TransformOptions['target'] | false
105114
/**
106115
* If `true`, a separate sourcemap file will be created. If 'inline', the
107116
* sourcemap will be appended to the resulting output file as data URI.
@@ -232,6 +241,7 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions {
232241
assetsDir: 'assets',
233242
assetsInlineLimit: 4096,
234243
cssCodeSplit: !raw?.lib,
244+
cssTarget: false,
235245
sourcemap: false,
236246
rollupOptions: {},
237247
minify: raw?.ssr ? false : 'esbuild',
@@ -275,6 +285,10 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions {
275285
resolved.target = 'es2019'
276286
}
277287

288+
if (!resolved.cssTarget) {
289+
resolved.cssTarget = resolved.target
290+
}
291+
278292
// normalize false string into actual false
279293
if ((resolved.minify as any) === 'false') {
280294
resolved.minify = false

packages/vite/src/node/plugins/css.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -906,7 +906,7 @@ async function minifyCSS(css: string, config: ResolvedConfig) {
906906
const { code, warnings } = await transform(css, {
907907
loader: 'css',
908908
minify: true,
909-
target: config.build.target || undefined
909+
target: config.build.cssTarget || undefined
910910
})
911911
if (warnings.length) {
912912
const msgs = await formatMessages(warnings, { kind: 'warning' })

0 commit comments

Comments
 (0)