vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.15k stars 6.03k forks source link

currentcolor + oklch() values inside a selector triggers error when Vite builds with LightningCSS #17900

Open ghost opened 3 weeks ago

ghost commented 3 weeks ago

Describe the bug

Previously, an issue was reported in Vite and in LightningCSS repositories about: LightningCSS not recognizing a combination of oklch and currentColor inside a selector.

That issue has been solved by LightningCSS and released in version 1.25.

[!TIP] Observe that issue in LightningCSS Playground. Select version <=1.24 in the sidebar (to see the Error message), and select version >=1.25 in the sidebar (to see No Error message anymore).

Since Vite 5.2.12, LightningCSS has been updated to version 1.25.

We expected that issue to be solved, however today it still happens in Vite.

Reproduction

https://stackblitz.com/edit/vitest-dev-vitest-k4wy6a

Steps to reproduce

Run npm run vite:build. You should see this error in the console:

vite v5.4.1 building for production...

watching for file changes...

build started...
transforming (1) index.jsthread '<unnamed>' panicked at src/properties/box_shadow.rs:228:43:
called `Result::unwrap()` on an `Err` value: ()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: script "vite:build" was terminated by signal SIGABRT (Abort)
Aborted

There are 2 scenarios in which this error does not happen. Observe them below:

Scenario 1 - comment the problematic selector

Comment the selector .baby-currentcolor-and-oklch in src/babies.css file:

/* .baby-currentcolor-and-oklch {
  box-shadow: oklch(100% 0 0deg / 50%) 0 0.6rem 0.9rem -0.1rem,
    currentColor 0 -0.4rem -0.8rem -0.5rem,
    oklch(100% 0 360deg / 100%) 0 0 0.4rem inset;
} */

Run npm run vite:build You should not see the error anymore in the console.

Scenario 2 - write css.ligtningcss.target in Vite config

In the vite.config.js file, uncomment the line 20, from this:

