Skip to content

Commit 898422b

Browse files
authoredJun 1, 2023
feat: support ssr optimizer (#3490)
1 parent b6c4a6c commit 898422b

File tree

7 files changed

+75
-84
lines changed

7 files changed

+75
-84
lines changed
 

‎packages/vitest/src/node/create.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export async function createVitest(mode: VitestRunMode, options: UserConfig, vit
2828
const server = await createServer(mergeConfig(config, mergeConfig(viteOverrides, { root: options.root })))
2929

3030
// optimizer needs .listen() to be called
31-
if (ctx.config.api?.port || ctx.config.deps?.experimentalOptimizer?.enabled)
31+
if (ctx.config.api?.port || ctx.config.deps?.experimentalOptimizer?.web?.enabled || ctx.config.deps?.experimentalOptimizer?.ssr?.enabled)
3232
await server.listen()
3333
else
3434
await server.pluginContainer.buildStart({})

‎packages/vitest/src/node/plugins/index.ts

+16-48
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { builtinModules } from 'node:module'
2-
import { version as viteVersion } from 'vite'
31
import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
42
import { relative } from 'pathe'
53
import { configDefaults } from '../../defaults'
@@ -14,6 +12,7 @@ import { GlobalSetupPlugin } from './globalSetup'
1412
import { CSSEnablerPlugin } from './cssEnabler'
1513
import { CoverageTransform } from './coverageTransform'
1614
import { MocksPlugin } from './mocks'
15+
import { resolveOptimizerConfig } from './utils'
1716

1817
export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('test')): Promise<VitePlugin[]> {
1918
const userConfig = deepMerge({}, options) as UserConfig
@@ -42,13 +41,13 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
4241
// preliminary merge of options to be able to create server options for vite
4342
// however to allow vitest plugins to modify vitest config values
4443
// this is repeated in configResolved where the config is final
45-
const preOptions = deepMerge(
44+
const testConfig = deepMerge(
4645
{} as UserConfig,
4746
configDefaults,
4847
options,
4948
removeUndefinedValues(viteConfig.test ?? {}),
5049
)
51-
preOptions.api = resolveApiServerConfig(preOptions)
50+
testConfig.api = resolveApiServerConfig(testConfig)
5251

5352
if (viteConfig.define) {
5453
delete viteConfig.define['import.meta.vitest']
@@ -90,8 +89,8 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
9089

9190
let open: string | boolean | undefined
9291

93-
if (preOptions.ui && preOptions.open)
94-
open = preOptions.uiBase ?? '/__vitest__/'
92+
if (testConfig.ui && testConfig.open)
93+
open = testConfig.uiBase ?? '/__vitest__/'
9594

9695
const config: ViteConfig = {
9796
root: viteConfig.test?.root || options.root,
@@ -105,24 +104,24 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
105104
// by default Vite resolves `module` field, which not always a native ESM module
106105
// setting this option can bypass that and fallback to cjs version
107106
mainFields: [],
108-
alias: preOptions.alias,
107+
alias: testConfig.alias,
109108
conditions: ['node'],
110109
// eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error
111110
// @ts-ignore we support Vite ^3.0, but browserField is available in Vite ^3.2
112111
browserField: false,
113112
},
114113
server: {
115-
...preOptions.api,
114+
...testConfig.api,
116115
watch: {
117-
ignored: preOptions.watchExclude,
116+
ignored: testConfig.watchExclude,
118117
},
119118
open,
120119
hmr: false,
121120
preTransformRequests: false,
122121
},
123122
}
124123

125-
const classNameStrategy = (typeof preOptions.css !== 'boolean' && preOptions.css?.modules?.classNameStrategy) || 'stable'
124+
const classNameStrategy = (typeof testConfig.css !== 'boolean' && testConfig.css?.modules?.classNameStrategy) || 'stable'
126125

127126
if (classNameStrategy !== 'scoped') {
128127
config.css ??= {}
@@ -135,45 +134,14 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
135134
}
136135
}
137136

138-
const optimizeConfig: Partial<ViteConfig> = {}
139-
const optimizer = preOptions.deps?.experimentalOptimizer
140-
const [major, minor] = viteVersion.split('.').map(Number)
141-
const allowed = major >= 5 || (major === 4 && minor >= 3)
142-
if (!allowed && optimizer?.enabled === true)
143-
console.warn(`Vitest: "deps.experimentalOptimizer" is only available in Vite >= 4.3.0, current Vite version: ${viteVersion}`)
144-
if (!allowed || optimizer?.enabled !== true) {
145-
optimizeConfig.cacheDir = undefined
146-
optimizeConfig.optimizeDeps = {
147-
// experimental in Vite >2.9.2, entries remains to help with older versions
148-
disabled: true,
149-
entries: [],
150-
}
151-
}
152-
else {
153-
const cacheDir = preOptions.cache !== false ? preOptions.cache?.dir : null
154-
optimizeConfig.cacheDir = cacheDir ?? 'node_modules/.vitest'
155-
const exclude = [
156-
'vitest',
157-
...builtinModules,
158-
...optimizer.exclude || [],
159-
...viteConfig.optimizeDeps?.exclude || [],
160-
]
161-
const include = [
162-
...optimizer.include || [],
163-
...viteConfig.optimizeDeps?.include || [],
164-
].filter((n: string) => !exclude.includes(n))
165-
166-
optimizeConfig.optimizeDeps = {
167-
...viteConfig.optimizeDeps,
168-
...optimizer,
169-
noDiscovery: true,
170-
disabled: false,
171-
entries: [],
172-
exclude,
173-
include,
174-
}
137+
const webOptimizer = resolveOptimizerConfig(testConfig.deps?.experimentalOptimizer?.web, viteConfig.optimizeDeps, testConfig)
138+
const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.experimentalOptimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig)
139+
140+
config.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || config.cacheDir
141+
config.optimizeDeps = webOptimizer.optimizeDeps
142+
config.ssr = {
143+
optimizeDeps: ssrOptimizer.optimizeDeps,
175144
}
176-
Object.assign(config, optimizeConfig)
177145

178146
return config
179147
},
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { builtinModules } from 'node:module'
2+
import { version as viteVersion } from 'vite'
3+
import type { DepOptimizationOptions } from 'vite'
4+
import type { DepsOptimizationOptions, InlineConfig } from '../../types'
5+
6+
export function resolveOptimizerConfig(testOptionc: DepsOptimizationOptions | undefined, viteOptions: DepOptimizationOptions | undefined, testConfig: InlineConfig) {
7+
const newConfig: { cacheDir?: string; optimizeDeps: DepOptimizationOptions } = {} as any
8+
const [major, minor] = viteVersion.split('.').map(Number)
9+
const allowed = major >= 5 || (major === 4 && minor >= 3)
10+
if (!allowed && testOptionc?.enabled === true)
11+
console.warn(`Vitest: "deps.optimizer" is only available in Vite >= 4.3.0, current Vite version: ${viteVersion}`)
12+
if (!allowed || testOptionc?.enabled !== true) {
13+
newConfig.cacheDir = undefined
14+
newConfig.optimizeDeps = {
15+
// experimental in Vite >2.9.2, entries remains to help with older versions
16+
disabled: true,
17+
entries: [],
18+
}
19+
}
20+
else {
21+
const cacheDir = testConfig.cache !== false ? testConfig.cache?.dir : null
22+
newConfig.cacheDir = cacheDir ?? 'node_modules/.vitest'
23+
newConfig.optimizeDeps = {
24+
...viteOptions,
25+
...testOptionc,
26+
noDiscovery: true,
27+
disabled: false,
28+
entries: [],
29+
exclude: ['vitest', ...builtinModules, ...(testOptionc.exclude || viteOptions?.exclude || [])],
30+
include: (testOptionc.include || viteOptions?.include || []).filter((n: string) => n !== 'vitest'),
31+
}
32+
}
33+
return newConfig
34+
}

‎packages/vitest/src/node/plugins/workspace.ts

+8-29
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import { builtinModules } from 'node:module'
21
import { dirname, relative } from 'pathe'
32
import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
4-
import { version as viteVersion } from 'vite'
53
import { configDefaults } from '../../defaults'
64
import { generateScopedClassName } from '../../integrations/css/css-modules'
75
import { deepMerge } from '../../utils/base'
@@ -12,6 +10,7 @@ import { CSSEnablerPlugin } from './cssEnabler'
1210
import { EnvReplacerPlugin } from './envReplacer'
1311
import { GlobalSetupPlugin } from './globalSetup'
1412
import { MocksPlugin } from './mocks'
13+
import { resolveOptimizerConfig } from './utils'
1514

1615
interface WorkspaceOptions extends UserWorkspaceConfig {
1716
root?: string
@@ -118,34 +117,14 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp
118117
}
119118
}
120119

