···381381382382If connection to the browser takes longer, the test suite will fail (default: `60_000`)
383383384384+### browser.dependencySourcemaps
385385+386386+- **CLI:** `--browser.dependencySourcemaps`
387387+- **Config:** [browser.dependencySourcemaps](/config/browser/dependencysourcemaps)
388388+389389+Serve sourcemaps of dependencies to the browser in headless runs, used by devtools when debugging into `node_modules`. Reported test errors are source-mapped either way. Use `--browser.dependencySourcemaps=false` to speed up test runs if you don't step into dependency code (default: `true`)
390390+384391### browser.trackUnhandledErrors
385392386393- **CLI:** `--browser.trackUnhandledErrors`
+21
docs/config/browser/dependencysourcemaps.md
···11+---
22+title: browser.dependencySourcemaps | Config
33+outline: deep
44+---
55+66+# browser.dependencySourcemaps
77+88+- **Type:** `boolean`
99+- **Default:** `true`
1010+1111+Serve sourcemaps of your dependencies (files in `node_modules`) to the browser during headless test runs.
1212+1313+These sourcemaps are used by browser devtools: with `dependencySourcemaps: false`, pausing inside dependency code shows the compiled code the browser actually runs instead of the dependency's original sources. If you don't debug into your dependencies this way, disabling them makes test runs faster: the server doesn't generate and inline the maps, and every browser tab downloads several times fewer bytes.
1414+1515+Reported test errors are not affected: when an error is thrown inside a pre-bundled dependency, Vitest maps its stack frames using the sourcemaps stored on disk even when this option is disabled. Frames from dependencies that are served without pre-bundling (for example, [linked packages](https://vite.dev/guide/dep-pre-bundling#monorepos-and-linked-dependencies)) that don't ship their own sourcemaps fall back to the position in the served code, which usually matches the original file.
1616+1717+Vitest never serves sourcemaps of its own pre-built modules in headless runs (unless [`--inspect`](/guide/cli#inspect) is used) — their frames are hidden from stack traces anyway. Sourcemaps of your own source files are always served.
1818+1919+::: tip
2020+If some of your workspace code resolves to a `node_modules` path (for example, with `resolve.preserveSymlinks`), set [`server.sourcemapIgnoreList`](https://vite.dev/config/server-options#server-sourcemapignorelist) to keep its sourcemaps even when this option is disabled.
2121+:::
+55-2
packages/browser/src/node/index.ts
···55import { MockerRegistry } from '@vitest/mocker'
66import { interceptorPlugin } from '@vitest/mocker/node'
77import { distClientRoot as uiClientRoot } from '@vitest/ui'
88-import { toArray } from '@vitest/utils/helpers'
88+import { cleanUrl, toArray } from '@vitest/utils/helpers'
99import { join, resolve } from 'pathe'
1010import sirv from 'sirv'
1111import c from 'tinyrainbow'
1212-import { isFileServingAllowed, isValidApiRequest, rolldownVersion, distDir as vitestDist } from 'vitest/node'
1212+import { isCSSRequest, isFileServingAllowed, isValidApiRequest, rolldownVersion, distDir as vitestDist } from 'vitest/node'
1313import { version } from '../../package.json'
1414import { distRoot } from './constants'
1515import { createOrchestratorMiddleware } from './middlewares/orchestratorMiddleware'
···347347 ...BrowserPlugin(contribution),
348348 // this plugin's `configureServer` is ignored since it's added through `applyToEnvironment`
349349 interceptorPlugin({ registry: mockerRegistry }),
350350+ {
351351+ name: 'vitest:browser:framework-sourcemaps',
352352+ enforce: 'post',
353353+ transform(code, id) {
354354+ const parentServer = contribution.parent as ParentBrowserProject | undefined
355355+ // In a headless run nothing can open devtools, so sourcemaps of
356356+ // Vitest's own pre-built modules are never consumed: their stack
357357+ // frames are filtered by stackIgnorePatterns. Generating and
358358+ // inlining these maps costs server CPU and multiplies the bytes
359359+ // the browser downloads by ~5 for every fresh browser context.
360360+ // Sourcemaps of user files and (by default) their dependencies are
361361+ // kept — they point error stacks and devtools at original sources.
362362+ if (
363363+ !parentServer
364364+ || !isHeadlessServer(parentServer)
365365+ || parentServer.vitest.config.inspector.enabled
366366+ ) {
367367+ return null
368368+ }
369369+ if (isCSSRequest(id)) {
370370+ return null
371371+ }
372372+ const path = cleanUrl(id)
373373+ if (path.startsWith(distRoot) || path.startsWith(vitestDist)) {
374374+ return { code, map: { mappings: '' } as any }
375375+ }
376376+ // users that never debug into node_modules can drop dependency
377377+ // sourcemaps entirely; `server.sourcemapIgnoreList` (default:
378378+ // node_modules) can opt paths back in even then, e.g. with
379379+ // `preserveSymlinks` where workspace code keeps its node_modules
380380+ // path and would be wrongly treated as a dependency
381381+ if (
382382+ parentServer.config.browser.dependencySourcemaps === false
383383+ && path.includes('/node_modules/')
384384+ && (parentServer.vite.config.server.sourcemapIgnoreList(path, path) ?? true)
385385+ ) {
386386+ return { code, map: { mappings: '' } as any }
387387+ }
388388+ return null
389389+ },
390390+ },
350391 ]
351392352393 return contribution
394394+}
395395+396396+function isHeadlessServer(parentServer: ParentBrowserProject): boolean {
397397+ if (!parentServer.config.browser.headless) {
398398+ return false
399399+ }
400400+ // sibling instances share this server (and its module graph cache, so a
401401+ // late-spawned instance would receive already-cached transforms) and can
402402+ // override `headless` — check the static instance options instead of the
403403+ // lazily populated `children` to stay deterministic across runs
404404+ const instances = parentServer.config.browser.instances ?? []
405405+ return instances.every(instance => instance.headless !== false)
353406}
354407355408function resolveBrowserOptimizeDeps(
+16-3
packages/browser/src/node/projectParent.ts
···6464 }
65656666 const result = this.vite.moduleGraph.getModuleById(id)?.transformResult
6767- // handle non-inline source map such as pre-bundled deps in node_modules/.vite
6868- if (result && !result.map) {
6969- const filePath = id.split('?')[0]
6767+ const filePath = id.split('?')[0]
6868+ // prefer the map stored on disk when the transform pipeline can't
6969+ // provide a usable one:
7070+ // - pre-bundled deps: the pipeline map resolves back into the
7171+ // optimizer cache, while the map esbuild wrote next to the file
7272+ // points at the real package sources
7373+ // - an empty `mappings` means the map was intentionally not served
7474+ // to the browser (`vitest:browser:framework-sourcemaps`), but disk
7575+ // is still the source of truth for error stack traces
7676+ if (
7777+ result && (
7878+ !result.map
7979+ || result.map.mappings === ''
8080+ || filePath.startsWith(this.vite.config.cacheDir)
8181+ )
8282+ ) {
7083 const extracted = extractSourcemapFromFile(result.code, filePath)
7184 this.sourceMapCache.set(id, extracted?.map)
7285 return extracted?.map
+3
packages/vitest/src/node/cli/cli-config.ts
···397397 description: 'If connection to the browser takes longer, the test suite will fail (default: `60_000`)',
398398 argument: '<timeout>',
399399 },
400400+ dependencySourcemaps: {
401401+ description: 'Serve sourcemaps of dependencies to the browser in headless runs, used by devtools when debugging into `node_modules`. Reported test errors are source-mapped either way. Use `--browser.dependencySourcemaps=false` to speed up test runs if you don\'t step into dependency code (default: `true`)',
402402+ },
400403 trackUnhandledErrors: {
401404 description: 'Control if Vitest catches uncaught exceptions so they can be reported (default: `true`)',
402405 },
+22
packages/vitest/src/node/types/browser.ts
···271271 screenshotFailures?: boolean
272272273273 /**
274274+ * Serve sourcemaps of your dependencies (files in `node_modules`) to the
275275+ * browser during headless test runs.
276276+ *
277277+ * These sourcemaps are used by browser devtools: when disabled, pausing
278278+ * inside dependency code shows the compiled code the browser actually
279279+ * runs instead of the dependency's original sources. If you don't debug
280280+ * into your dependencies this way, disabling them makes test runs faster:
281281+ * the server doesn't generate and inline the maps, and every browser tab
282282+ * downloads several times fewer bytes.
283283+ *
284284+ * Reported test errors are not affected: stack frames pointing into a
285285+ * pre-bundled dependency are mapped using the sourcemaps stored on disk
286286+ * even when this option is disabled.
287287+ *
288288+ * Vitest never serves sourcemaps of its own pre-built modules in headless
289289+ * runs (unless `--inspect` is used) — their frames are hidden from stack
290290+ * traces anyway. Sourcemaps of your own source files are always served.
291291+ * @default true
292292+ */
293293+ dependencySourcemaps?: boolean
294294+295295+ /**
274296 * Path to the index.html file that will be used to run tests.
275297 */
276298 testerHtmlPath?: string