@@ -6,12 +6,12 @@ import type { WebSocket } from 'ws'
66import type { WebSocketBrowserEvents , WebSocketBrowserHandlers } from '../types'
77import type { ParentBrowserProject } from './projectParent'
88import type { BrowserServerState } from './state'
9- import { existsSync , promises as fs } from 'node:fs'
9+ import { existsSync , promises as fs , readFileSync } from 'node:fs'
1010import { AutomockedModule , AutospiedModule , ManualMockedModule , RedirectedModule } from '@vitest/mocker'
1111import { ServerMockResolver } from '@vitest/mocker/node'
1212import { createBirpc } from 'birpc'
1313import { parse , stringify } from 'flatted'
14- import { dirname , join } from 'pathe'
14+ import { dirname , join , resolve } from 'pathe'
1515import { createDebugger , isFileServingAllowed , isValidApiRequest } from 'vitest/node'
1616import { 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 * s o u r c e M a p p i n g U R L = ( [ ^ \s ' " ] + ) \s * $ | \/ \* [ @ # ] \s * s o u r c e M a p p i n g U R L = [ ^ \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.
358390function cloneByOwnProperties ( value : any ) {
359391 // Clones the value's properties into a new Object. The simpler approach of
0 commit comments