121-
const optimizeConfig: Partial<ViteConfig> = {}
122-
const optimizer = testConfig.deps?.experimentalOptimizer
123-
const [major, minor] = viteVersion.split('.').map(Number)
124-
const allowed = major >= 5 || (major === 4 && minor >= 3)
125-
if (!allowed && optimizer?.enabled === true)
126-
console.warn(`Vitest: "deps.experimentalOptimizer" is only available in Vite >= 4.3.0, current Vite version: ${viteVersion}`)
127-
if (!allowed || optimizer?.enabled !== true) {
128-
optimizeConfig.cacheDir = undefined
129-
optimizeConfig.optimizeDeps = {
130-
// experimental in Vite >2.9.2, entries remains to help with older versions
131-
disabled: true,
132-
entries: [],
133-
}
134-
}
135-
else {
136-
const cacheDir = testConfig.cache !== false ? testConfig.cache?.dir : null
137-
optimizeConfig.cacheDir = cacheDir ?? 'node_modules/.vitest'
138-
optimizeConfig.optimizeDeps = {
139-
...viteConfig.optimizeDeps,
140-
...optimizer,
141-
noDiscovery: true,
142-
disabled: false,
143-
entries: [],
144-
exclude: ['vitest', ...builtinModules, ...(optimizer.exclude || viteConfig.optimizeDeps?.exclude || [])],
145-
include: (optimizer.include || viteConfig.optimizeDeps?.include || []).filter((n: string) => n !== 'vitest'),
146-
}
120+
const webOptimizer = resolveOptimizerConfig(testConfig.deps?.experimentalOptimizer?.web, viteConfig.optimizeDeps, testConfig)
121+
const ssrOptimizer = resolveOptimizerConfig(testConfig.deps?.experimentalOptimizer?.ssr, viteConfig.ssr?.optimizeDeps, testConfig)
122+
123+
config.cacheDir = webOptimizer.cacheDir || ssrOptimizer.cacheDir || config.cacheDir
124+
config.optimizeDeps = webOptimizer.optimizeDeps
125+
config.ssr = {
126+
optimizeDeps: ssrOptimizer.optimizeDeps,
147127
}
148-
Object.assign(config, optimizeConfig)
149128

150129
return config
151130
},

