From cbf91ba712022bdb8fae5800eb1c5a093699fb5f Mon Sep 17 00:00:00 2001 From: Vladimir Date: Mon, 5 Dec 2022 18:19:40 +0100 Subject: [PATCH] fix: always apply vite ssr source maps (#2433) * fix: always apply vite ssr source maps * chore: remove non-vite-node source maps from code * test: source map test * chore: force esbuild to not generate inline source map * chore: fix failing text --- packages/vite-node/src/client.ts | 9 +++---- packages/vite-node/src/server.ts | 3 ++- packages/vite-node/src/source-map.ts | 30 +++++++++++++++++++++++ packages/vite-node/src/utils.ts | 15 ------------ packages/vitest/src/node/plugins/index.ts | 3 +++ packages/vitest/src/utils/source-map.ts | 2 ++ test/stacktraces/vite.config.ts | 3 +++ 7 files changed, 44 insertions(+), 21 deletions(-) diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index b2b9d6a7deba..dff47bafca41 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -6,6 +6,7 @@ import { isNodeBuiltin } from 'mlly' import createDebug from 'debug' import { isPrimitive, mergeSlashes, normalizeModuleId, normalizeRequestId, slash, toFilePath } from './utils' import type { HotContext, ModuleCache, ViteNodeRunnerOptions } from './types' +import { extractSourceMap } from './source-map' const debugExecute = createDebug('vite-node:client:execute') const debugNative = createDebug('vite-node:client:native') @@ -114,13 +115,11 @@ export class ModuleCacheMap extends Map { * Return parsed source map based on inlined source map of the module */ getSourceMap(id: string) { - const fsPath = this.normalizePath(id) - const cache = this.get(fsPath) + const cache = this.get(id) if (cache.map) return cache.map - const mapString = cache?.code?.match(/\/\/# sourceMappingURL=data:application\/json;charset=utf-8;base64,(.+)/)?.[1] - if (mapString) { - const map = JSON.parse(Buffer.from(mapString, 'base64').toString('utf-8')) + const map = cache.code && extractSourceMap(cache.code) + if (map) { cache.map = map return map } diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 66654be63d92..f92a2ae687e4 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -4,8 +4,9 @@ import type { TransformResult, ViteDevServer } from 'vite' import createDebug from 'debug' import type { DebuggerOptions, FetchResult, RawSourceMap, ViteNodeResolveId, ViteNodeServerOptions } from './types' import { shouldExternalize } from './externalize' -import { toArray, toFilePath, withInlineSourcemap } from './utils' +import { toArray, toFilePath } from './utils' import { Debugger } from './debug' +import { withInlineSourcemap } from './source-map' export * from './externalize' diff --git a/packages/vite-node/src/source-map.ts b/packages/vite-node/src/source-map.ts index d862544d38cd..ca5cce95d54b 100644 --- a/packages/vite-node/src/source-map.ts +++ b/packages/vite-node/src/source-map.ts @@ -1,10 +1,40 @@ import { install } from 'source-map-support' +import type { TransformResult } from 'vite' import type { RawSourceMap } from './types' interface InstallSourceMapSupportOptions { getSourceMap: (source: string) => RawSourceMap | null | undefined } +let SOURCEMAPPING_URL = 'sourceMa' +SOURCEMAPPING_URL += 'ppingURL' + +const VITE_NODE_SOURCEMAPPING_URL = `${SOURCEMAPPING_URL}=data:application/json;charset=utf-8;source=vite-node` +const VITE_NODE_SOURCEMAPPING_REGEXP = new RegExp(`//# ${VITE_NODE_SOURCEMAPPING_URL};base64,(.+)`) +const OTHER_SOURCE_MAP_REGEXP = new RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json[^,]+base64,(.+)`) + +export async function withInlineSourcemap(result: TransformResult) { + const { code, map } = result + + if (!map || code.includes(VITE_NODE_SOURCEMAPPING_URL)) + return result + + // to reduce the payload size, we only inline vite node source map, because it's also the only one we use + if (OTHER_SOURCE_MAP_REGEXP.test(code)) + result.code = code.replace(OTHER_SOURCE_MAP_REGEXP, '') + + result.code = `${code}\n\n//# ${VITE_NODE_SOURCEMAPPING_URL};base64,${Buffer.from(JSON.stringify(map), 'utf-8').toString('base64')}\n` + + return result +} + +export function extractSourceMap(code: string): RawSourceMap | null { + const mapString = code.match(VITE_NODE_SOURCEMAPPING_REGEXP)?.[1] + if (mapString) + return JSON.parse(Buffer.from(mapString, 'base64').toString('utf-8')) + return null +} + export function installSourcemapsSupport(options: InstallSourceMapSupportOptions) { install({ environment: 'node', diff --git a/packages/vite-node/src/utils.ts b/packages/vite-node/src/utils.ts index 2adb87a0451e..dd041e388b70 100644 --- a/packages/vite-node/src/utils.ts +++ b/packages/vite-node/src/utils.ts @@ -1,7 +1,6 @@ import { fileURLToPath, pathToFileURL } from 'url' import { existsSync } from 'fs' import { relative, resolve } from 'pathe' -import type { TransformResult } from 'vite' import { isNodeBuiltin } from 'mlly' import type { Arrayable, Nullable } from './types' @@ -88,20 +87,6 @@ export function toFilePath(id: string, root: string): string { : absolute } -let SOURCEMAPPING_URL = 'sourceMa' -SOURCEMAPPING_URL += 'ppingURL' - -export async function withInlineSourcemap(result: TransformResult) { - const { code, map } = result - - if (code.includes(`${SOURCEMAPPING_URL}=`)) - return result - if (map) - result.code = `${code}\n\n//# ${SOURCEMAPPING_URL}=data:application/json;charset=utf-8;base64,${Buffer.from(JSON.stringify(map), 'utf-8').toString('base64')}\n` - - return result -} - /** * Convert `Arrayable` to `Array` * diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index abe240ac341b..26c1e51c73f3 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -90,6 +90,9 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t open = '/' const config: ViteConfig = { + esbuild: { + sourcemap: 'external', + }, resolve: { // by default Vite resolves `module` field, which not always a native ESM module // setting this option can bypass that and fallback to cjs version diff --git a/packages/vitest/src/utils/source-map.ts b/packages/vitest/src/utils/source-map.ts index 7e0afe9d0c33..9c7584169854 100644 --- a/packages/vitest/src/utils/source-map.ts +++ b/packages/vitest/src/utils/source-map.ts @@ -6,6 +6,8 @@ export const lineSplitRE = /\r?\n/ const stackIgnorePatterns = [ 'node:internal', '/vitest/dist/', + '/vite-node/dist', + '/vite-node/src', '/vitest/src/', '/node_modules/chai/', '/node_modules/tinypool/', diff --git a/test/stacktraces/vite.config.ts b/test/stacktraces/vite.config.ts index 41bc8c0ff39f..f2e0a568e16b 100644 --- a/test/stacktraces/vite.config.ts +++ b/test/stacktraces/vite.config.ts @@ -1,6 +1,9 @@ import { defineConfig } from 'vite' export default defineConfig({ + esbuild: { + sourcemap: 'both', + }, test: { include: ['test/*.test.ts'], },