From 6b1b4e68bf25c0fc58596bc67b1ae582199f4545 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 11 Apr 2023 13:22:54 +0200 Subject: [PATCH] fix: use relative paths in source map's "sources" field (#3177) --- packages/vite-node/src/server.ts | 16 ++++++++-------- packages/vite-node/src/source-map.ts | 20 +++++++++++--------- packages/vitest/src/typecheck/collect.ts | 2 +- packages/vitest/src/typecheck/typechecker.ts | 4 ++-- test/vite-node/test/server.test.ts | 2 +- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 804147591530..bf4a2885056a 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -119,11 +119,11 @@ export class ViteNodeServer { return this.fetchPromiseMap.get(id)! } - async transformRequest(id: string) { + async transformRequest(id: string, filepath = id) { // reuse transform for concurrent requests if (!this.transformPromiseMap.has(id)) { this.transformPromiseMap.set(id, - this._transformRequest(id) + this._transformRequest(id, filepath) .finally(() => { this.transformPromiseMap.delete(id) }), @@ -177,7 +177,7 @@ export class ViteNodeServer { } else { const start = performance.now() - const r = await this._transformRequest(id, transformMode) + const r = await this._transformRequest(id, filePath, transformMode) duration = performance.now() - start result = { code: r?.code, map: r?.map as any } } @@ -191,15 +191,15 @@ export class ViteNodeServer { return result } - protected async processTransformResult(id: string, result: TransformResult) { - const mod = this.server.moduleGraph.getModuleById(id) + protected async processTransformResult(filepath: string, result: TransformResult) { + const mod = this.server.moduleGraph.getModuleById(filepath) return withInlineSourcemap(result, { - filepath: mod?.file || id, + filepath: mod?.file || filepath, root: this.server.config.root, }) } - private async _transformRequest(id: string, customTransformMode?: 'web' | 'ssr') { + private async _transformRequest(id: string, filepath: string, customTransformMode?: 'web' | 'ssr') { debugRequest(id) let result: TransformResult | null = null @@ -225,7 +225,7 @@ export class ViteNodeServer { const sourcemap = this.options.sourcemap ?? 'inline' if (sourcemap === 'inline' && result && !id.includes('node_modules')) - result = await this.processTransformResult(id, result) + result = await this.processTransformResult(filepath, result) if (this.options.debug?.dumpModules) await this.debugger?.dumpFile(id, result) diff --git a/packages/vite-node/src/source-map.ts b/packages/vite-node/src/source-map.ts index 96d3ec12cff7..4adccd27a2d5 100644 --- a/packages/vite-node/src/source-map.ts +++ b/packages/vite-node/src/source-map.ts @@ -1,5 +1,5 @@ import type { TransformResult } from 'vite' -import { dirname, isAbsolute, join, resolve } from 'pathe' +import { dirname, isAbsolute, relative, resolve } from 'pathe' import type { EncodedSourceMap } from '@jridgewell/trace-mapping' import { install } from './source-map-handler' @@ -24,17 +24,19 @@ export function withInlineSourcemap(result: TransformResult, options: { if (!map || code.includes(VITE_NODE_SOURCEMAPPING_SOURCE)) return result - // sources path from `ViteDevServer` may be not a valid filesystem path (eg. /src/main.js), - // so we try to convert them to valid filesystem path map.sources = map.sources?.map((source) => { if (!source) return source - // make source absolute again, it might not be relative to the root, but to the "source root" - // https://github.com/bmeurer/vite/blob/172c3e36226ec4bdf2c9d5f8fa84310bde3fec54/packages/vite/src/node/server/transformRequest.ts#L281 - if (!isAbsolute(source)) - return resolve(dirname(options.filepath), source) - if (!source.startsWith(options.root)) - return join(options.root, source) + // sometimes files here are absolute, + // but they are considered absolute to the server url, not the file system + // this is a bug in Vite + // all files should be either absolute to the file system or relative to the source map file + if (isAbsolute(source)) { + const actualPath = (!source.startsWith(options.root) && source.startsWith('/')) + ? resolve(options.root, source.slice(1)) + : source + return relative(dirname(options.filepath), actualPath) + } return source }) diff --git a/packages/vitest/src/typecheck/collect.ts b/packages/vitest/src/typecheck/collect.ts index eae6d4a73af0..97e079b44a0a 100644 --- a/packages/vitest/src/typecheck/collect.ts +++ b/packages/vitest/src/typecheck/collect.ts @@ -40,7 +40,7 @@ export interface FileInformation { } export async function collectTests(ctx: WorkspaceProject, filepath: string): Promise { - const request = await ctx.vitenode.transformRequest(filepath) + const request = await ctx.vitenode.transformRequest(filepath, filepath) if (!request) return null const ast = parseAst(request.code, { diff --git a/packages/vitest/src/typecheck/typechecker.ts b/packages/vitest/src/typecheck/typechecker.ts index 5ba697721840..a9a0670c3c92 100644 --- a/packages/vitest/src/typecheck/typechecker.ts +++ b/packages/vitest/src/typecheck/typechecker.ts @@ -1,7 +1,7 @@ import { rm } from 'node:fs/promises' import type { ExecaChildProcess } from 'execa' import { execa } from 'execa' -import { extname, resolve } from 'pathe' +import { basename, extname, resolve } from 'pathe' import { SourceMapConsumer } from 'source-map' import { getTasks } from '../utils' import { ensurePackageInstalled } from '../node/pkg' @@ -132,7 +132,7 @@ export class Typechecker { const processedPos = mapConsumer?.generatedPositionFor({ line: originalError.line, column: originalError.column, - source: path, + source: basename(path), }) || originalError const line = processedPos.line ?? originalError.line const column = processedPos.column ?? originalError.column diff --git a/test/vite-node/test/server.test.ts b/test/vite-node/test/server.test.ts index 26fb4e4509c9..7020d91f76b3 100644 --- a/test/vite-node/test/server.test.ts +++ b/test/vite-node/test/server.test.ts @@ -42,6 +42,6 @@ describe('server works correctly', async () => { const sourceMap = extractSourceMap(fetchResult.code!) // expect got sourcemap source in a valid filesystem path - expect(sourceMap?.sources[0]).toBe(resolve(__dirname, '../src/foo.js')) + expect(sourceMap?.sources[0]).toBe('foo.js') }) })