‎packages/vitest/src/node/workspace.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export async function initializeProject(workspacePath: string | number, ctx: Vit
5252
const server = await createServer(config)
5353

5454
// optimizer needs .listen() to be called
55-
if (ctx.config.api?.port || project.config.deps?.experimentalOptimizer?.enabled)
55+
if (ctx.config.api?.port || project.config.deps?.experimentalOptimizer?.web?.enabled || project.config.deps?.experimentalOptimizer?.ssr?.enabled)
5656
await server.listen()
5757
else
5858
await server.pluginContainer.buildStart({})
@@ -269,8 +269,13 @@ export class WorkspaceProject {
269269
reporters: [],
270270
deps: {
271271
...this.config.deps,
272-
experimentalOptimizer: {
273-
enabled: this.config.deps?.experimentalOptimizer?.enabled ?? false,
272+
optimizer: {
273+
web: {
274+
enabled: this.config.deps?.experimentalOptimizer?.web?.enabled ?? false,
275+
},
276+
ssr: {
277+
enabled: this.config.deps?.experimentalOptimizer?.ssr?.enabled ?? false,
278+
},
274279
},
275280
},
276281
snapshotOptions: {

‎packages/vitest/src/types/config.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,17 @@ interface SequenceOptions {
7070
hooks?: SequenceHooks
7171
}
7272

73+
export type DepsOptimizationOptions = Omit<DepOptimizationConfig, 'disabled' | 'noDiscovery'> & {
74+
enabled: boolean
75+
}
76+
7377
interface DepsOptions {
7478
/**
7579
* Enable dependency optimization. This can improve the performance of your tests.
7680
*/
77-
experimentalOptimizer?: Omit<DepOptimizationConfig, 'disabled' | 'noDiscovery'> & {
78-
enabled: boolean
81+
experimentalOptimizer?: {
82+
web?: DepsOptimizationOptions
83+
ssr?: DepsOptimizationOptions
7984
}
8085
/**
8186
* Externalize means that Vite will bypass the package to native Node.

‎packages/vitest/src/utils/base.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export function stdout(): NodeJS.WriteStream {
129129
}
130130

131131
export function getEnvironmentTransformMode(config: ResolvedConfig, environment: VitestEnvironment) {
132-
if (!config.deps?.experimentalOptimizer?.enabled)
132+
if (!config.deps?.experimentalOptimizer?.ssr?.enabled && !config.deps?.experimentalOptimizer?.web?.enabled)
133133
return undefined
134134
return (environment === 'happy-dom' || environment === 'jsdom') ? 'web' : 'ssr'
135135
}

0 commit comments

Comments
 (0)
Please sign in to comment.