From d040d343edffabbf25b1a24d6b80b4b3d52a53d6 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 31 Oct 2022 18:20:08 +0100 Subject: [PATCH 01/14] fix: fix stack trace in errors and console --- packages/coverage-c8/src/provider.ts | 7 +--- packages/vite-node/package.json | 7 ++++ packages/vite-node/rollup.config.js | 15 +++++---- packages/vite-node/src/cli.ts | 5 +++ packages/vite-node/src/client.ts | 9 +++-- packages/vite-node/src/server.ts | 6 ++++ packages/vite-node/src/source-map.ts | 23 +++++++++++++ packages/vite-node/src/types.ts | 1 + packages/vitest/package.json | 2 +- packages/vitest/src/api/setup.ts | 6 ---- packages/vitest/src/node/error.ts | 4 +-- packages/vitest/src/node/reporters/json.ts | 3 +- packages/vitest/src/runtime/setup.ts | 22 ++++++++++-- packages/vitest/src/utils/source-map.ts | 39 ++++++---------------- pnpm-lock.yaml | 14 ++++++-- 15 files changed, 98 insertions(+), 65 deletions(-) create mode 100644 packages/vite-node/src/source-map.ts diff --git a/packages/coverage-c8/src/provider.ts b/packages/coverage-c8/src/provider.ts index 23f2c65a6bb2..bad4bc80bca8 100644 --- a/packages/coverage-c8/src/provider.ts +++ b/packages/coverage-c8/src/provider.ts @@ -80,11 +80,6 @@ export class C8CoverageProvider implements CoverageProvider { } })) - // This is a magic number. It corresponds to the amount of code - // that we add in packages/vite-node/src/client.ts:114 (vm.runInThisContext) - // TODO: Include our transformations in sourcemaps - const offset = 224 - report._getSourceMap = (coverage: Profiler.ScriptCoverage) => { const path = _url.pathToFileURL(coverage.url.split('?')[0]).href const data = sourceMapMeta[path] @@ -96,7 +91,7 @@ export class C8CoverageProvider implements CoverageProvider { sourceMap: { sourcemap: data.map, }, - source: Array(offset).fill('.').join('') + data.source, + source: data.source, } } diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index cd2943cee05e..96ce0e85ba50 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -39,6 +39,11 @@ "types": "./dist/hmr.d.ts", "require": "./dist/hmr.cjs", "import": "./dist/hmr.mjs" + }, + "./source-map": { + "types": "./dist/source-map.d.ts", + "require": "./dist/source-map.cjs", + "import": "./dist/source-map.mjs" } }, "main": "./dist/index.mjs", @@ -73,10 +78,12 @@ "debug": "^4.3.4", "mlly": "^0.5.16", "pathe": "^0.2.0", + "source-map-support": "^0.5.21", "vite": "^3.0.0" }, "devDependencies": { "@types/debug": "^4.1.7", + "@types/source-map-support": "^0.5.6", "cac": "^6.7.14", "picocolors": "^1.0.0", "rollup": "^2.79.1" diff --git a/packages/vite-node/rollup.config.js b/packages/vite-node/rollup.config.js index 8f1e22adc04e..37c8e2ad8d0f 100644 --- a/packages/vite-node/rollup.config.js +++ b/packages/vite-node/rollup.config.js @@ -9,13 +9,14 @@ import { defineConfig } from 'rollup' import pkg from './package.json' const entries = { - index: 'src/index.ts', - server: 'src/server.ts', - types: 'src/types.ts', - client: 'src/client.ts', - utils: 'src/utils.ts', - cli: 'src/cli.ts', - hmr: 'src/hmr/index.ts', + 'index': 'src/index.ts', + 'server': 'src/server.ts', + 'types': 'src/types.ts', + 'client': 'src/client.ts', + 'utils': 'src/utils.ts', + 'cli': 'src/cli.ts', + 'hmr': 'src/hmr/index.ts', + 'source-map': 'src/source-map.ts', } const external = [ diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index e75ae1588ccd..e244675990e9 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -7,6 +7,7 @@ import { ViteNodeRunner } from './client' import type { ViteNodeServerOptions } from './types' import { toArray } from './utils' import { createHotContext, handleMessage, viteNodeHmrPlugin } from './hmr' +import { installViteNodeSourcemaps } from './source-map' const cli = cac('vite-node') @@ -58,6 +59,10 @@ async function run(files: string[], options: CliOptions = {}) { const node = new ViteNodeServer(server, serverOptions) + installViteNodeSourcemaps({ + getSourceMap: source => node.getSourceMap(source), + }) + const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index b9456f7da684..0ce8f6bf2c70 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -290,10 +290,6 @@ export class ViteNodeRunner { }) } - // Be careful when changing this - // changing context will change amount of code added on line :114 (vm.runInThisContext) - // this messes up sourcemaps for coverage - // adjust `offset` variable in packages/vitest/src/integrations/coverage/c8.ts#86 if you do change this const context = this.prepareContext({ // esm transformed by Vite __vite_ssr_import__: request, @@ -318,9 +314,12 @@ export class ViteNodeRunner { transformed = transformed.replace(/^\#\!.*/, s => ' '.repeat(s.length)) // add 'use strict' since ESM enables it by default - const fn = vm.runInThisContext(`'use strict';async (${Object.keys(context).join(',')})=>{{${transformed}\n}}`, { + const codeDefinition = `'use strict';async (${Object.keys(context).join(',')})=>{{` + const code = `${codeDefinition}${transformed}\n}}` + const fn = vm.runInThisContext(code, { filename: fsPath, lineOffset: 0, + columnOffset: -codeDefinition.length, }) await fn(...Object.values(context)) diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index 2302b31726e7..c4920962729f 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -73,6 +73,12 @@ export class ViteNodeServer { return this.server.pluginContainer.resolveId(id, importer, { ssr: mode === 'ssr' }) } + getSourceMap(source: string) { + const ssrTransformResult = this.server.moduleGraph.getModuleById(source)?.ssrTransformResult + const fetchResult = this.fetchCache.get(source)?.result + return (fetchResult?.map || ssrTransformResult?.map) as unknown as RawSourceMap | null + } + async fetchModule(id: string): Promise { // reuse transform for concurrent requests if (!this.fetchPromiseMap.has(id)) { diff --git a/packages/vite-node/src/source-map.ts b/packages/vite-node/src/source-map.ts new file mode 100644 index 000000000000..b1438df029f9 --- /dev/null +++ b/packages/vite-node/src/source-map.ts @@ -0,0 +1,23 @@ +import { install } from 'source-map-support' +import type { RawSourceMap } from './types' + +interface InstallSourceMapSupportOptions { + getSourceMap: (source: string) => RawSourceMap | null | undefined +} + +export function installViteNodeSourcemaps(options: InstallSourceMapSupportOptions) { + install({ + environment: 'node', + handleUncaughtExceptions: false, + retrieveSourceMap(source) { + const map = options.getSourceMap(source) + if (map) { + return { + url: source, + map, + } + } + return null + }, + }) +} diff --git a/packages/vite-node/src/types.ts b/packages/vite-node/src/types.ts index b6581a641786..c94cfcfd75a9 100644 --- a/packages/vite-node/src/types.ts +++ b/packages/vite-node/src/types.ts @@ -45,6 +45,7 @@ export interface ModuleCache { promise?: Promise exports?: any code?: string + map?: RawSourceMap /** * Module ids that imports this module */ diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 17a8308e3378..4d074a49d508 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -111,6 +111,7 @@ "chai": "^4.3.6", "debug": "^4.3.4", "local-pkg": "^0.4.2", + "source-map-js": "^1.0.2", "strip-literal": "^0.4.2", "tinybench": "^2.3.1", "tinypool": "^0.3.0", @@ -152,7 +153,6 @@ "pretty-format": "^27.5.1", "prompts": "^2.4.2", "rollup": "^2.79.1", - "source-map-js": "^1.0.2", "strip-ansi": "^7.0.1", "typescript": "^4.8.4", "vite-node": "workspace:*", diff --git a/packages/vitest/src/api/setup.ts b/packages/vitest/src/api/setup.ts index eca3a1be9212..905bbf3c244c 100644 --- a/packages/vitest/src/api/setup.ts +++ b/packages/vitest/src/api/setup.ts @@ -8,7 +8,6 @@ import type { ModuleNode } from 'vite' import { API_PATH } from '../constants' import type { Vitest } from '../node' import type { File, ModuleGraphData, Reporter, TaskResultPack, UserConsoleLog } from '../types' -import { interpretSourcePos, parseStacktrace } from '../utils/source-map' import type { TransformResultWithSource, WebSocketEvents, WebSocketHandlers } from './types' export function setup(ctx: Vitest) { @@ -154,11 +153,6 @@ class WebSocketReporter implements Reporter { if (this.clients.size === 0) return - await Promise.all(packs.map(async (i) => { - if (i[1]?.error) - await interpretSourcePos(parseStacktrace(i[1].error as any), this.ctx) - })) - this.clients.forEach((client) => { client.onTaskUpdate?.(packs) }) diff --git a/packages/vitest/src/node/error.ts b/packages/vitest/src/node/error.ts index 5ab9ff874b97..856123847197 100644 --- a/packages/vitest/src/node/error.ts +++ b/packages/vitest/src/node/error.ts @@ -4,7 +4,7 @@ import { join, normalize, relative } from 'pathe' import c from 'picocolors' import cliTruncate from 'cli-truncate' import type { ErrorWithDiff, ParsedStack, Position } from '../types' -import { interpretSourcePos, lineSplitRE, parseStacktrace, posToNumber } from '../utils/source-map' +import { lineSplitRE, parseStacktrace, posToNumber } from '../utils/source-map' import { F_POINTER } from '../utils/figures' import { stringify } from '../integrations/chai/jest-matcher-utils' import type { Vitest } from './core' @@ -45,8 +45,6 @@ export async function printError(error: unknown, ctx: Vitest, options: PrintErro const stacks = parseStacktrace(e, fullStack) - await interpretSourcePos(stacks, ctx) - const nearest = stacks.find(stack => ctx.server.moduleGraph.getModuleById(stack.file) && existsSync(stack.file), diff --git a/packages/vitest/src/node/reporters/json.ts b/packages/vitest/src/node/reporters/json.ts index 2a60d800401a..bd5d8318dcbf 100644 --- a/packages/vitest/src/node/reporters/json.ts +++ b/packages/vitest/src/node/reporters/json.ts @@ -4,7 +4,7 @@ import type { Vitest } from '../../node' import type { File, Reporter, Suite, Task, TaskState } from '../../types' import { getSuites, getTests } from '../../utils' import { getOutputFile } from '../../utils/config-helpers' -import { interpretSourcePos, parseStacktrace } from '../../utils/source-map' +import { parseStacktrace } from '../../utils/source-map' // for compatibility reasons, the reporter produces a JSON similar to the one produced by the Jest JSON reporter // the following types are extracted from the Jest repository (and simplified) @@ -186,7 +186,6 @@ export class JsonReporter implements Reporter { return const stack = parseStacktrace(error) - await interpretSourcePos(stack, this.ctx) const frame = stack[stack.length - 1] if (!frame) return diff --git a/packages/vitest/src/runtime/setup.ts b/packages/vitest/src/runtime/setup.ts index c86501828557..98b8d93e4111 100644 --- a/packages/vitest/src/runtime/setup.ts +++ b/packages/vitest/src/runtime/setup.ts @@ -1,3 +1,4 @@ +import { installViteNodeSourcemaps } from 'vite-node/source-map' import { environments } from '../integrations/env' import type { Environment, ResolvedConfig } from '../types' import { clearTimeout, getWorkerState, isNode, setTimeout, toArray } from '../utils' @@ -15,9 +16,6 @@ export async function setupGlobalEnv(config: ResolvedConfig) { enumerable: false, }) - // it's useful to see the full stack trace in the console by default - Error.stackTraceLimit = 100 - // should be re-declared for each test // if run with "threads: false" setupDefines(config.defines) @@ -25,6 +23,24 @@ export async function setupGlobalEnv(config: ResolvedConfig) { if (globalSetup) return + const state = getWorkerState() + + installViteNodeSourcemaps({ + getSourceMap(source) { + const fsPath = state.moduleCache.normalizePath(source) + const cache = state.moduleCache.get(fsPath) + 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')) + cache.map = map + return map + } + return null + }, + }) + globalSetup = true if (isNode) diff --git a/packages/vitest/src/utils/source-map.ts b/packages/vitest/src/utils/source-map.ts index b5ed47277d8e..dfa3ed2e0af6 100644 --- a/packages/vitest/src/utils/source-map.ts +++ b/packages/vitest/src/utils/source-map.ts @@ -1,46 +1,27 @@ import { SourceMapConsumer } from 'source-map-js' import type { RawSourceMap } from 'vite-node' import type { ErrorWithDiff, ParsedStack, Position } from '../types' -import type { Vitest } from '../node' import { notNullish, slash } from './base' export const lineSplitRE = /\r?\n/ -export function getOriginalPos(map: RawSourceMap | null | undefined, { line, column }: Position): Promise { - return new Promise((resolve) => { - if (!map) - return resolve(null) +export function getOriginalPos(map: RawSourceMap | null | undefined, { line, column }: Position): Position | null { + if (!map) + return null - const consumer = new SourceMapConsumer(map) - const pos = consumer.originalPositionFor({ line, column }) - if (pos.line != null && pos.column != null) - resolve(pos as Position) + const consumer = new SourceMapConsumer(map) + const pos = consumer.originalPositionFor({ line, column }) + if (pos.line != null && pos.column != null) + return pos as Position - else - resolve(null) - }) -} - -export async function interpretSourcePos(stackFrames: ParsedStack[], ctx: Vitest): Promise { - for (const frame of stackFrames) { - if ('sourcePos' in frame) - continue - const ssrTransformResult = ctx.server.moduleGraph.getModuleById(frame.file)?.ssrTransformResult - const fetchResult = ctx.vitenode?.fetchCache.get(frame.file)?.result - const map = fetchResult?.map || ssrTransformResult?.map - if (!map) - continue - const sourcePos = await getOriginalPos(map as any as RawSourceMap, frame) - if (sourcePos) - frame.sourcePos = sourcePos - } - - return stackFrames + else + return null } const stackIgnorePatterns = [ 'node:internal', '/vitest/dist/', + '/vitest/src/', '/node_modules/chai/', '/node_modules/tinypool/', '/node_modules/tinyspy/', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86a9f819c0b3..84d6546967ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -746,20 +746,24 @@ importers: packages/vite-node: specifiers: '@types/debug': ^4.1.7 + '@types/source-map-support': ^0.5.6 cac: ^6.7.14 debug: ^4.3.4 mlly: ^0.5.16 pathe: ^0.2.0 picocolors: ^1.0.0 rollup: ^2.79.0 + source-map-support: ^0.5.21 vite: ^3.2.0 dependencies: debug: 4.3.4 mlly: 0.5.16 pathe: 0.2.0 + source-map-support: 0.5.21 vite: 3.2.1 devDependencies: '@types/debug': 4.1.7 + '@types/source-map-support': 0.5.6 cac: 6.7.14 picocolors: 1.0.0 rollup: 2.79.0 @@ -823,6 +827,7 @@ importers: chai: 4.3.6 debug: 4.3.4 local-pkg: 0.4.2 + source-map-js: 1.0.2 strip-literal: 0.4.2 tinybench: 2.3.1 tinypool: 0.3.0 @@ -863,7 +868,6 @@ importers: pretty-format: 27.5.1 prompts: 2.4.2 rollup: 2.79.0 - source-map-js: 1.0.2 strip-ansi: 7.0.1 typescript: 4.8.4 vite-node: link:../vite-node @@ -7186,6 +7190,12 @@ packages: resolution: {integrity: sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==} dev: true + /@types/source-map-support/0.5.6: + resolution: {integrity: sha512-b2nJ9YyXmkhGaa2b8VLM0kJ04xxwNyijcq12/kDoomCt43qbHBeK2SLNJ9iJmETaAj+bKUT05PQUu3Q66GvLhQ==} + dependencies: + source-map: 0.6.1 + dev: true + /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -9474,7 +9484,6 @@ packages: /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true /buffer-xor/1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} @@ -18480,7 +18489,6 @@ packages: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true /source-map-url/0.4.1: resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} From 8eb53753644fd9480e1b4b560087f505f3fa136b Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 31 Oct 2022 18:35:34 +0100 Subject: [PATCH 02/14] chore: update test snapshot --- test/reporters/tests/__snapshots__/json.test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/reporters/tests/__snapshots__/json.test.ts.snap b/test/reporters/tests/__snapshots__/json.test.ts.snap index 9cdc37ea070f..3f930ad33668 100644 --- a/test/reporters/tests/__snapshots__/json.test.ts.snap +++ b/test/reporters/tests/__snapshots__/json.test.ts.snap @@ -10,7 +10,7 @@ exports[`json reporter > generates correct report 1`] = ` ], "fullName": " should fail", "location": { - "column": 12, + "column": 13, "line": 6, }, "status": "failed", From 614273e68f5a5ae3a779040e63a4a64c5ec6f06c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 31 Oct 2022 18:48:19 +0100 Subject: [PATCH 03/14] chore: remove source-map-js --- packages/vitest/package.json | 1 - .../integrations/snapshot/port/inlineSnapshot.ts | 7 ++----- packages/vitest/src/utils/source-map.ts | 15 --------------- pnpm-lock.yaml | 2 -- 4 files changed, 2 insertions(+), 23 deletions(-) diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 4d074a49d508..60ec532fcc7d 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -111,7 +111,6 @@ "chai": "^4.3.6", "debug": "^4.3.4", "local-pkg": "^0.4.2", - "source-map-js": "^1.0.2", "strip-literal": "^0.4.2", "tinybench": "^2.3.1", "tinypool": "^0.3.0", diff --git a/packages/vitest/src/integrations/snapshot/port/inlineSnapshot.ts b/packages/vitest/src/integrations/snapshot/port/inlineSnapshot.ts index 1480c7030912..87f096233812 100644 --- a/packages/vitest/src/integrations/snapshot/port/inlineSnapshot.ts +++ b/packages/vitest/src/integrations/snapshot/port/inlineSnapshot.ts @@ -1,7 +1,6 @@ import { promises as fs } from 'fs' import type MagicString from 'magic-string' -import { rpc } from '../../../runtime/rpc' -import { getOriginalPos, lineSplitRE, numberToPos, posToNumber } from '../../../utils/source-map' +import { lineSplitRE, numberToPos, posToNumber } from '../../../utils/source-map' import { getCallLastIndex } from '../../../utils' export interface InlineSnapshot { @@ -17,14 +16,12 @@ export async function saveInlineSnapshots( const MagicString = (await import('magic-string')).default const files = new Set(snapshots.map(i => i.file)) await Promise.all(Array.from(files).map(async (file) => { - const map = await rpc().getSourceMap(file) const snaps = snapshots.filter(i => i.file === file) const code = await fs.readFile(file, 'utf8') const s = new MagicString(code) for (const snap of snaps) { - const pos = await getOriginalPos(map, snap) - const index = posToNumber(code, pos!) + const index = posToNumber(code, snap) replaceInlineSnap(code, s, index, snap.snapshot) } diff --git a/packages/vitest/src/utils/source-map.ts b/packages/vitest/src/utils/source-map.ts index dfa3ed2e0af6..7e0afe9d0c33 100644 --- a/packages/vitest/src/utils/source-map.ts +++ b/packages/vitest/src/utils/source-map.ts @@ -1,23 +1,8 @@ -import { SourceMapConsumer } from 'source-map-js' -import type { RawSourceMap } from 'vite-node' import type { ErrorWithDiff, ParsedStack, Position } from '../types' import { notNullish, slash } from './base' export const lineSplitRE = /\r?\n/ -export function getOriginalPos(map: RawSourceMap | null | undefined, { line, column }: Position): Position | null { - if (!map) - return null - - const consumer = new SourceMapConsumer(map) - const pos = consumer.originalPositionFor({ line, column }) - if (pos.line != null && pos.column != null) - return pos as Position - - else - return null -} - const stackIgnorePatterns = [ 'node:internal', '/vitest/dist/', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84d6546967ce..3680874209ae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -810,7 +810,6 @@ importers: pretty-format: ^27.5.1 prompts: ^2.4.2 rollup: ^2.79.0 - source-map-js: ^1.0.2 strip-ansi: ^7.0.1 strip-literal: ^0.4.2 tinybench: ^2.3.1 @@ -827,7 +826,6 @@ importers: chai: 4.3.6 debug: 4.3.4 local-pkg: 0.4.2 - source-map-js: 1.0.2 strip-literal: 0.4.2 tinybench: 2.3.1 tinypool: 0.3.0 From 84714a820afa5cd873ab82c64d5182301bbc39b4 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Mon, 31 Oct 2022 19:40:44 +0100 Subject: [PATCH 04/14] chore: fix .ts stackrace test --- test/stacktraces/test/__snapshots__/runner.test.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/stacktraces/test/__snapshots__/runner.test.ts.snap b/test/stacktraces/test/__snapshots__/runner.test.ts.snap index 54b488ab5a80..d1bbf798e55b 100644 --- a/test/stacktraces/test/__snapshots__/runner.test.ts.snap +++ b/test/stacktraces/test/__snapshots__/runner.test.ts.snap @@ -1,11 +1,11 @@ // Vitest Snapshot v1 exports[`stacktraces should respect sourcemaps > add.test.ts > add.test.ts 1`] = ` -" ❯ add.test.ts:12:23 +" ❯ add.test.ts:12:24 10| 11| it('add', () => { 12| expect(add(a.count)).toBe(100) - | ^ + | ^ 13| expect(add(1)).toBe(1) 14| return expect(add(1, 2, 3)).toBe(6) " From 0003a18ece8a2ba4bc393b333ac940f1d47b12df Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 11:00:53 +0100 Subject: [PATCH 05/14] chore: revert offset in c8 --- packages/coverage-c8/src/provider.ts | 7 ++++++- packages/vite-node/src/client.ts | 4 ++++ packages/vite-node/src/server.ts | 6 ++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/coverage-c8/src/provider.ts b/packages/coverage-c8/src/provider.ts index bad4bc80bca8..23f2c65a6bb2 100644 --- a/packages/coverage-c8/src/provider.ts +++ b/packages/coverage-c8/src/provider.ts @@ -80,6 +80,11 @@ export class C8CoverageProvider implements CoverageProvider { } })) + // This is a magic number. It corresponds to the amount of code + // that we add in packages/vite-node/src/client.ts:114 (vm.runInThisContext) + // TODO: Include our transformations in sourcemaps + const offset = 224 + report._getSourceMap = (coverage: Profiler.ScriptCoverage) => { const path = _url.pathToFileURL(coverage.url.split('?')[0]).href const data = sourceMapMeta[path] @@ -91,7 +96,7 @@ export class C8CoverageProvider implements CoverageProvider { sourceMap: { sourcemap: data.map, }, - source: data.source, + source: Array(offset).fill('.').join('') + data.source, } } diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 0ce8f6bf2c70..ef6c0ecb9108 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -290,6 +290,10 @@ export class ViteNodeRunner { }) } + // Be careful when changing this + // changing context will change amount of code added on line :114 (vm.runInThisContext) + // this messes up sourcemaps for coverage + // adjust `offset` variable in packages/coverage-c8/src/provider.ts#86 if you do change this const context = this.prepareContext({ // esm transformed by Vite __vite_ssr_import__: request, diff --git a/packages/vite-node/src/server.ts b/packages/vite-node/src/server.ts index c4920962729f..66654be63d92 100644 --- a/packages/vite-node/src/server.ts +++ b/packages/vite-node/src/server.ts @@ -74,9 +74,11 @@ export class ViteNodeServer { } getSourceMap(source: string) { - const ssrTransformResult = this.server.moduleGraph.getModuleById(source)?.ssrTransformResult const fetchResult = this.fetchCache.get(source)?.result - return (fetchResult?.map || ssrTransformResult?.map) as unknown as RawSourceMap | null + if (fetchResult?.map) + return fetchResult.map + const ssrTransformResult = this.server.moduleGraph.getModuleById(source)?.ssrTransformResult + return (ssrTransformResult?.map || null) as unknown as RawSourceMap | null } async fetchModule(id: string): Promise { From 1675f87aa806f2fd7fdeb8581352f199eeb05f15 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 11:03:09 +0100 Subject: [PATCH 06/14] chore: update license --- packages/vitest/LICENSE.md | 62 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/packages/vitest/LICENSE.md b/packages/vitest/LICENSE.md index 86747084cd3c..e3fc4e6dab15 100644 --- a/packages/vitest/LICENSE.md +++ b/packages/vitest/LICENSE.md @@ -335,6 +335,34 @@ Repository: micromatch/braces --------------------------------------- +## buffer-from +License: MIT +Repository: LinusU/buffer-from + +> MIT License +> +> Copyright (c) 2016, 2018 Linus Unnebäck +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. + +--------------------------------------- + ## cac License: MIT By: egoist @@ -1806,10 +1834,10 @@ Repository: chalk/slice-ansi --------------------------------------- -## source-map-js +## source-map License: BSD-3-Clause -By: Valentin 7rulnik Semirulnik, Nick Fitzgerald, Tobias Koppers, Duncan Beevers, Stephen Crane, Ryan Seddon, Miles Elam, Mihai Bazon, Michael Ficarra, Todd Wolfson, Alexander Solovyov, Felix Gnass, Conrad Irwin, usrbincc, David Glasser, Chase Douglas, Evan Wallace, Heather Arthur, Hugh Kennedy, Simon Lydell, Jmeas Smith, Michael Z Goddard, azu, John Gozde, Adam Kirkton, Chris Montgomery, J. Ryan Stinnett, Jack Herrington, Chris Truter, Daniel Espeset, Jamie Wong, Eddy Bruël, Hawken Rives, Gilad Peleg, djchie, Gary Ye, Nicolas Lalevée -Repository: 7rulnik/source-map-js +By: Nick Fitzgerald, Tobias Koppers, Duncan Beevers, Stephen Crane, Ryan Seddon, Miles Elam, Mihai Bazon, Michael Ficarra, Todd Wolfson, Alexander Solovyov, Felix Gnass, Conrad Irwin, usrbincc, David Glasser, Chase Douglas, Evan Wallace, Heather Arthur, Hugh Kennedy, Simon Lydell, Jmeas Smith, Michael Z Goddard, azu, John Gozde, Adam Kirkton, Chris Montgomery, J. Ryan Stinnett, Jack Herrington, Chris Truter, Daniel Espeset, Jamie Wong, Eddy Bruël, Hawken Rives, Gilad Peleg, djchie, Gary Ye, Nicolas Lalevée +Repository: http://github.com/mozilla/source-map.git > Copyright (c) 2009-2011, Mozilla Foundation and contributors > All rights reserved. @@ -1841,6 +1869,34 @@ Repository: 7rulnik/source-map-js --------------------------------------- +## source-map-support +License: MIT +Repository: https://github.com/evanw/node-source-map-support + +> The MIT License (MIT) +> +> Copyright (c) 2014 Evan Wallace +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. + +--------------------------------------- + ## sourcemap-codec License: MIT By: Rich Harris From 9b1c892f987f66d46ce974f2a4c76411dda69a5a Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 14:34:35 +0100 Subject: [PATCH 07/14] test: don't return inlined source map in imba --- test/stacktraces/fixtures/vite.config.ts | 2 +- test/stacktraces/test/__snapshots__/runner.test.ts.snap | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/stacktraces/fixtures/vite.config.ts b/test/stacktraces/fixtures/vite.config.ts index 766ce8757db1..6edbcbf7ef92 100644 --- a/test/stacktraces/fixtures/vite.config.ts +++ b/test/stacktraces/fixtures/vite.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ if (id.endsWith('.imba')) { return { code: - '\n/*body*/\nimport {it,expect} from \'vitest\';\n\nexport function add(...args){\n\t\n\treturn args.reduce(function(a,b) { return a + b; },0);\n};\n\nit("add",function() {\n\t\n\texpect(add()).toBe(0);\n\texpect(add(1)).toBe(3);\n\treturn expect(add(1,2,3)).toBe(6);\n});\n\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMudGVzdC5pbWJhIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidXRpbHMudGVzdC5pbWJhIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7aXQsIGV4cGVjdH0gZnJvbSAndml0ZXN0J1xuXG5leHBvcnQgZGVmIGFkZCguLi5hcmdzKVxuXHRyZXR1cm4gYXJncy5yZWR1Y2UoKGRvKGEsIGIpIGEgKyBiKSwgMClcblxuaXQgXCJhZGRcIiwgZG9cblx0ZXhwZWN0KGFkZCgpKS50b0JlIDBcblx0ZXhwZWN0KGFkZCgxKSkudG9CZSAzXG5cdGV4cGVjdChhZGQoMSwgMiwgMykpLnRvQmUgNlxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsTUFBTSxFQUFFLEVBQUUsQ0FBRSxNQUFNLE9BQU8sUUFBUTs7QUFFakMsTUFBTSxDQUFDLFFBQUcsQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDOztDQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBRSxRQUFFLENBQUMsQ0FBQyxDQUFFLENBQUMsSUFBRSxPQUFBLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFHLENBQUMsQ0FBQztDQUFBOztBQUV4QyxFQUFFLENBQUMsS0FBSyxDQUFFLFFBQUUsR0FBQTs7Q0FDWCxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0NBQ3BCLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFBO0NBQ3JCLE9BQUEsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUUsQ0FBQyxDQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtDQUFBLENBSDFCO0FBSUY7In0=', + '\n/*body*/\nimport {it,expect} from \'vitest\';\n\nexport function add(...args){\n\t\n\treturn args.reduce(function(a,b) { return a + b; },0);\n};\n\nit("add",function() {\n\t\n\texpect(add()).toBe(0);\n\texpect(add(1)).toBe(3);\n\treturn expect(add(1,2,3)).toBe(6);\n});', map: { version: 3, file: 'add-in-imba.test.imba', diff --git a/test/stacktraces/test/__snapshots__/runner.test.ts.snap b/test/stacktraces/test/__snapshots__/runner.test.ts.snap index d1bbf798e55b..038ac0806168 100644 --- a/test/stacktraces/test/__snapshots__/runner.test.ts.snap +++ b/test/stacktraces/test/__snapshots__/runner.test.ts.snap @@ -12,11 +12,11 @@ exports[`stacktraces should respect sourcemaps > add.test.ts > add.test.ts 1`] = `; exports[`stacktraces should respect sourcemaps > add-in-imba.test.imba > add-in-imba.test.imba 1`] = ` -" ❯ add-in-imba.test.imba:8:16 +" ❯ add-in-imba.test.imba:8:17 6| it \\"add\\", do 7| expect(add()).toBe 0 8| expect(add(1)).toBe 3 - | ^ + | ^ 9| expect(add(1, 2, 3)).toBe 6 10| " From 8f85da5b1e579a2d71f792a39d86ee6e67e36986 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 16:41:59 +0100 Subject: [PATCH 08/14] docs: add installViteNodeSourcemaps in vite-node --- packages/vite-node/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/vite-node/README.md b/packages/vite-node/README.md index 4bcb5b5da00b..c381eb32f7d2 100644 --- a/packages/vite-node/README.md +++ b/packages/vite-node/README.md @@ -56,6 +56,7 @@ In Vite Node, the server and runner (client) are separated, so you can integrate import { createServer } from 'vite' import { ViteNodeServer } from 'vite-node/server' import { ViteNodeRunner } from 'vite-node/client' +import { installViteNodeSourcemaps } from 'vite-node/source-map' // create vite server const server = await createServer({ @@ -70,6 +71,11 @@ await server.pluginContainer.buildStart({}) // create vite-node server const node = new ViteNodeServer(server) +// fixes stacktrace in Errors and console.trace calls +installViteNodeSourcemaps({ + getSourceMap: source => node.getSourceMap(source) +}) + // create vite-node runner const runner = new ViteNodeRunner({ root: server.config.root, From 6901f46161d53fc990f1f3e55851a24976d9271c Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 16:52:26 +0100 Subject: [PATCH 09/14] chore: replace installViteNodeSourcamp with getSourceMap --- packages/vite-node/README.md | 11 +++++------ packages/vite-node/package.json | 5 ----- packages/vite-node/rollup.config.js | 15 +++++++-------- packages/vite-node/src/cli.ts | 8 +++----- packages/vite-node/src/client.ts | 7 +++++++ packages/vite-node/src/source-map.ts | 2 +- packages/vite-node/src/types.ts | 1 + packages/vitest/src/runtime/setup.ts | 19 ------------------- packages/vitest/src/runtime/worker.ts | 13 +++++++++++++ 9 files changed, 37 insertions(+), 44 deletions(-) diff --git a/packages/vite-node/README.md b/packages/vite-node/README.md index c381eb32f7d2..6b03ba8729e3 100644 --- a/packages/vite-node/README.md +++ b/packages/vite-node/README.md @@ -56,7 +56,6 @@ In Vite Node, the server and runner (client) are separated, so you can integrate import { createServer } from 'vite' import { ViteNodeServer } from 'vite-node/server' import { ViteNodeRunner } from 'vite-node/client' -import { installViteNodeSourcemaps } from 'vite-node/source-map' // create vite server const server = await createServer({ @@ -71,11 +70,6 @@ await server.pluginContainer.buildStart({}) // create vite-node server const node = new ViteNodeServer(server) -// fixes stacktrace in Errors and console.trace calls -installViteNodeSourcemaps({ - getSourceMap: source => node.getSourceMap(source) -}) - // create vite-node runner const runner = new ViteNodeRunner({ root: server.config.root, @@ -86,6 +80,11 @@ const runner = new ViteNodeRunner({ fetchModule(id) { return node.fetchModule(id) }, + // fixes stacktrace in Errors and console.trace calls + // has to be syncronouse + getSourceMap(source) { + return node.getSourceMap(source) + }, resolveId(id, importer) { return node.resolveId(id, importer) }, diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 96ce0e85ba50..9708ff4084d5 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -39,11 +39,6 @@ "types": "./dist/hmr.d.ts", "require": "./dist/hmr.cjs", "import": "./dist/hmr.mjs" - }, - "./source-map": { - "types": "./dist/source-map.d.ts", - "require": "./dist/source-map.cjs", - "import": "./dist/source-map.mjs" } }, "main": "./dist/index.mjs", diff --git a/packages/vite-node/rollup.config.js b/packages/vite-node/rollup.config.js index 37c8e2ad8d0f..8f1e22adc04e 100644 --- a/packages/vite-node/rollup.config.js +++ b/packages/vite-node/rollup.config.js @@ -9,14 +9,13 @@ import { defineConfig } from 'rollup' import pkg from './package.json' const entries = { - 'index': 'src/index.ts', - 'server': 'src/server.ts', - 'types': 'src/types.ts', - 'client': 'src/client.ts', - 'utils': 'src/utils.ts', - 'cli': 'src/cli.ts', - 'hmr': 'src/hmr/index.ts', - 'source-map': 'src/source-map.ts', + index: 'src/index.ts', + server: 'src/server.ts', + types: 'src/types.ts', + client: 'src/client.ts', + utils: 'src/utils.ts', + cli: 'src/cli.ts', + hmr: 'src/hmr/index.ts', } const external = [ diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index e244675990e9..99d04a54353b 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -7,7 +7,6 @@ import { ViteNodeRunner } from './client' import type { ViteNodeServerOptions } from './types' import { toArray } from './utils' import { createHotContext, handleMessage, viteNodeHmrPlugin } from './hmr' -import { installViteNodeSourcemaps } from './source-map' const cli = cac('vite-node') @@ -59,10 +58,6 @@ async function run(files: string[], options: CliOptions = {}) { const node = new ViteNodeServer(server, serverOptions) - installViteNodeSourcemaps({ - getSourceMap: source => node.getSourceMap(source), - }) - const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, @@ -72,6 +67,9 @@ async function run(files: string[], options: CliOptions = {}) { resolveId(id, importer) { return node.resolveId(id, importer) }, + getSourceMap(source) { + return node.getSourceMap(source) + }, createHotContext(runner, url) { return createHotContext(runner, server.emitter, files, url) }, diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index ef6c0ecb9108..5b08b1c4207c 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 { installSourcemapsSupport } from './source-map' const debugExecute = createDebug('vite-node:client:execute') const debugNative = createDebug('vite-node:client:native') @@ -126,6 +127,12 @@ export class ViteNodeRunner { this.root = options.root ?? process.cwd() this.moduleCache = options.moduleCache ?? new ModuleCacheMap() this.debug = options.debug ?? (typeof process !== 'undefined' ? !!process.env.VITE_NODE_DEBUG_RUNNER : false) + + if (options.getSourceMap) { + installSourcemapsSupport({ + getSourceMap: options.getSourceMap, + }) + } } async executeFile(file: string) { diff --git a/packages/vite-node/src/source-map.ts b/packages/vite-node/src/source-map.ts index b1438df029f9..d862544d38cd 100644 --- a/packages/vite-node/src/source-map.ts +++ b/packages/vite-node/src/source-map.ts @@ -5,7 +5,7 @@ interface InstallSourceMapSupportOptions { getSourceMap: (source: string) => RawSourceMap | null | undefined } -export function installViteNodeSourcemaps(options: InstallSourceMapSupportOptions) { +export function installSourcemapsSupport(options: InstallSourceMapSupportOptions) { install({ environment: 'node', handleUncaughtExceptions: false, diff --git a/packages/vite-node/src/types.ts b/packages/vite-node/src/types.ts index c94cfcfd75a9..de1422ae4460 100644 --- a/packages/vite-node/src/types.ts +++ b/packages/vite-node/src/types.ts @@ -56,6 +56,7 @@ export interface ViteNodeRunnerOptions { root: string fetchModule: FetchFunction resolveId?: ResolveIdFunction + getSourceMap?: (id: string) => RawSourceMap | null | undefined createHotContext?: CreateHotContextFunction base?: string moduleCache?: ModuleCacheMap diff --git a/packages/vitest/src/runtime/setup.ts b/packages/vitest/src/runtime/setup.ts index 98b8d93e4111..80a19a29c24a 100644 --- a/packages/vitest/src/runtime/setup.ts +++ b/packages/vitest/src/runtime/setup.ts @@ -1,4 +1,3 @@ -import { installViteNodeSourcemaps } from 'vite-node/source-map' import { environments } from '../integrations/env' import type { Environment, ResolvedConfig } from '../types' import { clearTimeout, getWorkerState, isNode, setTimeout, toArray } from '../utils' @@ -23,24 +22,6 @@ export async function setupGlobalEnv(config: ResolvedConfig) { if (globalSetup) return - const state = getWorkerState() - - installViteNodeSourcemaps({ - getSourceMap(source) { - const fsPath = state.moduleCache.normalizePath(source) - const cache = state.moduleCache.get(fsPath) - 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')) - cache.map = map - return map - } - return null - }, - }) - globalSetup = true if (isNode) diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index 0428c26dae02..4496004f2f21 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -48,6 +48,19 @@ async function startViteNode(ctx: WorkerContext) { resolveId(id, importer) { return rpc().resolveId(id, importer) }, + getSourceMap(source) { + const fsPath = moduleCache.normalizePath(source) + const cache = moduleCache.get(fsPath) + 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')) + cache.map = map + return map + } + return null + }, moduleCache, mockMap, interopDefault: config.deps.interopDefault ?? true, From 04b3a59ec72b4fa73d740ff0a6a0db1fe46dec98 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 17:52:14 +0100 Subject: [PATCH 10/14] refactor: use "fixStackTrace" option in vitenode-runner --- packages/vite-node/README.md | 6 +----- packages/vite-node/src/cli.ts | 4 +--- packages/vite-node/src/client.ts | 19 +++++++++++++++++-- packages/vite-node/src/types.ts | 1 + packages/vitest/src/runtime/worker.ts | 14 +------------- 5 files changed, 21 insertions(+), 23 deletions(-) diff --git a/packages/vite-node/README.md b/packages/vite-node/README.md index 6b03ba8729e3..833fd46503df 100644 --- a/packages/vite-node/README.md +++ b/packages/vite-node/README.md @@ -74,17 +74,13 @@ const node = new ViteNodeServer(server) const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, + fixStackTrace: true, // when having the server and runner in a different context, // you will need to handle the communication between them // and pass to this function fetchModule(id) { return node.fetchModule(id) }, - // fixes stacktrace in Errors and console.trace calls - // has to be syncronouse - getSourceMap(source) { - return node.getSourceMap(source) - }, resolveId(id, importer) { return node.resolveId(id, importer) }, diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index 99d04a54353b..1168fda3baaa 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -61,15 +61,13 @@ async function run(files: string[], options: CliOptions = {}) { const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, + fixStackTrace: true, fetchModule(id) { return node.fetchModule(id) }, resolveId(id, importer) { return node.resolveId(id, importer) }, - getSourceMap(source) { - return node.getSourceMap(source) - }, createHotContext(runner, url) { return createHotContext(runner, server.emitter, files, url) }, diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index 5b08b1c4207c..f96401501ab2 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -127,10 +127,11 @@ export class ViteNodeRunner { this.root = options.root ?? process.cwd() this.moduleCache = options.moduleCache ?? new ModuleCacheMap() this.debug = options.debug ?? (typeof process !== 'undefined' ? !!process.env.VITE_NODE_DEBUG_RUNNER : false) + this.options.fixStackTrace ??= true - if (options.getSourceMap) { + if (this.options.fixStackTrace) { installSourcemapsSupport({ - getSourceMap: options.getSourceMap, + getSourceMap: this.options.getSourceMap ?? (id => this.getSourceMap(id)), }) } } @@ -143,6 +144,20 @@ export class ViteNodeRunner { return await this.cachedRequest(id, []) } + getSourceMap(id: string) { + const fsPath = this.moduleCache.normalizePath(id) + const cache = this.moduleCache.get(fsPath) + 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')) + cache.map = map + return map + } + return null + } + /** @internal */ async cachedRequest(rawId: string, callstack: string[]) { const id = normalizeRequestId(rawId, this.options.base) diff --git a/packages/vite-node/src/types.ts b/packages/vite-node/src/types.ts index de1422ae4460..61b8f78532ce 100644 --- a/packages/vite-node/src/types.ts +++ b/packages/vite-node/src/types.ts @@ -56,6 +56,7 @@ export interface ViteNodeRunnerOptions { root: string fetchModule: FetchFunction resolveId?: ResolveIdFunction + fixStackTrace?: boolean getSourceMap?: (id: string) => RawSourceMap | null | undefined createHotContext?: CreateHotContextFunction base?: string diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index 4496004f2f21..ba56802dcb94 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -48,21 +48,9 @@ async function startViteNode(ctx: WorkerContext) { resolveId(id, importer) { return rpc().resolveId(id, importer) }, - getSourceMap(source) { - const fsPath = moduleCache.normalizePath(source) - const cache = moduleCache.get(fsPath) - 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')) - cache.map = map - return map - } - return null - }, moduleCache, mockMap, + fixStackTrace: true, interopDefault: config.deps.interopDefault ?? true, root: config.root, base: config.base, From 7d15fdc2046c09e99438bd1f26d0be19fde54e1e Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 20:25:25 +0100 Subject: [PATCH 11/14] refactor: add source-map entry to vite-node --- packages/vite-node/package.json | 5 +++++ packages/vite-node/rollup.config.js | 15 ++++++++------- packages/vite-node/src/client.ts | 26 +++++++++++++++----------- packages/vitest/src/runtime/setup.ts | 10 +++++++++- packages/vitest/src/runtime/worker.ts | 2 +- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/packages/vite-node/package.json b/packages/vite-node/package.json index 9708ff4084d5..96ce0e85ba50 100644 --- a/packages/vite-node/package.json +++ b/packages/vite-node/package.json @@ -39,6 +39,11 @@ "types": "./dist/hmr.d.ts", "require": "./dist/hmr.cjs", "import": "./dist/hmr.mjs" + }, + "./source-map": { + "types": "./dist/source-map.d.ts", + "require": "./dist/source-map.cjs", + "import": "./dist/source-map.mjs" } }, "main": "./dist/index.mjs", diff --git a/packages/vite-node/rollup.config.js b/packages/vite-node/rollup.config.js index 8f1e22adc04e..37c8e2ad8d0f 100644 --- a/packages/vite-node/rollup.config.js +++ b/packages/vite-node/rollup.config.js @@ -9,13 +9,14 @@ import { defineConfig } from 'rollup' import pkg from './package.json' const entries = { - index: 'src/index.ts', - server: 'src/server.ts', - types: 'src/types.ts', - client: 'src/client.ts', - utils: 'src/utils.ts', - cli: 'src/cli.ts', - hmr: 'src/hmr/index.ts', + 'index': 'src/index.ts', + 'server': 'src/server.ts', + 'types': 'src/types.ts', + 'client': 'src/client.ts', + 'utils': 'src/utils.ts', + 'cli': 'src/cli.ts', + 'hmr': 'src/hmr/index.ts', + 'source-map': 'src/source-map.ts', } const external = [ diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index f96401501ab2..cca41cad643e 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -110,6 +110,20 @@ export class ModuleCacheMap extends Map { } return invalidated } + + getSourceMap(id: string) { + const fsPath = this.normalizePath(id) + const cache = this.get(fsPath) + 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')) + cache.map = map + return map + } + return null + } } export class ViteNodeRunner { @@ -145,17 +159,7 @@ export class ViteNodeRunner { } getSourceMap(id: string) { - const fsPath = this.moduleCache.normalizePath(id) - const cache = this.moduleCache.get(fsPath) - 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')) - cache.map = map - return map - } - return null + return this.moduleCache.getSourceMap(id) } /** @internal */ diff --git a/packages/vitest/src/runtime/setup.ts b/packages/vitest/src/runtime/setup.ts index 80a19a29c24a..2497b62fb46b 100644 --- a/packages/vitest/src/runtime/setup.ts +++ b/packages/vitest/src/runtime/setup.ts @@ -1,3 +1,4 @@ +import { installSourcemapsSupport } from 'vite-node/source-map' import { environments } from '../integrations/env' import type { Environment, ResolvedConfig } from '../types' import { clearTimeout, getWorkerState, isNode, setTimeout, toArray } from '../utils' @@ -24,8 +25,15 @@ export async function setupGlobalEnv(config: ResolvedConfig) { globalSetup = true - if (isNode) + if (isNode) { + const state = getWorkerState() + + installSourcemapsSupport({ + getSourceMap: source => state.moduleCache.getSourceMap(source), + }) + await setupConsoleLogSpy() + } if (config.globals) (await import('../integrations/globals')).registerApiGlobally() diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index ba56802dcb94..56349d678d54 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -50,7 +50,7 @@ async function startViteNode(ctx: WorkerContext) { }, moduleCache, mockMap, - fixStackTrace: true, + fixStackTrace: false, interopDefault: config.deps.interopDefault ?? true, root: config.root, base: config.base, From f8bff47bdd98381a16ec25275ca26887cd6b1927 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 20:29:36 +0100 Subject: [PATCH 12/14] refactor: return installSourcemapsSupport --- packages/vite-node/src/cli.ts | 6 +++++- packages/vite-node/src/client.ts | 11 +++-------- packages/vite-node/src/types.ts | 2 -- packages/vitest/src/runtime/worker.ts | 1 - 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/vite-node/src/cli.ts b/packages/vite-node/src/cli.ts index 1168fda3baaa..602848d0c86e 100644 --- a/packages/vite-node/src/cli.ts +++ b/packages/vite-node/src/cli.ts @@ -7,6 +7,7 @@ import { ViteNodeRunner } from './client' import type { ViteNodeServerOptions } from './types' import { toArray } from './utils' import { createHotContext, handleMessage, viteNodeHmrPlugin } from './hmr' +import { installSourcemapsSupport } from './source-map' const cli = cac('vite-node') @@ -58,10 +59,13 @@ async function run(files: string[], options: CliOptions = {}) { const node = new ViteNodeServer(server, serverOptions) + installSourcemapsSupport({ + getSourceMap: source => node.getSourceMap(source), + }) + const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, - fixStackTrace: true, fetchModule(id) { return node.fetchModule(id) }, diff --git a/packages/vite-node/src/client.ts b/packages/vite-node/src/client.ts index cca41cad643e..998464fc2028 100644 --- a/packages/vite-node/src/client.ts +++ b/packages/vite-node/src/client.ts @@ -6,7 +6,6 @@ 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 { installSourcemapsSupport } from './source-map' const debugExecute = createDebug('vite-node:client:execute') const debugNative = createDebug('vite-node:client:native') @@ -111,6 +110,9 @@ export class ModuleCacheMap extends Map { return invalidated } + /** + * 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) @@ -141,13 +143,6 @@ export class ViteNodeRunner { this.root = options.root ?? process.cwd() this.moduleCache = options.moduleCache ?? new ModuleCacheMap() this.debug = options.debug ?? (typeof process !== 'undefined' ? !!process.env.VITE_NODE_DEBUG_RUNNER : false) - this.options.fixStackTrace ??= true - - if (this.options.fixStackTrace) { - installSourcemapsSupport({ - getSourceMap: this.options.getSourceMap ?? (id => this.getSourceMap(id)), - }) - } } async executeFile(file: string) { diff --git a/packages/vite-node/src/types.ts b/packages/vite-node/src/types.ts index 61b8f78532ce..c94cfcfd75a9 100644 --- a/packages/vite-node/src/types.ts +++ b/packages/vite-node/src/types.ts @@ -56,8 +56,6 @@ export interface ViteNodeRunnerOptions { root: string fetchModule: FetchFunction resolveId?: ResolveIdFunction - fixStackTrace?: boolean - getSourceMap?: (id: string) => RawSourceMap | null | undefined createHotContext?: CreateHotContextFunction base?: string moduleCache?: ModuleCacheMap diff --git a/packages/vitest/src/runtime/worker.ts b/packages/vitest/src/runtime/worker.ts index 56349d678d54..0428c26dae02 100644 --- a/packages/vitest/src/runtime/worker.ts +++ b/packages/vitest/src/runtime/worker.ts @@ -50,7 +50,6 @@ async function startViteNode(ctx: WorkerContext) { }, moduleCache, mockMap, - fixStackTrace: false, interopDefault: config.deps.interopDefault ?? true, root: config.root, base: config.base, From db0904631b386c4cb1c7261c3e30bc18ee5f019d Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 20:31:32 +0100 Subject: [PATCH 13/14] docs: update vite-node docs --- packages/vite-node/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/vite-node/README.md b/packages/vite-node/README.md index 833fd46503df..cc056997964a 100644 --- a/packages/vite-node/README.md +++ b/packages/vite-node/README.md @@ -56,6 +56,7 @@ In Vite Node, the server and runner (client) are separated, so you can integrate import { createServer } from 'vite' import { ViteNodeServer } from 'vite-node/server' import { ViteNodeRunner } from 'vite-node/client' +import { installSourcemapsSupport } from './source-map' // create vite server const server = await createServer({ @@ -70,11 +71,15 @@ await server.pluginContainer.buildStart({}) // create vite-node server const node = new ViteNodeServer(server) +// fixes stacktraces in Errors +installSourcemapsSupport({ + getSourceMap: source => node.getSourceMap(source), +}) + // create vite-node runner const runner = new ViteNodeRunner({ root: server.config.root, base: server.config.base, - fixStackTrace: true, // when having the server and runner in a different context, // you will need to handle the communication between them // and pass to this function From b38c54d4f89557e02ec3d157fd2b532b5db1f408 Mon Sep 17 00:00:00 2001 From: Vladimir Sheremet Date: Tue, 1 Nov 2022 20:57:38 +0100 Subject: [PATCH 14/14] chore: fix import in docs [ci skip] --- packages/vite-node/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite-node/README.md b/packages/vite-node/README.md index cc056997964a..2bd2fa115ef3 100644 --- a/packages/vite-node/README.md +++ b/packages/vite-node/README.md @@ -56,7 +56,7 @@ In Vite Node, the server and runner (client) are separated, so you can integrate import { createServer } from 'vite' import { ViteNodeServer } from 'vite-node/server' import { ViteNodeRunner } from 'vite-node/client' -import { installSourcemapsSupport } from './source-map' +import { installSourcemapsSupport } from 'vite-node/source-map' // create vite server const server = await createServer({