Skip to content

Commit 57ae547

Browse files
authored
fix(browser): handle dependency stack traces with external source maps. Resolves: #9003 (#9016)
1 parent 5406e8e commit 57ae547

File tree

1 file changed

+35
-3
lines changed
  • packages/browser/src/node

1 file changed

+35
-3
lines changed

packages/browser/src/node/rpc.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ import type { WebSocket } from 'ws'
66
import type { WebSocketBrowserEvents, WebSocketBrowserHandlers } from '../types'
77
import type { ParentBrowserProject } from './projectParent'
88
import type { BrowserServerState } from './state'
9-
import { existsSync, promises as fs } from 'node:fs'
9+
import { existsSync, promises as fs, readFileSync } from 'node:fs'
1010
import { AutomockedModule, AutospiedModule, ManualMockedModule, RedirectedModule } from '@vitest/mocker'
1111
import { ServerMockResolver } from '@vitest/mocker/node'
1212
import { createBirpc } from 'birpc'
1313
import { parse, stringify } from 'flatted'
14-
import { dirname, join } from 'pathe'
14+
import { dirname, join, resolve } from 'pathe'
1515
import { createDebugger, isFileServingAllowed, isValidApiRequest } from 'vitest/node'
1616
import { WebSocketServer } from 'ws'
1717

@@ -204,7 +204,24 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject, defaultMocke
204204
},
205205
getBrowserFileSourceMap(id) {
206206
const mod = globalServer.vite.moduleGraph.getModuleById(id)
207-
return mod?.transformResult?.map
207+
const result = mod?.transformResult
208+
// this can happen for bundled dependencies in node_modules/.vite
209+
if (result && !result.map) {
210+
const sourceMapUrl = retrieveSourceMapURL(result.code)
211+
if (!sourceMapUrl) {
212+
return null
213+
}
214+
const filepathDir = dirname(id)
215+
const sourceMapPath = resolve(filepathDir, sourceMapUrl)
216+
try {
217+
const map = JSON.parse(readFileSync(sourceMapPath, 'utf-8'))
218+
return map
219+
}
220+
catch {
221+
return null
222+
}
223+
}
224+
return result?.map
208225
},
209226
cancelCurrentRun(reason) {
210227
vitest.cancelCurrentRun(reason)
@@ -354,6 +371,21 @@ export function setupBrowserRpc(globalServer: ParentBrowserProject, defaultMocke
354371
}
355372
}
356373

374+
function retrieveSourceMapURL(source: string): string | null {
375+
const re = /\/\/[@#]\s*sourceMappingURL=([^\s'"]+)\s*$|\/\*[@#]\s*sourceMappingURL=[^\s*'"]+\s*\*\/\s*$/gm
376+
// keep executing the search to find the *last* sourceMappingURL to avoid
377+
// picking up sourceMappingURLs from comments, strings, etc.
378+
let lastMatch, match
379+
// eslint-disable-next-line no-cond-assign
380+
while ((match = re.exec(source))) {
381+
lastMatch = match
382+
}
383+
if (!lastMatch) {
384+
return null
385+
}
386+
return lastMatch[1]
387+
}
388+
357389
// Serialization support utils.
358390
function cloneByOwnProperties(value: any) {
359391
// Clones the value's properties into a new Object. The simpler approach of

0 commit comments

Comments
 (0)