From 3e731bb352ba41b94fca139d615c080c5d2fc5bb Mon Sep 17 00:00:00 2001 From: murugu-21 Date: Fri, 18 Sep 2026 14:31:46 +0530 Subject: [PATCH 1/4] fix(sourcemap): skip URL source roots when injecting sources content A URL sourceRoot cannot be realpath'd, so the relative sources were resolved against the cwd and flagged as escaping the package. Remote sources have no local file to inject; leave the map untouched. --- .../node/server/__tests__/sourcemap.spec.ts | 42 ++++++++++++++++++- packages/vite/src/node/server/sourcemap.ts | 10 +++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts index d71118e32790b2..ce93ef4b4ee8e9 100644 --- a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts +++ b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts @@ -1,6 +1,7 @@ -import { describe, expect, test } from 'vitest' +import { describe, expect, test, vi } from 'vitest' import { isWindows } from '../../../shared/utils' -import { getNodeModulesPackageRoot } from '../sourcemap' +import type { Logger } from '../../logger' +import { getNodeModulesPackageRoot, injectSourcesContent } from '../sourcemap' describe('getNodeModulesPackageRoot', () => { const cases = [ @@ -69,3 +70,40 @@ describe('getNodeModulesPackageRoot', () => { }) } }) + +describe('injectSourcesContent', () => { + const createLogger = () => ({ warnOnce: vi.fn() }) as unknown as Logger + + test('leaves maps with a remote sourceRoot alone', async () => { + const map: Parameters[0] = { + sources: ['index.ts'], + sourceRoot: 'https://raw.githubusercontent.com/fb55/domutils/abc123/src/', + } + const logger = createLogger() + + await injectSourcesContent( + map, + '/project/node_modules/domutils/lib/esm/index.js', + logger, + ) + + expect(logger.warnOnce).not.toHaveBeenCalled() + expect(map.sourcesContent).toBeUndefined() + }) + + test('warns for sources that resolve outside the package', async () => { + const map: Parameters[0] = { + sources: ['/outside/project/index.ts'], + } + const logger = createLogger() + + await injectSourcesContent( + map, + '/project/node_modules/foo/dist/index.js', + logger, + ) + + expect(logger.warnOnce).toHaveBeenCalledOnce() + expect(map.sourcesContent).toEqual([null]) + }) +}) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 41943dab731a3e..2417a3236248bd 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -9,6 +9,7 @@ import type { Logger } from '../logger' import { blankReplacer, createDebugger, + isExternalUrl, isParentDirectory, normalizePath, } from '../utils' @@ -71,6 +72,15 @@ export async function injectSourcesContent( file: string, logger: Logger, ): Promise { + // A `sourceRoot` can be a URL (e.g. raw.githubusercontent.com) for packages + // that want devtools to fetch the original sources from a remote host. There + // is nothing local to read, so leave the map untouched instead of resolving + // the relative `sources` against the cwd and warning that they escape the + // package. + if (map.sourceRoot && isExternalUrl(map.sourceRoot)) { + return + } + let sourceRootPromise: Promise const packageRoot = getNodeModulesPackageRoot(file) From f76466f60fe9b1d59ea989f0e2d9d23b0d829de1 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Thu, 24 Sep 2026 18:43:41 +0900 Subject: [PATCH 2/4] fix: handle sources field as well --- .../node/server/__tests__/sourcemap.spec.ts | 18 ++++++++++++++++++ packages/vite/src/node/server/sourcemap.ts | 1 + 2 files changed, 19 insertions(+) diff --git a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts index ce93ef4b4ee8e9..ad1ad6087fb428 100644 --- a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts +++ b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts @@ -91,6 +91,24 @@ describe('injectSourcesContent', () => { expect(map.sourcesContent).toBeUndefined() }) + test('does not inject content for remote sources', async () => { + const map: Parameters[0] = { + sources: [ + 'https://raw.githubusercontent.com/fb55/domutils/abc123/src/index.ts', + ], + } + const logger = createLogger() + + await injectSourcesContent( + map, + '/project/node_modules/domutils/lib/esm/index.js', + logger, + ) + + expect(logger.warnOnce).not.toHaveBeenCalled() + expect(map.sourcesContent).toEqual([]) + }) + test('warns for sources that resolve outside the package', async () => { const map: Parameters[0] = { sources: ['/outside/project/index.ts'], diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 2417a3236248bd..57908298afedea 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -92,6 +92,7 @@ export async function injectSourcesContent( if ( sourcesContent[index] == null && sourcePath && + !isExternalUrl(sourcePath) && !virtualSourceRE.test(sourcePath) ) { sourcesContentPromises.push( From decb8212bdf77c0c2e7bdb4aaeafc3c6a84a4c50 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Thu, 24 Sep 2026 18:44:15 +0900 Subject: [PATCH 3/4] chore: remove obvious comment --- packages/vite/src/node/server/sourcemap.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 57908298afedea..4fc4821601767f 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -72,11 +72,6 @@ export async function injectSourcesContent( file: string, logger: Logger, ): Promise { - // A `sourceRoot` can be a URL (e.g. raw.githubusercontent.com) for packages - // that want devtools to fetch the original sources from a remote host. There - // is nothing local to read, so leave the map untouched instead of resolving - // the relative `sources` against the cwd and warning that they escape the - // package. if (map.sourceRoot && isExternalUrl(map.sourceRoot)) { return } From ff828969e49ac8a0e15707b336df2376ae2e7382 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Thu, 24 Sep 2026 18:47:42 +0900 Subject: [PATCH 4/4] test: tweak --- .../node/server/__tests__/sourcemap.spec.ts | 30 ++++++++++++------- packages/vite/src/node/server/sourcemap.ts | 2 +- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts index ad1ad6087fb428..a79d5ef8995ce9 100644 --- a/packages/vite/src/node/server/__tests__/sourcemap.spec.ts +++ b/packages/vite/src/node/server/__tests__/sourcemap.spec.ts @@ -1,7 +1,11 @@ import { describe, expect, test, vi } from 'vitest' import { isWindows } from '../../../shared/utils' -import type { Logger } from '../../logger' -import { getNodeModulesPackageRoot, injectSourcesContent } from '../sourcemap' +import { createLogger } from '../../logger' +import { + getNodeModulesPackageRoot, + injectSourcesContent, + type SourceMapLike, +} from '../sourcemap' describe('getNodeModulesPackageRoot', () => { const cases = [ @@ -72,14 +76,18 @@ describe('getNodeModulesPackageRoot', () => { }) describe('injectSourcesContent', () => { - const createLogger = () => ({ warnOnce: vi.fn() }) as unknown as Logger + function createMockLogger() { + const logger = createLogger() + logger.warnOnce = vi.fn() + return logger + } test('leaves maps with a remote sourceRoot alone', async () => { - const map: Parameters[0] = { + const map: SourceMapLike = { sources: ['index.ts'], sourceRoot: 'https://raw.githubusercontent.com/fb55/domutils/abc123/src/', } - const logger = createLogger() + const logger = createMockLogger() await injectSourcesContent( map, @@ -92,12 +100,12 @@ describe('injectSourcesContent', () => { }) test('does not inject content for remote sources', async () => { - const map: Parameters[0] = { + const map: SourceMapLike = { sources: [ 'https://raw.githubusercontent.com/fb55/domutils/abc123/src/index.ts', ], } - const logger = createLogger() + const logger = createMockLogger() await injectSourcesContent( map, @@ -106,14 +114,14 @@ describe('injectSourcesContent', () => { ) expect(logger.warnOnce).not.toHaveBeenCalled() - expect(map.sourcesContent).toEqual([]) + expect(map.sourcesContent).toStrictEqual([]) }) test('warns for sources that resolve outside the package', async () => { - const map: Parameters[0] = { + const map: SourceMapLike = { sources: ['/outside/project/index.ts'], } - const logger = createLogger() + const logger = createMockLogger() await injectSourcesContent( map, @@ -122,6 +130,6 @@ describe('injectSourcesContent', () => { ) expect(logger.warnOnce).toHaveBeenCalledOnce() - expect(map.sourcesContent).toEqual([null]) + expect(map.sourcesContent).toStrictEqual([null]) }) }) diff --git a/packages/vite/src/node/server/sourcemap.ts b/packages/vite/src/node/server/sourcemap.ts index 4fc4821601767f..5ee14c663153be 100644 --- a/packages/vite/src/node/server/sourcemap.ts +++ b/packages/vite/src/node/server/sourcemap.ts @@ -50,7 +50,7 @@ export function getNodeModulesPackageRoot( // prefixes used for special handling in esbuildDepPlugin. const virtualSourceRE = /^(?:dep:|browser-external:|virtual:)|\0/ -interface SourceMapLike { +export interface SourceMapLike { sources: string[] sourcesContent?: (string | null)[] sourceRoot?: string