css: {
  lightningcss: {
    // targets: browserslistToTargets(['since 2022'])

to this:

css: {
  lightningcss: {
    targets: browserslistToTargets(['since 2022'])

Run npm run vite:build You should not see the error anymore in the console.

[!NOTE] It should not have been necessary to write css.lightningcss.targets, because build.cssTarget was already set in Vite config! This is another bug. It was already reported in Vite repository. The cause of this another bug apparently is: LightningCSS expects an array of strings instead of string, and each string should be written in the format provided by Browserslist instead of 'es2022'.

System Info

System:
    OS: Linux

Logs

Click to expand ```shell vite:config bundled config file loaded in 46.14ms +0ms vite:config using resolved config: { vite:config build: { vite:config target: 'es2022', vite:config cssTarget: [ 'since 2022' ], vite:config outDir: 'dist', vite:config assetsDir: 'assets', vite:config assetsInlineLimit: 4096, vite:config cssCodeSplit: true, vite:config sourcemap: false, vite:config rollupOptions: { input: [Object] }, vite:config minify: 'esbuild', vite:config terserOptions: {}, vite:config write: true, vite:config emptyOutDir: true, vite:config copyPublicDir: true, vite:config manifest: false, vite:config lib: false, vite:config ssr: false, vite:config ssrManifest: false, vite:config ssrEmitAssets: false, vite:config reportCompressedSize: true, vite:config chunkSizeWarningLimit: 500, vite:config watch: { exclude: 'dist/**' }, vite:config cssMinify: 'lightningcss', vite:config commonjsOptions: { include: [Array], extensions: [Array] }, vite:config dynamicImportVarsOptions: { warnOnError: true, exclude: [Array] }, vite:config modulePreload: { polyfill: true } vite:config }, vite:config css: { lightningcss: { targets: [Object] }, transformer: 'lightningcss' }, vite:config configFile: '//babies/vite.config.js', vite:config configFileDependencies: [ vite:config '//babies/src/myConfig.js', vite:config '//babies/vite.config.js' vite:config ], vite:config inlineConfig: { vite:config root: undefined, vite:config base: undefined, vite:config mode: undefined, vite:config configFile: undefined, vite:config logLevel: undefined, vite:config clearScreen: undefined, vite:config build: {} vite:config }, vite:config root: '//babies', vite:config base: '/', vite:config decodedBase: '/', vite:config rawBase: '/', vite:config resolve: { vite:config mainFields: [ 'browser', 'module', 'jsnext:main', 'jsnext' ], vite:config conditions: [], vite:config extensions: [ vite:config '.mjs', '.js', vite:config '.mts', '.ts', vite:config '.jsx', '.tsx', vite:config '.json' vite:config ], vite:config dedupe: [], vite:config preserveSymlinks: false, vite:config alias: [ [Object], [Object] ] vite:config }, vite:config publicDir: '//babies/public', vite:config cacheDir: '//babies/node_modules/.vite', vite:config command: 'build', vite:config mode: 'production', vite:config ssr: { vite:config target: 'node', vite:config optimizeDeps: { noDiscovery: true, esbuildOptions: [Object] } vite:config }, vite:config isWorker: false, vite:config mainConfig: null, vite:config bundleChain: [], vite:config isProduction: true, vite:config plugins: [ vite:config 'vite:build-metadata', vite:config 'vite:watch-package-data', vite:config 'vite:pre-alias', vite:config 'alias', vite:config 'vite:modulepreload-polyfill', vite:config 'vite:resolve', vite:config 'vite:html-inline-proxy', vite:config 'vite:css', vite:config 'vite:esbuild', vite:config 'vite:json', vite:config 'vite:wasm-helper', vite:config 'vite:worker', vite:config 'vite:asset', vite:config 'vite:wasm-fallback', vite:config 'vite:define', vite:config 'vite:css-post', vite:config 'vite:build-html', vite:config 'vite:worker-import-meta-url', vite:config 'vite:asset-import-meta-url', vite:config 'vite:force-systemjs-wrap-complete', vite:config 'commonjs', vite:config 'vite:data-uri', vite:config 'vite:dynamic-import-vars', vite:config 'vite:import-glob', vite:config 'vite:build-import-analysis', vite:config 'vite:esbuild-transpile', vite:config 'vite:terser', vite:config 'vite:reporter', vite:config 'vite:load-fallback' vite:config ], vite:config esbuild: { jsxDev: false }, vite:config server: { vite:config preTransformRequests: true, vite:config sourcemapIgnoreList: [Function: isInNodeModules$1], vite:config middlewareMode: false, vite:config fs: { vite:config strict: true, vite:config allow: [Array], vite:config deny: [Array], vite:config cachedChecks: undefined vite:config } vite:config }, vite:config preview: { vite:config port: undefined, vite:config strictPort: undefined, vite:config host: undefined, vite:config https: undefined, vite:config open: undefined, vite:config proxy: undefined, vite:config cors: undefined, vite:config headers: undefined vite:config }, vite:config envDir: '//babies', vite:config env: { BASE_URL: '/', MODE: 'production', DEV: false, PROD: true }, vite:config assetsInclude: [Function: assetsInclude], vite:config logger: { vite:config hasWarned: false, vite:config info: [Function: info], vite:config warn: [Function: warn], vite:config warnOnce: [Function: warnOnce], vite:config error: [Function: error], vite:config clearScreen: [Function: clearScreen], vite:config hasErrorLogged: [Function: hasErrorLogged] vite:config }, vite:config packageCache: Map(1) { vite:config 'fnpd_//babies' => { vite:config dir: '//babies', vite:config data: [Object], vite:config hasSideEffects: [Function: hasSideEffects], vite:config webResolvedImports: {}, vite:config nodeResolvedImports: {}, vite:config setResolvedCache: [Function: setResolvedCache], vite:config getResolvedCache: [Function: getResolvedCache] vite:config }, vite:config set: [Function (anonymous)] vite:config }, vite:config createResolver: [Function: createResolver], vite:config optimizeDeps: { vite:config holdUntilCrawlEnd: true, vite:config esbuildOptions: { preserveSymlinks: false } vite:config }, vite:config worker: { format: 'iife', plugins: '() => plugins', rollupOptions: {} }, vite:config appType: 'spa', vite:config experimental: { importGlobRestoreExtension: false, hmrPartialAccept: false }, vite:config getSortedPlugins: [Function: getSortedPlugins], vite:config getSortedPluginHooks: [Function: getSortedPluginHooks] vite:config } +23ms vite v5.4.1 building for production... watching for file changes... build started... transforming (1) index.jsthread '' panicked at src/properties/box_shadow.rs:228:43: called `Result::unwrap()` on an `Err` value: () note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: Failed to run "vite" due to signal SIGABRT Aborted ```
stackblitz[bot] commented 3 weeks ago

Fix this issue in StackBlitz Codeflow Start a new pull request in StackBlitz Codeflow.

hi-ogawa commented 3 weeks ago

Scenario 2 - write css.ligtningcss.target in Vite config

It should not have been necessary to write css.lightningcss.targets, because build.cssTarget was already set in Vite config!

This may be a gray area, but it's probably working as intended since built.cssTarget is a configuration for build.cssMinify. As in the documentation, css.lightningcss.targets should influence built.cssTarget when build.cssMinify: "lightningcss", but not the other way around.


Other than this, I think there is still an issue on lightningcss side. The error happens when Vite uses default targets from

https://github.com/vitejs/vite/blob/83355a6529092b3a576e2c24bbd8f9097f7ef569/packages/vite/src/node/plugins/css.ts#L180-L182

https://github.com/vitejs/vite/blob/83355a6529092b3a576e2c24bbd8f9097f7ef569/packages/vite/src/node/constants.ts#L21-L27

and this can be reproduced on their playground with safari14: lightningcss playground

hi-ogawa commented 3 weeks ago

Whatever may happen, I am going to appreciate when the documentation becomes more clear about LightningCSS being incompatible to build.cssTarget today, with a note to redirect people to css.lightningcss.targets. It took me some time to discover this internal functioning when debugging.

@mrredtree I agree build.cssTarget is confusing now. Like you said, as a short term solution, it make sense to update the documentation and jsdoc. Please feel free to send a PR if you like.