Skip to content

Commit aeb6720

Browse files
authored
fix(browser): don't redirect vitest in client environment (#10975)
1 parent 8ff9b9a commit aeb6720

8 files changed

Lines changed: 81 additions & 24 deletions

File tree

packages/browser/src/node/index.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -460,10 +460,13 @@ function resolveBrowserOptimizeDeps(
460460
'vitest/browser',
461461
'@vitest/browser/utils',
462462
'@vitest/browser/context',
463-
// this is a real module but cannot be specified in `optimizeDeps.include`
464-
// because `@vitest/browser` is only installed as a transitive dependency of
465-
// provider-specific packages such as `@vitest/browser-playwright`
463+
// these are real modules, but they cannot be specified in
464+
// `optimizeDeps.include`: `@vitest/browser` is only installed as a
465+
// transitive dependency of provider-specific packages such as
466+
// `@vitest/browser-playwright`, so the optimizer cannot resolve them
467+
// from the project root
466468
'@vitest/browser/locators',
469+
'@vitest/browser/client',
467470
'msw',
468471
'msw/browser',
469472
]
@@ -495,12 +498,12 @@ function resolveBrowserOptimizeDeps(
495498

496499
// Pre-bundle the vitest runtime so the browser fetches a few optimized
497500
// chunks instead of ~20 separately-served dist chunks (faster startup).
498-
// `vitest`, `vitest/internal/browser` and `@vitest/browser/client` are
499-
// optimized together in a single pass, so esbuild dedupes their shared
500-
// stateful chunks (the test collector, the runner, the RPC client) to a
501-
// single instance — preserving module identity between the test files'
502-
// `import 'vitest'` and the tester. Their transitive deps (@vitest/utils,
503-
// @vitest/spy, pathe, tinyrainbow, …) are inlined into these bundles.
501+
// `vitest` and `vitest/internal/browser` are optimized together in a single
502+
// pass, so esbuild dedupes their shared stateful chunks (the test collector,
503+
// the runner) to a single instance, preserving module identity between the
504+
// test files' `import 'vitest'` and the tester. Their transitive deps
505+
// (@vitest/utils, @vitest/spy, pathe, tinyrainbow, …) are inlined into
506+
// these bundles.
504507
const include = [
505508
'vitest > expect-type',
506509
'vitest > magic-string',
@@ -509,7 +512,6 @@ function resolveBrowserOptimizeDeps(
509512
'vitest',
510513
'vitest/internal/browser',
511514
'vitest/internal/traces',
512-
'@vitest/browser/client',
513515
]
514516

515517
const provider = testConfig.browser?.provider

packages/vitest/src/node/plugins/vitestResolver.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,26 @@ import { join, resolve } from 'pathe'
44
import { distDir } from '../../paths'
55

66
export function VitestProjectResolver(harness: PluginHarness): Plugin {
7+
let browserEnabled = false
78
const plugin: Plugin = {
89
name: 'vitest:resolve-root',
910
enforce: 'pre',
1011
config: {
1112
order: 'post',
12-
handler() {
13+
handler(config) {
14+
browserEnabled = !!config.test?.browser?.enabled
1315
return {
1416
base: '/',
1517
}
1618
},
1719
},
1820
async resolveId(id, _, { ssr }) {
1921
if (id === 'vitest' || id.startsWith('@vitest/') || id.startsWith('vitest/')) {
22+
// the browser pre-bundles vitest, and the optimizer's copy must win
23+
// so the tester and the test files share one module instance
24+
if (browserEnabled && this.environment?.name === 'client') {
25+
return
26+
}
2027
// always redirect the request to the root vitest plugin since
2128
// it will be the one used to run Vitest
2229
const resolved = await harness.getVitest().vite.pluginContainer.resolveId(id, undefined, {
@@ -32,12 +39,14 @@ export function VitestProjectResolver(harness: PluginHarness): Plugin {
3239

3340
export function VitestCoreResolver(): Plugin {
3441
let root: string
42+
let browserEnabled = false
3543
return {
3644
name: 'vitest:resolve-core',
3745
enforce: 'pre',
3846
config: {
3947
order: 'post',
40-
handler() {
48+
handler(config) {
49+
browserEnabled = !!config.test?.browser?.enabled
4150
return {
4251
base: '/',
4352
}
@@ -47,19 +56,12 @@ export function VitestCoreResolver(): Plugin {
4756
root = config.root
4857
},
4958
async resolveId(id) {
59+
// the browser pre-bundles vitest, and the optimizer's copy must win
60+
// so the tester and the test files share one module instance
61+
if (browserEnabled && this.environment?.name === 'client') {
62+
return
63+
}
5064
if (id === 'vitest') {
51-
// in environments that pre-bundle vitest (the browser `client`
52-
// environment), the optimizer's copy must win: the tester and the
53-
// test files have to share a single module instance, and returning
54-
// the dist file directly would bypass the optimized dep resolution
55-
if (this.environment?.config.optimizeDeps.include?.includes('vitest')) {
56-
const resolved = await this.resolve(id, join(root, 'index.html'), {
57-
skipSelf: true,
58-
})
59-
if (resolved) {
60-
return resolved
61-
}
62-
}
6365
return resolve(distDir, 'index.js')
6466
}
6567
if (id.startsWith('@vitest/') || id.startsWith('vitest/')) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('passes', () => {
4+
expect(1).toBe(1)
5+
})

test/browser/fixtures/dep-imports-vitest/node_modules/fake-browser-lib/index.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/browser/fixtures/dep-imports-vitest/node_modules/fake-browser-lib/package.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import 'fake-browser-lib'
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { fileURLToPath } from 'node:url'
2+
import { defineConfig } from 'vitest/config'
3+
import { instances, provider } from '../../settings'
4+
5+
export default defineConfig({
6+
cacheDir: fileURLToPath(new URL('./node_modules/.vite', import.meta.url)),
7+
test: {
8+
projects: [
9+
{
10+
test: {
11+
name: 'tester',
12+
setupFiles: ['./setup.ts'],
13+
browser: {
14+
enabled: true,
15+
provider,
16+
instances,
17+
},
18+
},
19+
},
20+
],
21+
},
22+
})
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// https://github.com/vitest-dev/vitest/issues/10944
2+
3+
import { expect, test } from 'vitest'
4+
import { instances, runBrowserTests } from './utils'
5+
6+
test('pre-bundled dependency shares the vitest runtime with the tester', async () => {
7+
const { stderr, stdout } = await runBrowserTests({
8+
root: './fixtures/dep-imports-vitest',
9+
reporters: 'verbose',
10+
})
11+
12+
expect(stderr).toReportNoErrors()
13+
instances.forEach(({ browser }) => {
14+
expect(stdout).toReportPassedTest('basic.test.ts', `tester (${browser})`)
15+
})
16+
})

0 commit comments

Comments
 (0)
Sponsor
SponsoredKunjungi sekarang
Promo