From 8dc94b0f2cef69e4e9181c98c13caac363b5a349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Sat, 6 May 2023 23:33:50 +0200 Subject: [PATCH 1/8] feat(css): add support for Lightning CSS --- .eslintrc.cjs | 6 +- packages/vite/api-extractor.json | 2 + packages/vite/package.json | 7 +- packages/vite/rollup.config.ts | 1 + packages/vite/scripts/api-extractor.ts | 28 ++ .../src/node/__tests__/plugins/css.spec.ts | 23 +- packages/vite/src/node/build.ts | 43 ++- packages/vite/src/node/config.ts | 25 +- packages/vite/src/node/index.ts | 7 + packages/vite/src/node/plugins/css.ts | 294 +++++++++++++++++- packages/vite/src/node/plugins/html.ts | 5 +- packages/vite/src/types/lightningcss.d.ts | 10 + .../__tests__/lightningcss.spec.ts | 67 ++++ .../css-lightningcss/composed.module.css | 3 + .../composes-path-resolving.module.css | 3 + .../css-lightningcss/imported-at-import.css | 3 + playground/css-lightningcss/imported.css | 12 + playground/css-lightningcss/index.html | 28 ++ playground/css-lightningcss/inline.module.css | 3 + playground/css-lightningcss/inlined.css | 4 + .../css-lightningcss/linked-at-import.css | 3 + playground/css-lightningcss/linked.css | 8 + playground/css-lightningcss/main.js | 31 ++ playground/css-lightningcss/minify.css | 3 + playground/css-lightningcss/mod.module.css | 3 + playground/css-lightningcss/ok.png | Bin 0 -> 4986 bytes playground/css-lightningcss/package.json | 14 + playground/css-lightningcss/vite.config.js | 12 + pnpm-lock.yaml | 103 ++++++ 29 files changed, 726 insertions(+), 25 deletions(-) create mode 100644 packages/vite/scripts/api-extractor.ts create mode 100644 packages/vite/src/types/lightningcss.d.ts create mode 100644 playground/css-lightningcss/__tests__/lightningcss.spec.ts create mode 100644 playground/css-lightningcss/composed.module.css create mode 100644 playground/css-lightningcss/composes-path-resolving.module.css create mode 100644 playground/css-lightningcss/imported-at-import.css create mode 100644 playground/css-lightningcss/imported.css create mode 100644 playground/css-lightningcss/index.html create mode 100644 playground/css-lightningcss/inline.module.css create mode 100644 playground/css-lightningcss/inlined.css create mode 100644 playground/css-lightningcss/linked-at-import.css create mode 100644 playground/css-lightningcss/linked.css create mode 100644 playground/css-lightningcss/main.js create mode 100644 playground/css-lightningcss/minify.css create mode 100644 playground/css-lightningcss/mod.module.css create mode 100644 playground/css-lightningcss/ok.png create mode 100644 playground/css-lightningcss/package.json create mode 100644 playground/css-lightningcss/vite.config.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 948041496208bb..569431b09dbaba 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -135,7 +135,11 @@ module.exports = defineConfig({ }, }, { - files: ['packages/vite/src/types/**', '*.spec.ts'], + files: [ + 'packages/vite/src/types/**', + 'packages/vite/scripts/**', + '*.spec.ts', + ], rules: { 'n/no-extraneous-import': 'off', }, diff --git a/packages/vite/api-extractor.json b/packages/vite/api-extractor.json index 0b5b4178c2bd90..642cef99fecd59 100644 --- a/packages/vite/api-extractor.json +++ b/packages/vite/api-extractor.json @@ -5,6 +5,8 @@ "mainEntryPointFilePath": "./temp/node/index.d.ts", + "bundledPackages": ["lightningcss"], + "dtsRollup": { "enabled": true, "untrimmedFilePath": "", diff --git a/packages/vite/package.json b/packages/vite/package.json index 7ce565f9e29505..8ce79856748b02 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -56,7 +56,7 @@ "build-types": "run-s build-types-temp build-types-pre-patch build-types-roll build-types-post-patch build-types-check", "build-types-temp": "tsc --emitDeclarationOnly --outDir temp/node -p src/node", "build-types-pre-patch": "tsx scripts/prePatchTypes.ts", - "build-types-roll": "api-extractor run && rimraf temp", + "build-types-roll": "tsx scripts/api-extractor.ts run && rimraf temp", "build-types-post-patch": "tsx scripts/postPatchTypes.ts", "build-types-check": "tsx scripts/checkBuiltTypes.ts && tsc --project tsconfig.check.json", "typecheck": "tsc --noEmit", @@ -108,6 +108,7 @@ "http-proxy": "^1.18.1", "json-stable-stringify": "^1.0.2", "launch-editor-middleware": "^2.6.0", + "lightningcss": "^1.20.0", "magic-string": "^0.30.0", "micromatch": "^4.0.5", "mlly": "^1.3.0", @@ -139,6 +140,7 @@ "sass": "*", "stylus": "*", "sugarss": "*", + "lightningcss": "^1.20.0", "terser": "^5.4.0" }, "peerDependenciesMeta": { @@ -157,6 +159,9 @@ "sugarss": { "optional": true }, + "lightningcss": { + "optional": true + }, "terser": { "optional": true } diff --git a/packages/vite/rollup.config.ts b/packages/vite/rollup.config.ts index 7a1064778ae9f8..ebfe0fcacb4cc0 100644 --- a/packages/vite/rollup.config.ts +++ b/packages/vite/rollup.config.ts @@ -160,6 +160,7 @@ function createNodeConfig(isProduction: boolean) { }, external: [ 'fsevents', + 'lightningcss', ...Object.keys(pkg.dependencies), ...(isProduction ? [] : Object.keys(pkg.devDependencies)), ], diff --git a/packages/vite/scripts/api-extractor.ts b/packages/vite/scripts/api-extractor.ts new file mode 100644 index 00000000000000..773b5e195c2e52 --- /dev/null +++ b/packages/vite/scripts/api-extractor.ts @@ -0,0 +1,28 @@ +import { Extractor, ExtractorConfig } from '@microsoft/api-extractor' + +const result = Extractor.invoke( + ExtractorConfig.loadFileAndPrepare('./api-extractor.json'), + { + messageCallback: (message) => { + const ignore = () => { + // @ts-expect-error TS requires to use the const enum, which is not available as the named export in tsx + message.logLevel = 'none' + } + if ( + message.sourceFilePath?.includes('lightningcss') && + message.messageId === 'tsdoc-characters-after-block-tag' + ) { + ignore() + } + if (message.messageId === 'ae-forgotten-export') { + if (message.sourceFilePath?.endsWith('/src/types/lightningcss.d.ts')) { + // We only expose LightningCSS types via prefixed types to avoid + // having confusing name like "Targets" in Vite types + ignore() + } + } + }, + }, +) + +if (!result.succeeded) process.exit(1) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index fcf42f91667865..cccdda396f8df6 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -3,7 +3,12 @@ import path from 'node:path' import { describe, expect, test, vi } from 'vitest' import { resolveConfig } from '../../config' import type { InlineConfig } from '../../config' -import { cssPlugin, cssUrlRE, hoistAtRules } from '../../plugins/css' +import { + convertTargets, + cssPlugin, + cssUrlRE, + hoistAtRules, +} from '../../plugins/css' describe('search css url function', () => { test('some spaces before it', () => { @@ -237,3 +242,19 @@ async function createCssPluginTransform( }, } } + +describe('convertTargets', () => { + test('basic cases', () => { + expect(convertTargets('es2018')).toStrictEqual({ + chrome: 4128768, + edge: 5177344, + firefox: 3801088, + safari: 786432, + opera: 3276800, + }) + expect(convertTargets(['safari13.1', 'ios13', 'node14'])).toStrictEqual({ + ios_saf: 851968, + safari: 852224, + }) + }) +}) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 354d603f3d124c..aea9fdb922ec46 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -20,6 +20,10 @@ import type { import type { Terser } from 'dep-types/terser' import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'dep-types/commonjs' +import type { + LightningCSSDrafts, + LightningCSSTargets, +} from 'dep-types/lightningcss' import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' import type { TransformOptions } from 'esbuild' import type { InlineConfig, ResolvedConfig } from './config' @@ -59,6 +63,7 @@ import { resolveChokidarOptions } from './watch' import { completeSystemWrapPlugin } from './plugins/completeSystemWrap' import { mergeConfig } from './publicUtils' import { webWorkerPostPlugin } from './plugins/worker' +import { convertTargets } from './plugins/css' export interface BuildOptions { /** @@ -133,6 +138,20 @@ export interface BuildOptions { * @default minify */ cssMinify?: boolean + /** + * @experimental + * Use Lightning CSS to minify CSS. This should be installed as a peer + * dependency. Targets is automatically converted from esbuild (css)target, but + * can be provided for more granular control. + * @default esbuild + */ + cssMinifier?: + | { minifier: 'esbuild' } + | { + minifier: 'LightningCSS' + targets?: LightningCSSTargets + drafts?: LightningCSSDrafts + } /** * If `true`, a separate sourcemap file will be created. If 'inline', the * sourcemap will be appended to the resulting output file as data URI. @@ -298,8 +317,17 @@ export type ResolveModulePreloadDependenciesFn = ( ) => string[] export interface ResolvedBuildOptions - extends Required> { + extends Required< + Omit + > { modulePreload: false | ResolvedModulePreloadOptions + cssMinifier: + | { minifier: 'esbuild' } + | { + minifier: 'LightningCSS' + targets: LightningCSSTargets + drafts: LightningCSSDrafts + } } export function resolveBuildOptions( @@ -419,6 +447,19 @@ export function resolveBuildOptions( resolved.cssMinify = !!resolved.minify } + if (!resolved.cssMinifier) { + resolved.cssMinifier = { minifier: 'esbuild' } + } + + if (resolved.cssMinifier.minifier === 'LightningCSS') { + if (!resolved.cssMinifier.targets) { + resolved.cssMinifier.targets = convertTargets(resolved.cssTarget) + } + if (!resolved.cssMinifier.drafts) { + resolved.cssMinifier.drafts = {} + } + } + return resolved } diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 0823fa51e7d6f2..a9c00f78697fac 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -21,7 +21,12 @@ import type { ResolvedServerOptions, ServerOptions } from './server' import { resolveServerOptions } from './server' import type { PreviewOptions, ResolvedPreviewOptions } from './preview' import { resolvePreviewOptions } from './preview' -import type { CSSOptions } from './plugins/css' +import { + type CSSOptions, + type LightningCSSOptions, + type ResolvedLightningCSSOptions, + resolveCSSOptions, +} from './plugins/css' import { asyncFlatten, createDebugger, @@ -167,9 +172,16 @@ export interface UserConfig { */ resolve?: ResolveOptions & { alias?: AliasOptions } /** - * CSS related options (preprocessors and CSS modules) + * CSS related options + * - CSSOptions is the default and provide configuration for PostCSS and + * various preprocessors + * - LightningCSSOptions is an experimental option to handle CSS modules, + * assets and imports via Lightning CSS. It requires to install it + * as a peer dependency. This is incompatible with the use of preprocessors. + * + * See build options to configure CSS minification. */ - css?: CSSOptions + css?: CSSOptions | LightningCSSOptions /** * JSON loading options */ @@ -326,7 +338,10 @@ export interface InlineConfig extends UserConfig { } export type ResolvedConfig = Readonly< - Omit & { + Omit< + UserConfig, + 'plugins' | 'css' | 'assetsInclude' | 'optimizeDeps' | 'worker' + > & { configFile: string | undefined configFileDependencies: string[] inlineConfig: InlineConfig @@ -349,6 +364,7 @@ export type ResolvedConfig = Readonly< alias: Alias[] } plugins: readonly Plugin[] + css: CSSOptions | ResolvedLightningCSSOptions | undefined esbuild: ESBuildOptions | false server: ResolvedServerOptions build: ResolvedBuildOptions @@ -672,6 +688,7 @@ export async function resolveConfig( mainConfig: null, isProduction, plugins: userPlugins, + css: resolveCSSOptions(config.css, resolvedBuildOptions), esbuild: config.esbuild === false ? false diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index cc44fe17b10524..a8caa3b7012ad0 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -76,6 +76,8 @@ export type { CSSOptions, CSSModulesOptions, PreprocessCSSResult, + LightningCSSOptions, + ResolvedLightningCSSOptions, } from './plugins/css' export type { JsonOptions } from './plugins/json' export type { TransformOptions as EsbuildTransformOptions } from 'esbuild' @@ -143,3 +145,8 @@ export type { Terser } from 'dep-types/terser' export type { RollupCommonJSOptions } from 'dep-types/commonjs' export type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' export type { Matcher, AnymatchPattern, AnymatchFn } from 'dep-types/anymatch' +export type { + LightningCSSTargets, + LightningCSSDrafts, + LightningCSSModulesConfig, +} from 'dep-types/lightningcss' diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 7228c2fae781e2..218ebd54b64c66 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -20,12 +20,17 @@ import type Sass from 'sass' import type Stylus from 'stylus' import type Less from 'less' import type { Alias } from 'dep-types/alias' +import type { + LightningCSSDrafts, + LightningCSSModulesConfig, + LightningCSSTargets, +} from 'dep-types/lightningcss' import type { TransformOptions } from 'esbuild' import { formatMessages, transform } from 'esbuild' import type { RawSourceMap } from '@ampproject/remapping' import { getCodeWithSourcemap, injectSourcesContent } from '../server/sourcemap' import type { ModuleNode } from '../server/moduleGraph' -import type { ResolveFn, ViteDevServer } from '../' +import type { ResolveFn, ResolvedBuildOptions, ViteDevServer } from '../' import { resolveUserExternal, toOutputFilePathInCss } from '../build' import { CLIENT_PUBLIC_PATH, @@ -35,6 +40,7 @@ import { import type { ResolvedConfig } from '../config' import type { Plugin } from '../plugin' import { + arraify, arrayEqual, asyncReplace, cleanUrl, @@ -74,6 +80,7 @@ export interface CSSOptions { /** * https://github.com/css-modules/postcss-modules */ + transformer?: 'PostCSS' modules?: CSSModulesOptions | false preprocessorOptions?: Record postcss?: @@ -116,13 +123,57 @@ export interface CSSModulesOptions { ) => string) } +/** + * @experimental + */ +export interface LightningCSSOptions { + transformer: 'LightningCSS' + modules?: LightningCSSModulesConfig + /** + * Use `{ nesting: true }` to enable support for CSS nesting. The implementation + * is following the ongoing specification, so this could contain + * breaking changes in future version of Lightning CSS. + */ + drafts?: LightningCSSDrafts +} + +/** + * @experimental + */ +export interface ResolvedLightningCSSOptions { + transformer: 'LightningCSS' + targets: LightningCSSTargets + modules: LightningCSSModulesConfig | undefined + drafts: LightningCSSDrafts +} + +export function resolveCSSOptions( + options: CSSOptions | LightningCSSOptions | undefined, + resolvedBuildOptions: ResolvedBuildOptions, +): CSSOptions | ResolvedLightningCSSOptions | undefined { + if (options?.transformer === 'LightningCSS') { + return { + transformer: 'LightningCSS', + targets: + resolvedBuildOptions.cssMinifier.minifier === 'LightningCSS' && + resolvedBuildOptions.cssMinifier.targets + ? resolvedBuildOptions.cssMinifier.targets + : convertTargets(resolvedBuildOptions.cssTarget), + modules: options.modules, + drafts: options.drafts ?? {}, + } + } + return options +} + const cssModuleRE = new RegExp(`\\.module${CSS_LANGS_RE.source}`) -const directRequestRE = /(?:\?|&)direct\b/ -const htmlProxyRE = /(?:\?|&)html-proxy\b/ +const directRequestRE = /[?&]direct\b/ +const htmlProxyRE = /[?&]html-proxy\b/ const commonjsProxyRE = /\?commonjs-proxy/ -const inlineRE = /(?:\?|&)inline\b/ -const inlineCSSRE = /(?:\?|&)inline-css\b/ -const usedRE = /(?:\?|&)used\b/ +const inlineRE = /[?&]inline\b/ +const inlineCSSRE = /[?&]inline-css\b/ +const styleAttrRE = /[?&]style-attr\b/ +const usedRE = /[?&]used\b/ const varRE = /^var\(/i const cssBundleName = 'style.css' @@ -190,7 +241,9 @@ export function cssPlugin(config: ResolvedConfig): Plugin { }) // warm up cache for resolved postcss config - resolvePostcssConfig(config) + if (config.css?.transformer !== 'LightningCSS') { + resolvePostcssConfig(config, config.css) + } return { name: 'vite:css', @@ -393,7 +446,10 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { if (config.command === 'serve') { const getContentWithSourcemap = async (content: string) => { - if (config.css?.devSourcemap) { + if ( + config.css?.transformer === 'LightningCSS' || + config.css?.devSourcemap + ) { const sourcemap = this.getCombinedSourcemap() if (sourcemap.mappings && !sourcemap.sourcesContent) { await injectSourcesContent(sourcemap, cleanUrl(id), config.logger) @@ -441,6 +497,9 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { const isHTMLProxy = htmlProxyRE.test(id) const query = parseRequest(id) if (inlineCSS && isHTMLProxy) { + if (styleAttrRE.test(id)) { + css = css.replace(/"/g, '"') + } addToHTMLProxyTransformResult( `${getHash(cleanUrl(id))}_${Number.parseInt(query!.index)}`, css, @@ -815,6 +874,14 @@ const configToAtImportResolvers = new WeakMap< ResolvedConfig, CSSAtImportResolvers >() +function getAtImportResolvers(config: ResolvedConfig) { + let atImportResolvers = configToAtImportResolvers.get(config) + if (!atImportResolvers) { + atImportResolvers = createCSSResolvers(config) + configToAtImportResolvers.set(config, atImportResolvers) + } + return atImportResolvers +} async function compileCSS( id: string, @@ -828,6 +895,10 @@ async function compileCSS( modules?: Record deps?: Set }> { + if (config.css?.transformer === 'LightningCSS') { + return compileLightningCSS(id, code, config, config.css, urlReplacer) + } + const { modules: modulesOptions, preprocessorOptions, @@ -839,7 +910,7 @@ async function compileCSS( const needInlineImport = code.includes('@import') const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code) const lang = id.match(CSS_LANGS_RE)?.[1] as CssLang | undefined - const postcssConfig = await resolvePostcssConfig(config) + const postcssConfig = await resolvePostcssConfig(config, config.css) // 1. plain css that needs no processing if ( @@ -856,11 +927,7 @@ async function compileCSS( let modules: Record | undefined const deps = new Set() - let atImportResolvers = configToAtImportResolvers.get(config)! - if (!atImportResolvers) { - atImportResolvers = createCSSResolvers(config) - configToAtImportResolvers.set(config, atImportResolvers) - } + const atImportResolvers = getAtImportResolvers(config) // 2. pre-processors: sass etc. if (isPreProcessor(lang)) { @@ -1206,6 +1273,7 @@ interface PostCSSConfigResult { async function resolvePostcssConfig( config: ResolvedConfig, + cssConfig: CSSOptions | undefined, ): Promise { let result = postcssConfigCache.get(config) if (result !== undefined) { @@ -1213,7 +1281,7 @@ async function resolvePostcssConfig( } // inline postcss config via vite config - const inlineOptions = config.css?.postcss + const inlineOptions = cssConfig?.postcss if (isObject(inlineOptions)) { const options = { ...inlineOptions } @@ -1414,6 +1482,25 @@ async function doImportCSSReplace( } async function minifyCSS(css: string, config: ResolvedConfig) { + if (config.build.cssMinifier?.minifier === 'LightningCSS') { + const { code, warnings } = (await importLightningCSS()).transform({ + filename: cssBundleName, + code: Buffer.from(css), + targets: config.build.cssMinifier.targets, + drafts: config.build.cssMinifier.drafts, + minify: true, + }) + if (warnings.length) { + config.logger.warn( + colors.yellow( + `warnings when minifying css:\n${warnings + .map((w) => w.message) + .join('\n')}`, + ), + ) + } + return code.toString() + } try { const { code, warnings } = await transform(css, { loader: 'css', @@ -2042,3 +2129,180 @@ const preProcessors = Object.freeze({ function isPreProcessor(lang: any): lang is PreprocessLang { return lang && lang in preProcessors } + +const importLightningCSS = createCachedImport(() => import('lightningcss')) + +async function compileLightningCSS( + id: string, + src: string, + config: ResolvedConfig, + cssConfig: ResolvedLightningCSSOptions, + urlReplacer?: CssUrlReplacer, +): ReturnType { + const deps = new Set() + // Relative path is needed to get stable hash when using CSS modules + const filename = cleanUrl(path.relative(config.root, id)) + const toAbsolute = (filePath: string) => + path.isAbsolute(filePath) ? filePath : path.join(config.root, filePath) + + const res = styleAttrRE.test(id) + ? (await importLightningCSS()).transformStyleAttribute({ + filename, + code: Buffer.from(src), + targets: cssConfig.targets, + minify: config.isProduction && config.build.cssMinify, + analyzeDependencies: true, + }) + : await ( + await importLightningCSS() + ).bundleAsync({ + filename, + resolver: { + read(filePath) { + if (filePath === filename) { + return src + } + return fs.readFileSync(toAbsolute(filePath), 'utf-8') + }, + async resolve(id, from) { + const publicFile = checkPublicFile(id, config) + if (publicFile) { + return publicFile + } + + const resolved = await getAtImportResolvers(config).css( + id, + toAbsolute(from), + ) + + if (resolved) { + deps.add(resolved) + return resolved + } + return id + }, + }, + targets: cssConfig.targets, + minify: config.isProduction && config.build.cssMinify, + sourceMap: true, + analyzeDependencies: true, + cssModules: cssModuleRE.test(id) + ? cssConfig.modules ?? true + : undefined, + drafts: cssConfig.drafts, + }) + + let css = res.code.toString() + for (const dep of res.dependencies!) { + switch (dep.type) { + case 'url': + deps.add(dep.url) + if (urlReplacer) { + css = css.replace(dep.placeholder, await urlReplacer(dep.url, id)) + } + break + default: + throw new Error(`Unsupported dependency type: ${dep.type}`) + } + } + + let modules: Record | undefined + if ('exports' in res && res.exports) { + modules = {} + // https://github.com/parcel-bundler/lightningcss/issues/291 + const sortedEntries = Object.entries(res.exports).sort((a, b) => + a[0].localeCompare(b[0]), + ) + for (const [key, value] of sortedEntries) { + modules[key] = value.name + // https://lightningcss.dev/css-modules.html#class-composition + for (const c of value.composes) { + modules[key] += ' ' + c.name + } + } + } + + return { + code: css, + map: 'map' in res ? res.map?.toString() : undefined, + deps, + modules, + } +} + +// Convert https://esbuild.github.io/api/#target +// To https://github.com/parcel-bundler/lightningcss/blob/master/node/targets.d.ts +const map: Record = { + chrome: 'chrome', + edge: 'edge', + firefox: 'firefox', + hermes: false, + ie: 'ie', + ios: 'ios_saf', + node: false, + opera: 'opera', + rhino: false, + safari: 'safari', +} + +const esMap: Record = { + // https://caniuse.com/?search=es2015 + 2015: ['chrome49', 'edge13', 'safari10', 'firefox44', 'opera36'], + // https://caniuse.com/?search=es2016 + 2016: ['chrome50', 'edge13', 'safari10', 'firefox43', 'opera37'], + // https://caniuse.com/?search=es2017 + 2017: ['chrome58', 'edge15', 'safari11', 'firefox52', 'opera45'], + // https://caniuse.com/?search=es2018 + 2018: ['chrome63', 'edge79', 'safari12', 'firefox58', 'opera50'], + // https://caniuse.com/?search=es2019 + 2019: ['chrome73', 'edge79', 'safari12.1', 'firefox64', 'opera60'], + // https://caniuse.com/?search=es2020 + 2020: ['chrome80', 'edge80', 'safari14.1', 'firefox80', 'opera67'], + // https://caniuse.com/?search=es2021 + 2021: ['chrome85', 'edge85', 'safari14.1', 'firefox80', 'opera71'], + // https://caniuse.com/?search=es2022 + 2022: ['chrome94', 'edge94', 'safari16.4', 'firefox93', 'opera80'], +} + +const esRE = /es(\d{4})/ +const versionRE = /\d/ + +export const convertTargets = ( + esbuildTarget: string | string[] | false, +): LightningCSSTargets => { + const targets: LightningCSSTargets = {} + if (!esbuildTarget) return targets + + const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => { + const match = e.match(esRE) + if (!match) return e + const year = Number(match[1]) + if (!esMap[year]) throw new Error(`Unsupported target "${e}"`) + return esMap[year] + }) + + for (const entry of entriesWithoutES) { + if (entry === 'esnext') continue + const index = entry.match(versionRE)?.index + if (index) { + const browser = map[entry.slice(0, index)] + if (browser === false) continue // No mapping available + if (browser) { + const [major, minor = 0] = entry + .slice(index) + .split('.') + .map((v) => parseInt(v, 10)) + if (!isNaN(major) && !isNaN(minor)) { + const version = (major << 16) | (minor << 8) + if (!targets[browser] || version < targets[browser]!) { + targets[browser] = version + } + continue + } + } + } + throw new Error(`Unsupported target "${entry}"`) + } + + return targets +} diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 729b9009b1c34c..b76c36dbda71df 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -42,7 +42,8 @@ interface ScriptAssetsUrl { url: string } -const htmlProxyRE = /\?html-proxy=?(?:&inline-css)?&index=(\d+)\.(js|css)$/ +const htmlProxyRE = + /\?html-proxy=?(?:&inline-css)?(?:&style-attr)?&index=(\d+)\.(js|css)$/ const inlineCSSRE = /__VITE_INLINE_CSS__([a-z\d]{8}_\d+)__/g // Do not allow preceding '.', but do allow preceding '...' for spread operations const inlineImportRE = @@ -481,7 +482,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { const filePath = id.replace(normalizePath(config.root), '') addToHTMLProxyCache(config, filePath, inlineModuleIndex, { code }) // will transform with css plugin and cache result with css-post plugin - js += `\nimport "${id}?html-proxy&inline-css&index=${inlineModuleIndex}.css"` + js += `\nimport "${id}?html-proxy&inline-css&style-attr&index=${inlineModuleIndex}.css"` const hash = getHash(cleanUrl(id)) // will transform in `applyHtmlTransforms` const sourceCodeLocation = node.sourceCodeLocation!.attrs!['style'] diff --git a/packages/vite/src/types/lightningcss.d.ts b/packages/vite/src/types/lightningcss.d.ts new file mode 100644 index 00000000000000..4fca70540b5a49 --- /dev/null +++ b/packages/vite/src/types/lightningcss.d.ts @@ -0,0 +1,10 @@ +import type { CSSModulesConfig, Drafts, Targets } from 'lightningcss' + +/* + Using a namespace create issue once bundled because definition are nor inlined, + and it creates types like `export type Drafts = Drafts` +*/ + +export type LightningCSSModulesConfig = CSSModulesConfig +export type LightningCSSDrafts = Drafts +export type LightningCSSTargets = Targets diff --git a/playground/css-lightningcss/__tests__/lightningcss.spec.ts b/playground/css-lightningcss/__tests__/lightningcss.spec.ts new file mode 100644 index 00000000000000..a94d09a296e6d6 --- /dev/null +++ b/playground/css-lightningcss/__tests__/lightningcss.spec.ts @@ -0,0 +1,67 @@ +import { expect, test } from 'vitest' +import { + editFile, + findAssetFile, + getColor, + isBuild, + page, + untilUpdated, +} from '~utils' + +// note: tests should retrieve the element at the beginning of test and reuse it +// in later assertions to ensure CSS HMR doesn't reload the page +test('linked css', async () => { + const linked = await page.$('.linked') + const atImport = await page.$('.linked-at-import') + + expect(await getColor(linked)).toBe('blue') + expect(await getColor(atImport)).toBe('red') + + editFile('linked.css', (code) => code.replace('color: blue', 'color: red')) + await untilUpdated(() => getColor(linked), 'red') + + editFile('linked-at-import.css', (code) => + code.replace('color: red', 'color: blue'), + ) + await untilUpdated(() => getColor(atImport), 'blue') +}) + +test('css import from js', async () => { + const imported = await page.$('.imported') + const atImport = await page.$('.imported-at-import') + + expect(await getColor(imported)).toBe('green') + expect(await getColor(atImport)).toBe('purple') + + editFile('imported.css', (code) => code.replace('color: green', 'color: red')) + await untilUpdated(() => getColor(imported), 'red') + + editFile('imported-at-import.css', (code) => + code.replace('color: purple', 'color: blue'), + ) + await untilUpdated(() => getColor(atImport), 'blue') +}) + +test('css modules', async () => { + const imported = await page.$('.modules') + expect(await getColor(imported)).toBe('turquoise') + + expect(await imported.getAttribute('class')).toMatch(/\w{6}_apply-color/) + + editFile('mod.module.css', (code) => + code.replace('color: turquoise', 'color: red'), + ) + await untilUpdated(() => getColor(imported), 'red') +}) + +test('inline css modules', async () => { + const css = await page.textContent('.modules-inline') + expect(css).toMatch(/\.\w{6}_apply-color-inline/) +}) + +test.runIf(isBuild)('minify css', async () => { + // should keep the rgba() syntax + const cssFile = findAssetFile(/index-\w+\.css$/) + expect(cssFile).toMatch('rgba(') + expect(cssFile).not.toMatch('#ffff00b3') +}) diff --git a/playground/css-lightningcss/composed.module.css b/playground/css-lightningcss/composed.module.css new file mode 100644 index 00000000000000..b2ae0e967dced1 --- /dev/null +++ b/playground/css-lightningcss/composed.module.css @@ -0,0 +1,3 @@ +.apply-color { + color: turquoise; +} diff --git a/playground/css-lightningcss/composes-path-resolving.module.css b/playground/css-lightningcss/composes-path-resolving.module.css new file mode 100644 index 00000000000000..2873293f9c7605 --- /dev/null +++ b/playground/css-lightningcss/composes-path-resolving.module.css @@ -0,0 +1,3 @@ +.path-resolving-css { + composes: apply-color from './composed.module.css'; +} diff --git a/playground/css-lightningcss/imported-at-import.css b/playground/css-lightningcss/imported-at-import.css new file mode 100644 index 00000000000000..b71ef00e65b27a --- /dev/null +++ b/playground/css-lightningcss/imported-at-import.css @@ -0,0 +1,3 @@ +.imported-at-import { + color: purple; +} diff --git a/playground/css-lightningcss/imported.css b/playground/css-lightningcss/imported.css new file mode 100644 index 00000000000000..41a9505a6cffe4 --- /dev/null +++ b/playground/css-lightningcss/imported.css @@ -0,0 +1,12 @@ +@import './imported-at-import.css'; + +.imported { + color: green; +} + +pre { + background-color: #eee; + width: 500px; + padding: 1em 1.5em; + border-radius: 10px; +} diff --git a/playground/css-lightningcss/index.html b/playground/css-lightningcss/index.html new file mode 100644 index 00000000000000..166e477c758396 --- /dev/null +++ b/playground/css-lightningcss/index.html @@ -0,0 +1,28 @@ + + +
+

Lightning CSS

+ +

<link>: This should be blue

+

@import in <link>: This should be red

+ +

import from js: This should be green

+

+ @import in import from js: This should be purple +

+ +

CSS modules: this should be turquoise

+

Imported CSS module:

+

+
+  

Imported compose/from CSS module:

+

+ CSS modules composes path resolving: this should be turquoise +

+

+
+  

Inline CSS module:

+

+
+ + diff --git a/playground/css-lightningcss/inline.module.css b/playground/css-lightningcss/inline.module.css new file mode 100644 index 00000000000000..9566e21e2cd1af --- /dev/null +++ b/playground/css-lightningcss/inline.module.css @@ -0,0 +1,3 @@ +.apply-color-inline { + color: turquoise; +} diff --git a/playground/css-lightningcss/inlined.css b/playground/css-lightningcss/inlined.css new file mode 100644 index 00000000000000..1b08950784ee76 --- /dev/null +++ b/playground/css-lightningcss/inlined.css @@ -0,0 +1,4 @@ +.inlined { + color: green; + background: url('./ok.png'); +} diff --git a/playground/css-lightningcss/linked-at-import.css b/playground/css-lightningcss/linked-at-import.css new file mode 100644 index 00000000000000..a778a3c754bb1b --- /dev/null +++ b/playground/css-lightningcss/linked-at-import.css @@ -0,0 +1,3 @@ +.linked-at-import { + color: red; +} diff --git a/playground/css-lightningcss/linked.css b/playground/css-lightningcss/linked.css new file mode 100644 index 00000000000000..49f677d1e6462a --- /dev/null +++ b/playground/css-lightningcss/linked.css @@ -0,0 +1,8 @@ +@import './linked-at-import.css'; + +/* test nesting */ +.wrapper { + .linked { + color: blue; + } +} diff --git a/playground/css-lightningcss/main.js b/playground/css-lightningcss/main.js new file mode 100644 index 00000000000000..8391376675565e --- /dev/null +++ b/playground/css-lightningcss/main.js @@ -0,0 +1,31 @@ +import './minify.css' +import './imported.css' +import mod from './mod.module.css' + +document.querySelector('.modules').classList.add(mod['apply-color']) +text('.modules-code', JSON.stringify(mod, null, 2)) + +import composesPathResolvingMod from './composes-path-resolving.module.css' +document + .querySelector('.path-resolved-modules-css') + .classList.add(...composesPathResolvingMod['path-resolving-css'].split(' ')) +text( + '.path-resolved-modules-code', + JSON.stringify(composesPathResolvingMod, null, 2), +) + +import inlineMod from './inline.module.css?inline' +text('.modules-inline', inlineMod) + +function text(el, text) { + document.querySelector(el).textContent = text +} + +if (import.meta.hot) { + import.meta.hot.accept('./mod.module.css', (newMod) => { + const list = document.querySelector('.modules').classList + list.remove(mod.applyColor) + list.add(newMod.applyColor) + text('.modules-code', JSON.stringify(newMod.default, null, 2)) + }) +} diff --git a/playground/css-lightningcss/minify.css b/playground/css-lightningcss/minify.css new file mode 100644 index 00000000000000..ada062407cdb38 --- /dev/null +++ b/playground/css-lightningcss/minify.css @@ -0,0 +1,3 @@ +.test-minify { + color: rgba(255, 255, 0, 0.7); +} diff --git a/playground/css-lightningcss/mod.module.css b/playground/css-lightningcss/mod.module.css new file mode 100644 index 00000000000000..b2ae0e967dced1 --- /dev/null +++ b/playground/css-lightningcss/mod.module.css @@ -0,0 +1,3 @@ +.apply-color { + color: turquoise; +} diff --git a/playground/css-lightningcss/ok.png b/playground/css-lightningcss/ok.png new file mode 100644 index 0000000000000000000000000000000000000000..a8d1e52510c41ceeaf3515ee2f594a82557d1685 GIT binary patch literal 4986 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 b37?V{t|cgkE9S{uec08Nb(D$~%%1%R{RRHc literal 0 HcmV?d00001 diff --git a/playground/css-lightningcss/package.json b/playground/css-lightningcss/package.json new file mode 100644 index 00000000000000..2d33ee8d5c36c2 --- /dev/null +++ b/playground/css-lightningcss/package.json @@ -0,0 +1,14 @@ +{ + "name": "@vitejs/test-css-lightningcss", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "debug": "node --inspect-brk ../../packages/vite/bin/vite", + "preview": "vite preview" + }, + "devDependencies": { + "lightningcss": "^1.20.0" + } +} diff --git a/playground/css-lightningcss/vite.config.js b/playground/css-lightningcss/vite.config.js new file mode 100644 index 00000000000000..a9efedb4b363ab --- /dev/null +++ b/playground/css-lightningcss/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + css: { + transformer: 'LightningCSS', + drafts: { nesting: true }, + }, + build: { + cssTarget: ['chrome61'], + cssMinifier: { minifier: 'LightningCSS' }, + }, +}) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ddadf91e4b2e5d..b7b45840a1851c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -348,6 +348,9 @@ importers: launch-editor-middleware: specifier: ^2.6.0 version: 2.6.0 + lightningcss: + specifier: ^1.20.0 + version: 1.20.0 magic-string: specifier: ^0.30.0 version: 0.30.0 @@ -536,6 +539,12 @@ importers: playground/css-dynamic-import: {} + playground/css-lightningcss: + devDependencies: + lightningcss: + specifier: ^1.20.0 + version: 1.20.0 + playground/css-sourcemap: devDependencies: less: @@ -5337,6 +5346,12 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: true + /detect-libc@2.0.1: resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} engines: {node: '>=8'} @@ -7276,6 +7291,94 @@ packages: type-check: 0.4.0 dev: true + /lightningcss-darwin-arm64@1.20.0: + resolution: {integrity: sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /lightningcss-darwin-x64@1.20.0: + resolution: {integrity: sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /lightningcss-linux-arm-gnueabihf@1.20.0: + resolution: {integrity: sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /lightningcss-linux-arm64-gnu@1.20.0: + resolution: {integrity: sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /lightningcss-linux-arm64-musl@1.20.0: + resolution: {integrity: sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /lightningcss-linux-x64-gnu@1.20.0: + resolution: {integrity: sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /lightningcss-linux-x64-musl@1.20.0: + resolution: {integrity: sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /lightningcss-win32-x64-msvc@1.20.0: + resolution: {integrity: sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /lightningcss@1.20.0: + resolution: {integrity: sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.20.0 + lightningcss-darwin-x64: 1.20.0 + lightningcss-linux-arm-gnueabihf: 1.20.0 + lightningcss-linux-arm64-gnu: 1.20.0 + lightningcss-linux-arm64-musl: 1.20.0 + lightningcss-linux-x64-gnu: 1.20.0 + lightningcss-linux-x64-musl: 1.20.0 + lightningcss-win32-x64-msvc: 1.20.0 + dev: true + /lilconfig@2.0.5: resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} engines: {node: '>=10'} From 0bdd121dce81be87aac83f219623b5941e7de9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Sun, 28 May 2023 17:10:13 +0200 Subject: [PATCH 2/8] Use object type --- packages/vite/src/node/build.ts | 13 +++++-------- packages/vite/src/node/index.ts | 6 +----- packages/vite/src/node/plugins/css.ts | 22 +++++++++------------- packages/vite/src/types/lightningcss.d.ts | 10 ++++++---- 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index aea9fdb922ec46..9de2442a1f7c51 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -20,10 +20,7 @@ import type { import type { Terser } from 'dep-types/terser' import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'dep-types/commonjs' -import type { - LightningCSSDrafts, - LightningCSSTargets, -} from 'dep-types/lightningcss' +import type { LightningCSS } from 'dep-types/lightningcss' import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' import type { TransformOptions } from 'esbuild' import type { InlineConfig, ResolvedConfig } from './config' @@ -149,8 +146,8 @@ export interface BuildOptions { | { minifier: 'esbuild' } | { minifier: 'LightningCSS' - targets?: LightningCSSTargets - drafts?: LightningCSSDrafts + targets?: LightningCSS['Targets'] + drafts?: LightningCSS['Drafts'] } /** * If `true`, a separate sourcemap file will be created. If 'inline', the @@ -325,8 +322,8 @@ export interface ResolvedBuildOptions | { minifier: 'esbuild' } | { minifier: 'LightningCSS' - targets: LightningCSSTargets - drafts: LightningCSSDrafts + targets: LightningCSS['Targets'] + drafts: LightningCSS['Drafts'] } } diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index a8caa3b7012ad0..81f65dc5772c52 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -145,8 +145,4 @@ export type { Terser } from 'dep-types/terser' export type { RollupCommonJSOptions } from 'dep-types/commonjs' export type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' export type { Matcher, AnymatchPattern, AnymatchFn } from 'dep-types/anymatch' -export type { - LightningCSSTargets, - LightningCSSDrafts, - LightningCSSModulesConfig, -} from 'dep-types/lightningcss' +export type { LightningCSS } from 'dep-types/lightningcss' diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 218ebd54b64c66..e6ccf31df27332 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -20,11 +20,7 @@ import type Sass from 'sass' import type Stylus from 'stylus' import type Less from 'less' import type { Alias } from 'dep-types/alias' -import type { - LightningCSSDrafts, - LightningCSSModulesConfig, - LightningCSSTargets, -} from 'dep-types/lightningcss' +import type { LightningCSS } from 'dep-types/lightningcss' import type { TransformOptions } from 'esbuild' import { formatMessages, transform } from 'esbuild' import type { RawSourceMap } from '@ampproject/remapping' @@ -128,13 +124,13 @@ export interface CSSModulesOptions { */ export interface LightningCSSOptions { transformer: 'LightningCSS' - modules?: LightningCSSModulesConfig + modules?: LightningCSS['CSSModulesConfig'] /** * Use `{ nesting: true }` to enable support for CSS nesting. The implementation * is following the ongoing specification, so this could contain * breaking changes in future version of Lightning CSS. */ - drafts?: LightningCSSDrafts + drafts?: LightningCSS['Drafts'] } /** @@ -142,9 +138,9 @@ export interface LightningCSSOptions { */ export interface ResolvedLightningCSSOptions { transformer: 'LightningCSS' - targets: LightningCSSTargets - modules: LightningCSSModulesConfig | undefined - drafts: LightningCSSDrafts + targets: LightningCSS['Targets'] + modules: LightningCSS['CSSModulesConfig'] | undefined + drafts: LightningCSS['Drafts'] } export function resolveCSSOptions( @@ -2232,7 +2228,7 @@ async function compileLightningCSS( // Convert https://esbuild.github.io/api/#target // To https://github.com/parcel-bundler/lightningcss/blob/master/node/targets.d.ts -const map: Record = { +const map: Record = { chrome: 'chrome', edge: 'edge', firefox: 'firefox', @@ -2269,8 +2265,8 @@ const versionRE = /\d/ export const convertTargets = ( esbuildTarget: string | string[] | false, -): LightningCSSTargets => { - const targets: LightningCSSTargets = {} +): LightningCSS['Targets'] => { + const targets: LightningCSS['Targets'] = {} if (!esbuildTarget) return targets const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => { diff --git a/packages/vite/src/types/lightningcss.d.ts b/packages/vite/src/types/lightningcss.d.ts index 4fca70540b5a49..7afe703acb17d2 100644 --- a/packages/vite/src/types/lightningcss.d.ts +++ b/packages/vite/src/types/lightningcss.d.ts @@ -1,10 +1,12 @@ import type { CSSModulesConfig, Drafts, Targets } from 'lightningcss' /* - Using a namespace create issue once bundled because definition are nor inlined, + Using a namespace create issue once bundled because definition are not inlined, and it creates types like `export type Drafts = Drafts` */ -export type LightningCSSModulesConfig = CSSModulesConfig -export type LightningCSSDrafts = Drafts -export type LightningCSSTargets = Targets +export type LightningCSS = { + CSSModulesConfig: CSSModulesConfig + Drafts: Drafts + Targets: Targets +} From a1a2156499316decec7b8018cee1145ba2459cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Sun, 28 May 2023 17:40:38 +0200 Subject: [PATCH 3/8] Update API to keep one CSSOptions --- packages/vite/src/node/build.ts | 6 +- packages/vite/src/node/config.ts | 16 +-- packages/vite/src/node/index.ts | 3 +- packages/vite/src/node/plugins/css.ts | 109 +++++++++++---------- playground/css-lightningcss/vite.config.js | 8 +- 5 files changed, 69 insertions(+), 73 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 9de2442a1f7c51..f956facb1461bf 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -145,7 +145,7 @@ export interface BuildOptions { cssMinifier?: | { minifier: 'esbuild' } | { - minifier: 'LightningCSS' + minifier: 'lightningcss' targets?: LightningCSS['Targets'] drafts?: LightningCSS['Drafts'] } @@ -321,7 +321,7 @@ export interface ResolvedBuildOptions cssMinifier: | { minifier: 'esbuild' } | { - minifier: 'LightningCSS' + minifier: 'lightningcss' targets: LightningCSS['Targets'] drafts: LightningCSS['Drafts'] } @@ -448,7 +448,7 @@ export function resolveBuildOptions( resolved.cssMinifier = { minifier: 'esbuild' } } - if (resolved.cssMinifier.minifier === 'LightningCSS') { + if (resolved.cssMinifier.minifier === 'lightningcss') { if (!resolved.cssMinifier.targets) { resolved.cssMinifier.targets = convertTargets(resolved.cssTarget) } diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index a9c00f78697fac..9255d90b09f3f0 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -23,8 +23,7 @@ import type { PreviewOptions, ResolvedPreviewOptions } from './preview' import { resolvePreviewOptions } from './preview' import { type CSSOptions, - type LightningCSSOptions, - type ResolvedLightningCSSOptions, + type ResolvedCSSOptions, resolveCSSOptions, } from './plugins/css' import { @@ -172,16 +171,9 @@ export interface UserConfig { */ resolve?: ResolveOptions & { alias?: AliasOptions } /** - * CSS related options - * - CSSOptions is the default and provide configuration for PostCSS and - * various preprocessors - * - LightningCSSOptions is an experimental option to handle CSS modules, - * assets and imports via Lightning CSS. It requires to install it - * as a peer dependency. This is incompatible with the use of preprocessors. - * - * See build options to configure CSS minification. + * CSS related options (preprocessors and CSS modules) */ - css?: CSSOptions | LightningCSSOptions + css?: CSSOptions /** * JSON loading options */ @@ -364,7 +356,7 @@ export type ResolvedConfig = Readonly< alias: Alias[] } plugins: readonly Plugin[] - css: CSSOptions | ResolvedLightningCSSOptions | undefined + css: ResolvedCSSOptions | undefined esbuild: ESBuildOptions | false server: ResolvedServerOptions build: ResolvedBuildOptions diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index 81f65dc5772c52..b33d128096a86d 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -76,8 +76,7 @@ export type { CSSOptions, CSSModulesOptions, PreprocessCSSResult, - LightningCSSOptions, - ResolvedLightningCSSOptions, + ResolvedCSSOptions, } from './plugins/css' export type { JsonOptions } from './plugins/json' export type { TransformOptions as EsbuildTransformOptions } from 'esbuild' diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index e6ccf31df27332..cea60b78e3c435 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -73,10 +73,18 @@ import type { ESBuildOptions } from './esbuild' // const debug = createDebugger('vite:css') export interface CSSOptions { + /** + * Using lightningcss is an experimental option to handle CSS modules, + * assets and imports via Lightning CSS. It requires to install it as a + * peer dependency. This is incompatible with the use of preprocessors. + * + * @default 'postcss' + * @experimental + */ + transformer?: 'postcss' | 'lightningcss' /** * https://github.com/css-modules/postcss-modules */ - transformer?: 'PostCSS' modules?: CSSModulesOptions | false preprocessorOptions?: Record postcss?: @@ -90,6 +98,19 @@ export interface CSSOptions { * @experimental */ devSourcemap?: boolean + + /** + * @experimental + */ + lightningcss?: { + modules?: LightningCSS['CSSModulesConfig'] + /** + * Use `{ nesting: true }` to enable support for CSS nesting. The implementation + * is following the ongoing specification, so this could contain + * breaking changes in future version of Lightning CSS. + */ + drafts?: LightningCSS['Drafts'] + } } export interface CSSModulesOptions { @@ -119,47 +140,34 @@ export interface CSSModulesOptions { ) => string) } -/** - * @experimental - */ -export interface LightningCSSOptions { - transformer: 'LightningCSS' - modules?: LightningCSS['CSSModulesConfig'] - /** - * Use `{ nesting: true }` to enable support for CSS nesting. The implementation - * is following the ongoing specification, so this could contain - * breaking changes in future version of Lightning CSS. - */ - drafts?: LightningCSS['Drafts'] -} - -/** - * @experimental - */ -export interface ResolvedLightningCSSOptions { - transformer: 'LightningCSS' - targets: LightningCSS['Targets'] - modules: LightningCSS['CSSModulesConfig'] | undefined - drafts: LightningCSS['Drafts'] +export type ResolvedCSSOptions = Omit & { + lightningcss?: { + targets: LightningCSS['Targets'] + modules: LightningCSS['CSSModulesConfig'] | undefined + drafts: LightningCSS['Drafts'] + } } export function resolveCSSOptions( - options: CSSOptions | LightningCSSOptions | undefined, + options: CSSOptions | undefined, resolvedBuildOptions: ResolvedBuildOptions, -): CSSOptions | ResolvedLightningCSSOptions | undefined { - if (options?.transformer === 'LightningCSS') { +): ResolvedCSSOptions | undefined { + if (options?.lightningcss) { return { - transformer: 'LightningCSS', - targets: - resolvedBuildOptions.cssMinifier.minifier === 'LightningCSS' && - resolvedBuildOptions.cssMinifier.targets - ? resolvedBuildOptions.cssMinifier.targets - : convertTargets(resolvedBuildOptions.cssTarget), - modules: options.modules, - drafts: options.drafts ?? {}, + ...options, + lightningcss: { + targets: + resolvedBuildOptions.cssMinifier.minifier === 'lightningcss' && + resolvedBuildOptions.cssMinifier.targets + ? resolvedBuildOptions.cssMinifier.targets + : convertTargets(resolvedBuildOptions.cssTarget), + modules: options.lightningcss.modules, + drafts: options.lightningcss.drafts ?? {}, + }, } } - return options + // TS doesn't narrow the type with the previous if :/ + return options as Omit } const cssModuleRE = new RegExp(`\\.module${CSS_LANGS_RE.source}`) @@ -237,8 +245,8 @@ export function cssPlugin(config: ResolvedConfig): Plugin { }) // warm up cache for resolved postcss config - if (config.css?.transformer !== 'LightningCSS') { - resolvePostcssConfig(config, config.css) + if (config.css?.transformer !== 'lightningcss') { + resolvePostcssConfig(config) } return { @@ -442,10 +450,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { if (config.command === 'serve') { const getContentWithSourcemap = async (content: string) => { - if ( - config.css?.transformer === 'LightningCSS' || - config.css?.devSourcemap - ) { + if (config.css?.devSourcemap) { const sourcemap = this.getCombinedSourcemap() if (sourcemap.mappings && !sourcemap.sourcesContent) { await injectSourcesContent(sourcemap, cleanUrl(id), config.logger) @@ -891,8 +896,8 @@ async function compileCSS( modules?: Record deps?: Set }> { - if (config.css?.transformer === 'LightningCSS') { - return compileLightningCSS(id, code, config, config.css, urlReplacer) + if (config.css?.transformer === 'lightningcss') { + return compileLightningCSS(id, code, config, urlReplacer) } const { @@ -906,7 +911,7 @@ async function compileCSS( const needInlineImport = code.includes('@import') const hasUrl = cssUrlRE.test(code) || cssImageSetRE.test(code) const lang = id.match(CSS_LANGS_RE)?.[1] as CssLang | undefined - const postcssConfig = await resolvePostcssConfig(config, config.css) + const postcssConfig = await resolvePostcssConfig(config) // 1. plain css that needs no processing if ( @@ -1269,7 +1274,6 @@ interface PostCSSConfigResult { async function resolvePostcssConfig( config: ResolvedConfig, - cssConfig: CSSOptions | undefined, ): Promise { let result = postcssConfigCache.get(config) if (result !== undefined) { @@ -1277,7 +1281,7 @@ async function resolvePostcssConfig( } // inline postcss config via vite config - const inlineOptions = cssConfig?.postcss + const inlineOptions = config.css?.postcss if (isObject(inlineOptions)) { const options = { ...inlineOptions } @@ -1478,7 +1482,7 @@ async function doImportCSSReplace( } async function minifyCSS(css: string, config: ResolvedConfig) { - if (config.build.cssMinifier?.minifier === 'LightningCSS') { + if (config.build.cssMinifier?.minifier === 'lightningcss') { const { code, warnings } = (await importLightningCSS()).transform({ filename: cssBundleName, code: Buffer.from(css), @@ -2132,7 +2136,6 @@ async function compileLightningCSS( id: string, src: string, config: ResolvedConfig, - cssConfig: ResolvedLightningCSSOptions, urlReplacer?: CssUrlReplacer, ): ReturnType { const deps = new Set() @@ -2145,7 +2148,7 @@ async function compileLightningCSS( ? (await importLightningCSS()).transformStyleAttribute({ filename, code: Buffer.from(src), - targets: cssConfig.targets, + targets: config.css?.lightningcss?.targets, minify: config.isProduction && config.build.cssMinify, analyzeDependencies: true, }) @@ -2178,14 +2181,14 @@ async function compileLightningCSS( return id }, }, - targets: cssConfig.targets, + targets: config.css?.lightningcss?.targets, minify: config.isProduction && config.build.cssMinify, - sourceMap: true, + sourceMap: config.css?.devSourcemap, analyzeDependencies: true, cssModules: cssModuleRE.test(id) - ? cssConfig.modules ?? true + ? config.css?.lightningcss?.modules ?? true : undefined, - drafts: cssConfig.drafts, + drafts: config.css?.lightningcss?.drafts, }) let css = res.code.toString() diff --git a/playground/css-lightningcss/vite.config.js b/playground/css-lightningcss/vite.config.js index a9efedb4b363ab..f17c446f5bf896 100644 --- a/playground/css-lightningcss/vite.config.js +++ b/playground/css-lightningcss/vite.config.js @@ -2,11 +2,13 @@ import { defineConfig } from 'vite' export default defineConfig({ css: { - transformer: 'LightningCSS', - drafts: { nesting: true }, + transformer: 'lightningcss', + lightningcss: { + drafts: { nesting: true }, + }, }, build: { cssTarget: ['chrome61'], - cssMinifier: { minifier: 'LightningCSS' }, + cssMinifier: { minifier: 'lightningcss' }, }, }) From 0becd35f355d6476e342924e41c836e5e75c7b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Sat, 3 Jun 2023 11:39:58 +0200 Subject: [PATCH 4/8] update cssMinifier API --- packages/vite/src/node/build.ts | 48 ++++++++++------------ packages/vite/src/node/plugins/css.ts | 12 +++--- playground/css-lightningcss/vite.config.js | 2 +- 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index f956facb1461bf..67f51e3bcba1e0 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -138,17 +138,19 @@ export interface BuildOptions { /** * @experimental * Use Lightning CSS to minify CSS. This should be installed as a peer - * dependency. Targets is automatically converted from esbuild (css)target, but - * can be provided for more granular control. + * dependency. * @default esbuild */ - cssMinifier?: - | { minifier: 'esbuild' } - | { - minifier: 'lightningcss' - targets?: LightningCSS['Targets'] - drafts?: LightningCSS['Drafts'] - } + cssMinifier?: 'esbuild' | 'lightningcss' + /** + * @experimental + * Targets is automatically converted from esbuild (css)target, but + * can be provided for more granular control. + */ + lightningcss?: { + targets?: LightningCSS['Targets'] + drafts?: LightningCSS['Drafts'] + } /** * If `true`, a separate sourcemap file will be created. If 'inline', the * sourcemap will be appended to the resulting output file as data URI. @@ -315,16 +317,13 @@ export type ResolveModulePreloadDependenciesFn = ( export interface ResolvedBuildOptions extends Required< - Omit + Omit > { modulePreload: false | ResolvedModulePreloadOptions - cssMinifier: - | { minifier: 'esbuild' } - | { - minifier: 'lightningcss' - targets: LightningCSS['Targets'] - drafts: LightningCSS['Drafts'] - } + lightningcss?: { + targets: LightningCSS['Targets'] + drafts: LightningCSS['Drafts'] + } } export function resolveBuildOptions( @@ -444,16 +443,11 @@ export function resolveBuildOptions( resolved.cssMinify = !!resolved.minify } - if (!resolved.cssMinifier) { - resolved.cssMinifier = { minifier: 'esbuild' } - } - - if (resolved.cssMinifier.minifier === 'lightningcss') { - if (!resolved.cssMinifier.targets) { - resolved.cssMinifier.targets = convertTargets(resolved.cssTarget) - } - if (!resolved.cssMinifier.drafts) { - resolved.cssMinifier.drafts = {} + if (resolved.cssMinifier === 'lightningcss') { + resolved.lightningcss = { + targets: + resolved.lightningcss?.targets ?? convertTargets(resolved.cssTarget), + drafts: resolved.lightningcss?.drafts ?? {}, } } diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index cea60b78e3c435..e4b427e919788e 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -157,9 +157,9 @@ export function resolveCSSOptions( ...options, lightningcss: { targets: - resolvedBuildOptions.cssMinifier.minifier === 'lightningcss' && - resolvedBuildOptions.cssMinifier.targets - ? resolvedBuildOptions.cssMinifier.targets + resolvedBuildOptions.cssMinifier === 'lightningcss' && + resolvedBuildOptions.lightningcss?.targets + ? resolvedBuildOptions.lightningcss.targets : convertTargets(resolvedBuildOptions.cssTarget), modules: options.lightningcss.modules, drafts: options.lightningcss.drafts ?? {}, @@ -1482,12 +1482,12 @@ async function doImportCSSReplace( } async function minifyCSS(css: string, config: ResolvedConfig) { - if (config.build.cssMinifier?.minifier === 'lightningcss') { + if (config.build.cssMinifier === 'lightningcss') { const { code, warnings } = (await importLightningCSS()).transform({ filename: cssBundleName, code: Buffer.from(css), - targets: config.build.cssMinifier.targets, - drafts: config.build.cssMinifier.drafts, + targets: config.build.lightningcss!.targets, + drafts: config.build.lightningcss!.drafts, minify: true, }) if (warnings.length) { diff --git a/playground/css-lightningcss/vite.config.js b/playground/css-lightningcss/vite.config.js index f17c446f5bf896..01d02638a987a2 100644 --- a/playground/css-lightningcss/vite.config.js +++ b/playground/css-lightningcss/vite.config.js @@ -9,6 +9,6 @@ export default defineConfig({ }, build: { cssTarget: ['chrome61'], - cssMinifier: { minifier: 'lightningcss' }, + cssMinifier: 'lightningcss', }, }) From 67c821dc6bc66faf2d6a3f8d0a73eb2bef54c36a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Thu, 15 Jun 2023 03:17:23 +0200 Subject: [PATCH 5/8] Simplify build API and expose more options --- packages/vite/package.json | 4 +- packages/vite/scripts/api-extractor.ts | 5 +- packages/vite/src/node/build.ts | 38 +-------- packages/vite/src/node/index.ts | 2 +- packages/vite/src/node/plugins/css.ts | 49 +++++------ packages/vite/src/types/lightningcss.d.ts | 31 ++++--- playground/css-lightningcss/vite.config.js | 2 +- pnpm-lock.yaml | 94 +++++++++++++++++++++- 8 files changed, 140 insertions(+), 85 deletions(-) diff --git a/packages/vite/package.json b/packages/vite/package.json index 8ce79856748b02..054987dd6d4ab3 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -108,7 +108,7 @@ "http-proxy": "^1.18.1", "json-stable-stringify": "^1.0.2", "launch-editor-middleware": "^2.6.0", - "lightningcss": "^1.20.0", + "lightningcss": "^1.21.0", "magic-string": "^0.30.0", "micromatch": "^4.0.5", "mlly": "^1.3.0", @@ -140,7 +140,7 @@ "sass": "*", "stylus": "*", "sugarss": "*", - "lightningcss": "^1.20.0", + "lightningcss": "^1.21.0", "terser": "^5.4.0" }, "peerDependenciesMeta": { diff --git a/packages/vite/scripts/api-extractor.ts b/packages/vite/scripts/api-extractor.ts index 773b5e195c2e52..1154830ffa8cd6 100644 --- a/packages/vite/scripts/api-extractor.ts +++ b/packages/vite/scripts/api-extractor.ts @@ -8,10 +8,7 @@ const result = Extractor.invoke( // @ts-expect-error TS requires to use the const enum, which is not available as the named export in tsx message.logLevel = 'none' } - if ( - message.sourceFilePath?.includes('lightningcss') && - message.messageId === 'tsdoc-characters-after-block-tag' - ) { + if (message.sourceFilePath?.includes('lightningcss')) { ignore() } if (message.messageId === 'ae-forgotten-export') { diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts index 67f51e3bcba1e0..859713d598ee7c 100644 --- a/packages/vite/src/node/build.ts +++ b/packages/vite/src/node/build.ts @@ -20,7 +20,6 @@ import type { import type { Terser } from 'dep-types/terser' import commonjsPlugin from '@rollup/plugin-commonjs' import type { RollupCommonJSOptions } from 'dep-types/commonjs' -import type { LightningCSS } from 'dep-types/lightningcss' import type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' import type { TransformOptions } from 'esbuild' import type { InlineConfig, ResolvedConfig } from './config' @@ -60,7 +59,6 @@ import { resolveChokidarOptions } from './watch' import { completeSystemWrapPlugin } from './plugins/completeSystemWrap' import { mergeConfig } from './publicUtils' import { webWorkerPostPlugin } from './plugins/worker' -import { convertTargets } from './plugins/css' export interface BuildOptions { /** @@ -132,25 +130,9 @@ export interface BuildOptions { /** * Override CSS minification specifically instead of defaulting to `build.minify`, * so you can configure minification for JS and CSS separately. - * @default minify - */ - cssMinify?: boolean - /** - * @experimental - * Use Lightning CSS to minify CSS. This should be installed as a peer - * dependency. - * @default esbuild - */ - cssMinifier?: 'esbuild' | 'lightningcss' - /** - * @experimental - * Targets is automatically converted from esbuild (css)target, but - * can be provided for more granular control. + * @default 'esbuild' */ - lightningcss?: { - targets?: LightningCSS['Targets'] - drafts?: LightningCSS['Drafts'] - } + cssMinify?: boolean | 'esbuild' | 'lightningcss' /** * If `true`, a separate sourcemap file will be created. If 'inline', the * sourcemap will be appended to the resulting output file as data URI. @@ -316,14 +298,8 @@ export type ResolveModulePreloadDependenciesFn = ( ) => string[] export interface ResolvedBuildOptions - extends Required< - Omit - > { + extends Required> { modulePreload: false | ResolvedModulePreloadOptions - lightningcss?: { - targets: LightningCSS['Targets'] - drafts: LightningCSS['Drafts'] - } } export function resolveBuildOptions( @@ -443,14 +419,6 @@ export function resolveBuildOptions( resolved.cssMinify = !!resolved.minify } - if (resolved.cssMinifier === 'lightningcss') { - resolved.lightningcss = { - targets: - resolved.lightningcss?.targets ?? convertTargets(resolved.cssTarget), - drafts: resolved.lightningcss?.drafts ?? {}, - } - } - return resolved } diff --git a/packages/vite/src/node/index.ts b/packages/vite/src/node/index.ts index b33d128096a86d..ffa1d4ecd83a49 100644 --- a/packages/vite/src/node/index.ts +++ b/packages/vite/src/node/index.ts @@ -144,4 +144,4 @@ export type { Terser } from 'dep-types/terser' export type { RollupCommonJSOptions } from 'dep-types/commonjs' export type { RollupDynamicImportVarsOptions } from 'dep-types/dynamicImportVars' export type { Matcher, AnymatchPattern, AnymatchFn } from 'dep-types/anymatch' -export type { LightningCSS } from 'dep-types/lightningcss' +export type { LightningCSSOptions } from 'dep-types/lightningcss' diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index e4b427e919788e..1b84a819c336d6 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -20,7 +20,7 @@ import type Sass from 'sass' import type Stylus from 'stylus' import type Less from 'less' import type { Alias } from 'dep-types/alias' -import type { LightningCSS } from 'dep-types/lightningcss' +import type { LightningCSSOptions } from 'dep-types/lightningcss' import type { TransformOptions } from 'esbuild' import { formatMessages, transform } from 'esbuild' import type { RawSourceMap } from '@ampproject/remapping' @@ -102,15 +102,7 @@ export interface CSSOptions { /** * @experimental */ - lightningcss?: { - modules?: LightningCSS['CSSModulesConfig'] - /** - * Use `{ nesting: true }` to enable support for CSS nesting. The implementation - * is following the ongoing specification, so this could contain - * breaking changes in future version of Lightning CSS. - */ - drafts?: LightningCSS['Drafts'] - } + lightningcss?: LightningCSSOptions } export interface CSSModulesOptions { @@ -141,10 +133,8 @@ export interface CSSModulesOptions { } export type ResolvedCSSOptions = Omit & { - lightningcss?: { - targets: LightningCSS['Targets'] - modules: LightningCSS['CSSModulesConfig'] | undefined - drafts: LightningCSS['Drafts'] + lightningcss?: LightningCSSOptions & { + targets: LightningCSSOptions['targets'] } } @@ -156,13 +146,10 @@ export function resolveCSSOptions( return { ...options, lightningcss: { + ...options.lightningcss, targets: - resolvedBuildOptions.cssMinifier === 'lightningcss' && - resolvedBuildOptions.lightningcss?.targets - ? resolvedBuildOptions.lightningcss.targets - : convertTargets(resolvedBuildOptions.cssTarget), - modules: options.lightningcss.modules, - drafts: options.lightningcss.drafts ?? {}, + options.lightningcss.targets ?? + convertTargets(resolvedBuildOptions.cssTarget), }, } } @@ -1482,12 +1469,12 @@ async function doImportCSSReplace( } async function minifyCSS(css: string, config: ResolvedConfig) { - if (config.build.cssMinifier === 'lightningcss') { + if (config.build.cssMinify === 'lightningcss') { const { code, warnings } = (await importLightningCSS()).transform({ + ...config.css?.lightningcss, + cssModules: undefined, filename: cssBundleName, code: Buffer.from(css), - targets: config.build.lightningcss!.targets, - drafts: config.build.lightningcss!.drafts, minify: true, }) if (warnings.length) { @@ -2149,7 +2136,7 @@ async function compileLightningCSS( filename, code: Buffer.from(src), targets: config.css?.lightningcss?.targets, - minify: config.isProduction && config.build.cssMinify, + minify: config.isProduction && !!config.build.cssMinify, analyzeDependencies: true, }) : await ( @@ -2182,11 +2169,11 @@ async function compileLightningCSS( }, }, targets: config.css?.lightningcss?.targets, - minify: config.isProduction && config.build.cssMinify, + minify: config.isProduction && !!config.build.cssMinify, sourceMap: config.css?.devSourcemap, analyzeDependencies: true, cssModules: cssModuleRE.test(id) - ? config.css?.lightningcss?.modules ?? true + ? config.css?.lightningcss?.cssModules ?? true : undefined, drafts: config.css?.lightningcss?.drafts, }) @@ -2231,7 +2218,11 @@ async function compileLightningCSS( // Convert https://esbuild.github.io/api/#target // To https://github.com/parcel-bundler/lightningcss/blob/master/node/targets.d.ts -const map: Record = { + +const map: Record< + string, + keyof NonNullable | false | undefined +> = { chrome: 'chrome', edge: 'edge', firefox: 'firefox', @@ -2268,8 +2259,8 @@ const versionRE = /\d/ export const convertTargets = ( esbuildTarget: string | string[] | false, -): LightningCSS['Targets'] => { - const targets: LightningCSS['Targets'] = {} +): LightningCSSOptions['targets'] => { + const targets: LightningCSSOptions['targets'] = {} if (!esbuildTarget) return targets const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => { diff --git a/packages/vite/src/types/lightningcss.d.ts b/packages/vite/src/types/lightningcss.d.ts index 7afe703acb17d2..305ffb30f1879b 100644 --- a/packages/vite/src/types/lightningcss.d.ts +++ b/packages/vite/src/types/lightningcss.d.ts @@ -1,12 +1,23 @@ -import type { CSSModulesConfig, Drafts, Targets } from 'lightningcss' +import type { + CSSModulesConfig, + Drafts, + Features, + NonStandard, + PseudoClasses, + Targets, +} from 'lightningcss' -/* - Using a namespace create issue once bundled because definition are not inlined, - and it creates types like `export type Drafts = Drafts` -*/ - -export type LightningCSS = { - CSSModulesConfig: CSSModulesConfig - Drafts: Drafts - Targets: Targets +/** + * Options are spread, so you can also use options that are not typed here like + * visitor that will impact to much the bundle size. + */ +export type LightningCSSOptions = { + targets?: Targets + include?: Features + exclude?: Features + drafts?: Drafts + nonStandard?: NonStandard + pseudoClasses?: PseudoClasses + unusedSymbols?: string[] + cssModules?: CSSModulesConfig } diff --git a/playground/css-lightningcss/vite.config.js b/playground/css-lightningcss/vite.config.js index 01d02638a987a2..7926682609b766 100644 --- a/playground/css-lightningcss/vite.config.js +++ b/playground/css-lightningcss/vite.config.js @@ -9,6 +9,6 @@ export default defineConfig({ }, build: { cssTarget: ['chrome61'], - cssMinifier: 'lightningcss', + cssMinify: 'lightningcss', }, }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b7b45840a1851c..bf1069463b39f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '6.1' settings: autoInstallPeers: false @@ -349,8 +349,8 @@ importers: specifier: ^2.6.0 version: 2.6.0 lightningcss: - specifier: ^1.20.0 - version: 1.20.0 + specifier: ^1.21.0 + version: 1.21.0 magic-string: specifier: ^0.30.0 version: 0.30.0 @@ -7300,6 +7300,15 @@ packages: dev: true optional: true + /lightningcss-darwin-arm64@1.21.0: + resolution: {integrity: sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /lightningcss-darwin-x64@1.20.0: resolution: {integrity: sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg==} engines: {node: '>= 12.0.0'} @@ -7309,6 +7318,15 @@ packages: dev: true optional: true + /lightningcss-darwin-x64@1.21.0: + resolution: {integrity: sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + /lightningcss-linux-arm-gnueabihf@1.20.0: resolution: {integrity: sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg==} engines: {node: '>= 12.0.0'} @@ -7318,6 +7336,15 @@ packages: dev: true optional: true + /lightningcss-linux-arm-gnueabihf@1.21.0: + resolution: {integrity: sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + /lightningcss-linux-arm64-gnu@1.20.0: resolution: {integrity: sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw==} engines: {node: '>= 12.0.0'} @@ -7327,6 +7354,15 @@ packages: dev: true optional: true + /lightningcss-linux-arm64-gnu@1.21.0: + resolution: {integrity: sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /lightningcss-linux-arm64-musl@1.20.0: resolution: {integrity: sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ==} engines: {node: '>= 12.0.0'} @@ -7336,6 +7372,15 @@ packages: dev: true optional: true + /lightningcss-linux-arm64-musl@1.21.0: + resolution: {integrity: sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /lightningcss-linux-x64-gnu@1.20.0: resolution: {integrity: sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g==} engines: {node: '>= 12.0.0'} @@ -7345,6 +7390,15 @@ packages: dev: true optional: true + /lightningcss-linux-x64-gnu@1.21.0: + resolution: {integrity: sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /lightningcss-linux-x64-musl@1.20.0: resolution: {integrity: sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA==} engines: {node: '>= 12.0.0'} @@ -7354,6 +7408,15 @@ packages: dev: true optional: true + /lightningcss-linux-x64-musl@1.21.0: + resolution: {integrity: sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /lightningcss-win32-x64-msvc@1.20.0: resolution: {integrity: sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA==} engines: {node: '>= 12.0.0'} @@ -7363,6 +7426,15 @@ packages: dev: true optional: true + /lightningcss-win32-x64-msvc@1.21.0: + resolution: {integrity: sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + /lightningcss@1.20.0: resolution: {integrity: sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g==} engines: {node: '>= 12.0.0'} @@ -7379,6 +7451,22 @@ packages: lightningcss-win32-x64-msvc: 1.20.0 dev: true + /lightningcss@1.21.0: + resolution: {integrity: sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.21.0 + lightningcss-darwin-x64: 1.21.0 + lightningcss-linux-arm-gnueabihf: 1.21.0 + lightningcss-linux-arm64-gnu: 1.21.0 + lightningcss-linux-arm64-musl: 1.21.0 + lightningcss-linux-x64-gnu: 1.21.0 + lightningcss-linux-x64-musl: 1.21.0 + lightningcss-win32-x64-msvc: 1.21.0 + dev: true + /lilconfig@2.0.5: resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} engines: {node: '>=10'} From b27fd4f417447e16c4272df561bf06d0504eeb06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Thu, 15 Jun 2023 10:06:36 +0200 Subject: [PATCH 6/8] Don't use build config in dev --- packages/vite/src/node/config.ts | 2 +- packages/vite/src/node/plugins/css.ts | 16 ++++++++++++---- packages/vite/src/types/lightningcss.d.ts | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 9255d90b09f3f0..bf6ecbb708dc29 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -680,7 +680,7 @@ export async function resolveConfig( mainConfig: null, isProduction, plugins: userPlugins, - css: resolveCSSOptions(config.css, resolvedBuildOptions), + css: resolveCSSOptions(config.css), esbuild: config.esbuild === false ? false diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1b84a819c336d6..b2465d4a1d45ba 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -26,11 +26,12 @@ import { formatMessages, transform } from 'esbuild' import type { RawSourceMap } from '@ampproject/remapping' import { getCodeWithSourcemap, injectSourcesContent } from '../server/sourcemap' import type { ModuleNode } from '../server/moduleGraph' -import type { ResolveFn, ResolvedBuildOptions, ViteDevServer } from '../' +import type { ResolveFn, ViteDevServer } from '../' import { resolveUserExternal, toOutputFilePathInCss } from '../build' import { CLIENT_PUBLIC_PATH, CSS_LANGS_RE, + ESBUILD_MODULES_TARGET, SPECIAL_QUERY_RE, } from '../constants' import type { ResolvedConfig } from '../config' @@ -140,7 +141,6 @@ export type ResolvedCSSOptions = Omit & { export function resolveCSSOptions( options: CSSOptions | undefined, - resolvedBuildOptions: ResolvedBuildOptions, ): ResolvedCSSOptions | undefined { if (options?.lightningcss) { return { @@ -149,7 +149,7 @@ export function resolveCSSOptions( ...options.lightningcss, targets: options.lightningcss.targets ?? - convertTargets(resolvedBuildOptions.cssTarget), + convertTargets(ESBUILD_MODULES_TARGET), }, } } @@ -1472,6 +1472,7 @@ async function minifyCSS(css: string, config: ResolvedConfig) { if (config.build.cssMinify === 'lightningcss') { const { code, warnings } = (await importLightningCSS()).transform({ ...config.css?.lightningcss, + targets: convertTargets(config.build.cssTarget), cssModules: undefined, filename: cssBundleName, code: Buffer.from(css), @@ -2257,11 +2258,17 @@ const esMap: Record = { const esRE = /es(\d{4})/ const versionRE = /\d/ +const convertTargetsCache = new Map< + string | string[], + LightningCSSOptions['targets'] +>() export const convertTargets = ( esbuildTarget: string | string[] | false, ): LightningCSSOptions['targets'] => { + if (!esbuildTarget) return {} + const cached = convertTargetsCache.get(esbuildTarget) + if (cached) return cached const targets: LightningCSSOptions['targets'] = {} - if (!esbuildTarget) return targets const entriesWithoutES = arraify(esbuildTarget).flatMap((e) => { const match = e.match(esRE) @@ -2294,5 +2301,6 @@ export const convertTargets = ( throw new Error(`Unsupported target "${entry}"`) } + convertTargetsCache.set(esbuildTarget, targets) return targets } diff --git a/packages/vite/src/types/lightningcss.d.ts b/packages/vite/src/types/lightningcss.d.ts index 305ffb30f1879b..98367f381283a2 100644 --- a/packages/vite/src/types/lightningcss.d.ts +++ b/packages/vite/src/types/lightningcss.d.ts @@ -9,7 +9,7 @@ import type { /** * Options are spread, so you can also use options that are not typed here like - * visitor that will impact to much the bundle size. + * visitor (not exposed because it would impact too much the bundle size) */ export type LightningCSSOptions = { targets?: Targets From 111868d3d88d2bc3bbeb2fdd90ef0d8af6cb8879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Thu, 15 Jun 2023 13:49:36 +0200 Subject: [PATCH 7/8] Bump dep in playground --- playground/css-lightningcss/package.json | 2 +- pnpm-lock.yaml | 92 +----------------------- 2 files changed, 3 insertions(+), 91 deletions(-) diff --git a/playground/css-lightningcss/package.json b/playground/css-lightningcss/package.json index 2d33ee8d5c36c2..8a9583a76564ad 100644 --- a/playground/css-lightningcss/package.json +++ b/playground/css-lightningcss/package.json @@ -9,6 +9,6 @@ "preview": "vite preview" }, "devDependencies": { - "lightningcss": "^1.20.0" + "lightningcss": "^1.21.0" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf1069463b39f6..5bebc5f20f08a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -542,8 +542,8 @@ importers: playground/css-lightningcss: devDependencies: lightningcss: - specifier: ^1.20.0 - version: 1.20.0 + specifier: ^1.21.0 + version: 1.21.0 playground/css-sourcemap: devDependencies: @@ -7291,15 +7291,6 @@ packages: type-check: 0.4.0 dev: true - /lightningcss-darwin-arm64@1.20.0: - resolution: {integrity: sha512-aYEohJTlzwB8URJaNiS57tMbjyLub0mYvxlxKQk8SZv+irXx6MoBWpDNQKKTS9gg1pGf/eAwjpa3BLAoCBsh1A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /lightningcss-darwin-arm64@1.21.0: resolution: {integrity: sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==} engines: {node: '>= 12.0.0'} @@ -7309,15 +7300,6 @@ packages: dev: true optional: true - /lightningcss-darwin-x64@1.20.0: - resolution: {integrity: sha512-cmMgY8FFWVaGgtift7eKKkHMqlz9O09/yTdlCXEDOeDP9yeo6vHOBTRP7ojb368kjw8Ew3l0L2uT1Gtx56eNkg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - /lightningcss-darwin-x64@1.21.0: resolution: {integrity: sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==} engines: {node: '>= 12.0.0'} @@ -7327,15 +7309,6 @@ packages: dev: true optional: true - /lightningcss-linux-arm-gnueabihf@1.20.0: - resolution: {integrity: sha512-/m+NDO1O6JCv7R9F0XWlXcintQHx4MPNU+kt8jZJO07LLdGwCfvjN31GVcwVPlStnnx/cU8uTTmax6g/Qu/whg==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - /lightningcss-linux-arm-gnueabihf@1.21.0: resolution: {integrity: sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==} engines: {node: '>= 12.0.0'} @@ -7345,15 +7318,6 @@ packages: dev: true optional: true - /lightningcss-linux-arm64-gnu@1.20.0: - resolution: {integrity: sha512-gtXoa6v0HvMRLbev6Hsef0+Q5He7NslB+Rs7G49Y5LUSdJeGIATEN+j8JzHC0DnxCsOGbEgGRmvtJzzYDkkluw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /lightningcss-linux-arm64-gnu@1.21.0: resolution: {integrity: sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==} engines: {node: '>= 12.0.0'} @@ -7363,15 +7327,6 @@ packages: dev: true optional: true - /lightningcss-linux-arm64-musl@1.20.0: - resolution: {integrity: sha512-Po7XpucM1kZnkiyd2BNwTExSDcZ8jm8uB9u+Sq44qjpkf5f75jreQwn3DQm9I1t5C6tB9HGt30HExMju9umJBQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /lightningcss-linux-arm64-musl@1.21.0: resolution: {integrity: sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==} engines: {node: '>= 12.0.0'} @@ -7381,15 +7336,6 @@ packages: dev: true optional: true - /lightningcss-linux-x64-gnu@1.20.0: - resolution: {integrity: sha512-8yR/fGNn/P0I+Lc3PK+VWPET/zdSpBfHFIG0DJ38TywMbItVKvnFvoTBwnIm4LqBz7g2G2dDexnNP95za2Ll8g==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /lightningcss-linux-x64-gnu@1.21.0: resolution: {integrity: sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==} engines: {node: '>= 12.0.0'} @@ -7399,15 +7345,6 @@ packages: dev: true optional: true - /lightningcss-linux-x64-musl@1.20.0: - resolution: {integrity: sha512-EmpJ+VkPZ8RACiB4m+l8TmapmE1W2UvJKDHE+ML/3Ihr9tRKUs3CibfnQTFZC8aSsrxgXagDAN+PgCDDhIyriA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - /lightningcss-linux-x64-musl@1.21.0: resolution: {integrity: sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==} engines: {node: '>= 12.0.0'} @@ -7417,15 +7354,6 @@ packages: dev: true optional: true - /lightningcss-win32-x64-msvc@1.20.0: - resolution: {integrity: sha512-BRdPvbq7Cc1qxAzp2emqWJHrqsEkf4ggxS29VOnxT7jhkdHKU+a26OVMjvm/OL0NH0ToNOZNAPvHMSexiEgBeA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - /lightningcss-win32-x64-msvc@1.21.0: resolution: {integrity: sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==} engines: {node: '>= 12.0.0'} @@ -7435,22 +7363,6 @@ packages: dev: true optional: true - /lightningcss@1.20.0: - resolution: {integrity: sha512-4bj8aP+Vi+or8Gwq/hknmicr4PmA8D9uL/3qY0N0daX5vYBMYERGI6Y93nzoeRgQMULq+gtrN/FvJYtH0xNN8g==} - engines: {node: '>= 12.0.0'} - dependencies: - detect-libc: 1.0.3 - optionalDependencies: - lightningcss-darwin-arm64: 1.20.0 - lightningcss-darwin-x64: 1.20.0 - lightningcss-linux-arm-gnueabihf: 1.20.0 - lightningcss-linux-arm64-gnu: 1.20.0 - lightningcss-linux-arm64-musl: 1.20.0 - lightningcss-linux-x64-gnu: 1.20.0 - lightningcss-linux-x64-musl: 1.20.0 - lightningcss-win32-x64-msvc: 1.20.0 - dev: true - /lightningcss@1.21.0: resolution: {integrity: sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==} engines: {node: '>= 12.0.0'} From 780723a825ff733c980ca2f208f7a02d97f88d17 Mon Sep 17 00:00:00 2001 From: patak Date: Thu, 15 Jun 2023 15:54:47 +0200 Subject: [PATCH 8/8] chore: avoid bumping pnpm lockfile version --- pnpm-lock.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5bebc5f20f08a7..a8212068b7216f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.1' +lockfileVersion: '6.0' settings: autoInstallPeers: false