From 74dc5967a6a3a2902b569f3d79d19ab4a673d299 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 21 Aug 2023 18:28:40 +0200 Subject: [PATCH] fix(vitest): correctly resolve optimizer status (#3992) --- docs/config/index.md | 10 ++++++--- packages/vitest/src/node/config.ts | 6 +++++ packages/vitest/src/node/plugins/index.ts | 13 +++-------- packages/vitest/src/node/plugins/optimizer.ts | 22 +++++++++++++++++++ packages/vitest/src/node/plugins/utils.ts | 22 ++++++++++++++----- packages/vitest/src/node/plugins/workspace.ts | 13 +++-------- packages/vitest/src/node/workspace.ts | 6 +++-- 7 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 packages/vitest/src/node/plugins/optimizer.ts diff --git a/docs/config/index.md b/docs/config/index.md index 54922d6b2d8d..d10f91451783 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -207,10 +207,14 @@ You will not be able to edit your `node_modules` code for debugging, since the c #### deps.optimizer.{mode}.enabled - **Type:** `boolean` -- **Default:** `true` +- **Default:** `true` if using >= Vite 4.3.2, `false` otherwise Enable dependency optimization. +::: warning +This option only works with Vite 4.3.2 and higher. +::: + #### deps.web - **Type:** `{ transformAssets?, ... }` @@ -227,7 +231,7 @@ Usually, files inside `node_modules` are externalized, but these options also af Should Vitest process assets (.png, .svg, .jpg, etc) files and resolve them like Vite does in the browser. -hese module will have a default export equal to the path to the asset, if no query is specified. +This module will have a default export equal to the path to the asset, if no query is specified. ::: warning At the moment, this option only works with [`experimentalVmThreads`](#experimentalvmthreads) pool. @@ -240,7 +244,7 @@ At the moment, this option only works with [`experimentalVmThreads`](#experiment Should Vitest process CSS (.css, .scss, .sass, etc) files and resolve them like Vite does in the browser. -If CSS files are disabled with [`css`](#css) options, this option will just silence `UNKNOWN_EXTENSION` errors. +If CSS files are disabled with [`css`](#css) options, this option will just silence `ERR_UNKNOWN_FILE_EXTENSION` errors. ::: warning At the moment, this option only works with [`experimentalVmThreads`](#experimentalvmthreads) pool. diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 51bf4e999ae7..b5f04b9f4887 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -137,6 +137,12 @@ export function resolveConfig( if (!resolved.deps.moduleDirectories.includes('/node_modules/')) resolved.deps.moduleDirectories.push('/node_modules/') + resolved.deps.optimizer ??= {} + resolved.deps.optimizer.ssr ??= {} + resolved.deps.optimizer.ssr.enabled ??= true + resolved.deps.optimizer.web ??= {} + resolved.deps.optimizer.web.enabled ??= true + resolved.deps.web ??= {} resolved.deps.web.transformAssets ??= true resolved.deps.web.transformCss ??= true diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 4cd4d47d6ee9..5004a8c87d22 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -12,8 +12,9 @@ import { GlobalSetupPlugin } from './globalSetup' import { CSSEnablerPlugin } from './cssEnabler' import { CoverageTransform } from './coverageTransform' import { MocksPlugin } from './mocks' -import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow, resolveOptimizerConfig } from './utils' +import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow } from './utils' import { VitestResolver } from './vitestResolver' +import { VitestOptimizer } from './optimizer' export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('test')): Promise { const userConfig = deepMerge({}, options) as UserConfig @@ -112,15 +113,6 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t } } - const webOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps, testConfig) - const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig) - - config.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || config.cacheDir - config.optimizeDeps = webOptimizer.optimizeDeps - config.ssr = { - optimizeDeps: ssrOptimizer.optimizeDeps, - } - return config }, async configResolved(viteConfig) { @@ -195,6 +187,7 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t : null, MocksPlugin(), VitestResolver(ctx), + VitestOptimizer(), ] .filter(notNullish) } diff --git a/packages/vitest/src/node/plugins/optimizer.ts b/packages/vitest/src/node/plugins/optimizer.ts new file mode 100644 index 000000000000..85cd3c36e17a --- /dev/null +++ b/packages/vitest/src/node/plugins/optimizer.ts @@ -0,0 +1,22 @@ +import type { Plugin } from 'vite' +import { resolveOptimizerConfig } from './utils' + +export function VitestOptimizer(): Plugin { + return { + name: 'vitest:normalize-optimizer', + config: { + order: 'post', + handler(viteConfig) { + const testConfig = viteConfig.test || {} + const webOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps, testConfig) + const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig) + + viteConfig.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || viteConfig.cacheDir + viteConfig.optimizeDeps = webOptimizer.optimizeDeps + viteConfig.ssr = { + optimizeDeps: ssrOptimizer.optimizeDeps, + } + }, + }, + } +} diff --git a/packages/vitest/src/node/plugins/utils.ts b/packages/vitest/src/node/plugins/utils.ts index 122d0eb78984..f9ca637ff39f 100644 --- a/packages/vitest/src/node/plugins/utils.ts +++ b/packages/vitest/src/node/plugins/utils.ts @@ -1,4 +1,3 @@ -import { builtinModules } from 'node:module' import { searchForWorkspaceRoot, version as viteVersion } from 'vite' import type { DepOptimizationOptions, ResolvedConfig, UserConfig as ViteConfig } from 'vite' import { dirname } from 'pathe' @@ -7,10 +6,10 @@ import type { DepsOptimizationOptions, InlineConfig } from '../../types' export function resolveOptimizerConfig(_testOptions: DepsOptimizationOptions | undefined, viteOptions: DepOptimizationOptions | undefined, testConfig: InlineConfig) { const testOptions = _testOptions || {} const newConfig: { cacheDir?: string; optimizeDeps: DepOptimizationOptions } = {} as any - const [major, minor] = viteVersion.split('.').map(Number) - const allowed = major >= 5 || (major === 4 && minor >= 3) + const [major, minor, fix] = viteVersion.split('.').map(Number) + const allowed = major >= 5 || (major === 4 && minor >= 4) || (major === 4 && minor === 3 && fix >= 2) if (!allowed && testOptions?.enabled === true) - console.warn(`Vitest: "deps.optimizer" is only available in Vite >= 4.3.0, current Vite version: ${viteVersion}`) + console.warn(`Vitest: "deps.optimizer" is only available in Vite >= 4.3.2, current Vite version: ${viteVersion}`) else // enable by default testOptions.enabled ??= true @@ -24,6 +23,17 @@ export function resolveOptimizerConfig(_testOptions: DepsOptimizationOptions | u } else { const cacheDir = testConfig.cache !== false ? testConfig.cache?.dir : null + const currentInclude = (testOptions.include || viteOptions?.include || []) + const exclude = [ + 'vitest', + // Ideally, we shouldn't optimize react in test mode, otherwise we need to optimize _every_ dependency that uses react. + 'react', + ...(testOptions.exclude || viteOptions?.exclude || []), + ] + const runtime = currentInclude.filter(n => n.endsWith('jsx-dev-runtime')) + exclude.push(...runtime) + + const include = (testOptions.include || viteOptions?.include || []).filter((n: string) => !exclude.includes(n)) newConfig.cacheDir = cacheDir ?? 'node_modules/.vitest' newConfig.optimizeDeps = { ...viteOptions, @@ -31,8 +41,8 @@ export function resolveOptimizerConfig(_testOptions: DepsOptimizationOptions | u noDiscovery: true, disabled: false, entries: [], - exclude: ['vitest', ...builtinModules, ...(testOptions.exclude || viteOptions?.exclude || [])], - include: (testOptions.include || viteOptions?.include || []).filter((n: string) => n !== 'vitest'), + exclude, + include, } } return newConfig diff --git a/packages/vitest/src/node/plugins/workspace.ts b/packages/vitest/src/node/plugins/workspace.ts index fef1b2299349..ea291ad41331 100644 --- a/packages/vitest/src/node/plugins/workspace.ts +++ b/packages/vitest/src/node/plugins/workspace.ts @@ -10,8 +10,9 @@ import { CSSEnablerPlugin } from './cssEnabler' import { SsrReplacerPlugin } from './ssrReplacer' import { GlobalSetupPlugin } from './globalSetup' import { MocksPlugin } from './mocks' -import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow, resolveOptimizerConfig } from './utils' +import { deleteDefineConfig, hijackVitePluginInject, resolveFsAllow } from './utils' import { VitestResolver } from './vitestResolver' +import { VitestOptimizer } from './optimizer' interface WorkspaceOptions extends UserWorkspaceConfig { root?: string @@ -95,15 +96,6 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp } } - const webOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.web, viteConfig.optimizeDeps, testConfig) - const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.optimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig) - - config.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || config.cacheDir - config.optimizeDeps = webOptimizer.optimizeDeps - config.ssr = { - optimizeDeps: ssrOptimizer.optimizeDeps, - } - return config }, configResolved(viteConfig) { @@ -132,5 +124,6 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp GlobalSetupPlugin(project, project.ctx.logger), MocksPlugin(), VitestResolver(project.ctx), + VitestOptimizer(), ] } diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index 52e4f0ec89ab..11aabfd263d9 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -285,6 +285,7 @@ export class WorkspaceProject { } getSerializableConfig() { + const optimizer = this.config.deps?.optimizer return deepMerge({ ...this.config, coverage: this.ctx.config.coverage, @@ -293,10 +294,10 @@ export class WorkspaceProject { ...this.config.deps, optimizer: { web: { - enabled: this.config.deps?.optimizer?.web?.enabled ?? true, + enabled: optimizer?.web?.enabled ?? true, }, ssr: { - enabled: this.config.deps?.optimizer?.ssr?.enabled ?? true, + enabled: optimizer?.ssr?.enabled ?? true, }, }, }, @@ -315,6 +316,7 @@ export class WorkspaceProject { }, inspect: this.ctx.config.inspect, inspectBrk: this.ctx.config.inspectBrk, + alias: [], }, this.ctx.configOverride || {} as any, ) as ResolvedConfig }