Skip to content

Commit

Permalink
fix(vitest): add inlined deps to ssr.noExternal so they are added to …
Browse files Browse the repository at this point in the history
…the module graph (#4945)
  • Loading branch information
sheremet-va committed Jan 12, 2024
1 parent 9ae9dac commit 1663f5c
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 15 deletions.
3 changes: 2 additions & 1 deletion packages/vite-node/src/server.ts
Expand Up @@ -65,7 +65,8 @@ export class ViteNodeServer {
}
else if (options.deps.inline !== true) {
options.deps.inline ??= []
options.deps.inline.push(...toArray(ssrOptions.noExternal))
const inline = options.deps.inline
options.deps.inline.push(...toArray(ssrOptions.noExternal).filter(dep => !inline.includes(dep)))
}
}
if (process.env.VITE_NODE_DEBUG_DUMP) {
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/config.ts
Expand Up @@ -8,6 +8,7 @@ export interface UserWorkspaceConfig extends ViteUserConfig {
// will import vitest declare test in module 'vite'
export { configDefaults, defaultInclude, defaultExclude, coverageConfigDefaults } from './defaults'
export { mergeConfig } from 'vite'
export { extraInlineDeps } from './constants'

export type { ConfigEnv, ViteUserConfig as UserConfig }
export type UserConfigFnObject = (env: ConfigEnv) => ViteUserConfig
Expand Down
9 changes: 9 additions & 0 deletions packages/vitest/src/constants.ts
Expand Up @@ -6,6 +6,15 @@ export const EXIT_CODE_RESTART = 43

export const API_PATH = '/__vitest_api__'

export const extraInlineDeps = [
/^(?!.*(?:node_modules)).*\.mjs$/,
/^(?!.*(?:node_modules)).*\.cjs\.js$/,
// Vite client
/vite\w*\/dist\/client\/env.mjs/,
// Nuxt
'@nuxt/test-utils',
]

export const CONFIG_NAMES = [
'vitest.config',
'vite.config',
Expand Down
11 changes: 1 addition & 10 deletions packages/vitest/src/node/config.ts
Expand Up @@ -3,7 +3,7 @@ import { normalize, relative, resolve } from 'pathe'
import c from 'picocolors'
import type { ResolvedConfig as ResolvedViteConfig } from 'vite'
import type { ApiConfig, ResolvedConfig, UserConfig, VitestRunMode } from '../types'
import { defaultBrowserPort, defaultPort } from '../constants'
import { defaultBrowserPort, defaultPort, extraInlineDeps } from '../constants'
import { benchmarkConfigDefaults, configDefaults } from '../defaults'
import { isCI, stdProvider, toArray } from '../utils'
import type { BuiltinPool } from '../types/pool-options'
Expand All @@ -13,15 +13,6 @@ import { RandomSequencer } from './sequencers/RandomSequencer'
import type { BenchmarkBuiltinReporters } from './reporters'
import { builtinPools } from './pool'

const extraInlineDeps = [
/^(?!.*(?:node_modules)).*\.mjs$/,
/^(?!.*(?:node_modules)).*\.cjs\.js$/,
// Vite client
/vite\w*\/dist\/client\/env.mjs/,
// Nuxt
'@nuxt/test-utils',
]

function resolvePath(path: string, root: string) {
return normalize(
resolveModule(path, { paths: [root] })
Expand Down
21 changes: 20 additions & 1 deletion packages/vitest/src/node/plugins/index.ts
Expand Up @@ -2,7 +2,7 @@ import type { UserConfig as ViteConfig, Plugin as VitePlugin } from 'vite'
import { relative } from 'pathe'
import { configDefaults } from '../../defaults'
import type { ResolvedConfig, UserConfig } from '../../types'
import { deepMerge, notNullish, removeUndefinedValues } from '../../utils'
import { deepMerge, notNullish, removeUndefinedValues, toArray } from '../../utils'
import { ensurePackageInstalled } from '../pkg'
import { resolveApiServerConfig } from '../config'
import { Vitest } from '../core'
Expand Down Expand Up @@ -103,6 +103,25 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t
},
}

// we want inline dependencies to be resolved by analyser plugin so module graph is populated correctly
if (viteConfig.ssr?.noExternal !== true) {
const inline = testConfig.server?.deps?.inline
if (inline === true) {
config.ssr = { noExternal: true }
}
else {
const noExternal = viteConfig.ssr?.noExternal
const noExternalArray = typeof noExternal !== 'undefined' ? toArray(noExternal) : undefined
// filter the same packages
const uniqueInline = inline && noExternalArray
? inline.filter(dep => !noExternalArray.includes(dep))
: inline
config.ssr = {
noExternal: uniqueInline,
}
}
}

// chokidar fsevents is unstable on macos when emitting "ready" event
if (process.platform === 'darwin' && process.env.VITE_TEST_WATCHER_DEBUG) {
config.server!.watch!.useFsEvents = false
Expand Down
123 changes: 120 additions & 3 deletions test/config/test/resolution.test.ts
@@ -1,10 +1,17 @@
import type { UserConfig } from 'vitest'
import type { UserConfig as ViteUserConfig } from 'vite'
import { describe, expect, it } from 'vitest'
import { createVitest } from 'vitest/node'
import { extraInlineDeps } from 'vitest/config'

async function config(cliOptions: UserConfig, configValue: UserConfig = {}) {
const vitest = await createVitest('test', { ...cliOptions, watch: false }, { test: configValue })
return vitest.config
async function vitest(cliOptions: UserConfig, configValue: UserConfig = {}, viteConfig: ViteUserConfig = {}) {
const vitest = await createVitest('test', { ...cliOptions, watch: false }, { ...viteConfig, test: configValue as any })
return vitest
}

async function config(cliOptions: UserConfig, configValue: UserConfig = {}, viteConfig: ViteUserConfig = {}) {
const v = await vitest(cliOptions, configValue, viteConfig)
return v.config
}

describe('correctly defines isolated flags', async () => {
Expand Down Expand Up @@ -102,3 +109,113 @@ describe('correctly defines isolated flags', async () => {
expect(c.isolate).toBe(true)
})
})

describe('correctly defines inline and noExternal flags', async () => {
it('both are true if inline is true', async () => {
const v = await vitest({}, {
server: {
deps: {
inline: true,
},
},
})
expect(v.vitenode.options.deps?.inline).toBe(true)
expect(v.vitenode.server.config.ssr.noExternal).toBe(true)
})

it('both are true if noExternal is true', async () => {
const v = await vitest({}, {}, {
ssr: {
noExternal: true,
},
})
expect(v.vitenode.options.deps?.inline).toBe(true)
expect(v.vitenode.server.config.ssr.noExternal).toBe(true)
})

it('inline are added to noExternal', async () => {
const regexp1 = /dep1/
const regexp2 = /dep2/

const v = await vitest({}, {
server: {
deps: {
inline: ['dep1', 'dep2', regexp1, regexp2],
},
},
})

expect(v.vitenode.options.deps?.inline).toEqual([
'dep1',
'dep2',
regexp1,
regexp2,
...extraInlineDeps,
])
expect(v.server.config.ssr.noExternal).toEqual([
'dep1',
'dep2',
regexp1,
regexp2,
...extraInlineDeps,
])
})

it('noExternal are added to inline', async () => {
const regexp1 = /dep1/
const regexp2 = /dep2/

const v = await vitest({}, {}, {
ssr: {
noExternal: ['dep1', 'dep2', regexp1, regexp2],
},
})

expect(v.vitenode.options.deps?.inline).toEqual([
...extraInlineDeps,
'dep1',
'dep2',
regexp1,
regexp2,
])
expect(v.server.config.ssr.noExternal).toEqual([
'dep1',
'dep2',
regexp1,
regexp2,
])
})

it('noExternal and inline don\'t have duplicates', async () => {
const regexp1 = /dep1/
const regexp2 = /dep2/

const v = await vitest({}, {
server: {
deps: {
inline: ['dep2', regexp1, 'dep3'],
},
},
}, {
ssr: {
noExternal: ['dep1', 'dep2', regexp1, regexp2],
},
})

expect(v.vitenode.options.deps?.inline).toEqual([
'dep2',
regexp1,
'dep3',
...extraInlineDeps,
'dep1',
regexp2,
])
expect(v.server.config.ssr.noExternal).toEqual([
'dep1',
'dep2',
regexp1,
regexp2,
'dep3',
])
})
})

0 comments on commit 1663f5c

Please sign in to comment.