mirror of
https://github.com/vitejs/vite.git
synced 2024-11-22 07:09:05 +00:00
fix(ssr): stacktrace uses abs path with or without sourcemap (#12902)
Co-authored-by: sapphi-red <green@sapphi.red>
This commit is contained in:
parent
feef0354dc
commit
88c855eadc
@ -222,7 +222,7 @@ async function instantiateModule(
|
||||
ssrExportAllKey,
|
||||
'"use strict";' +
|
||||
result.code +
|
||||
`\n//# sourceURL=${mod.url}${sourceMapSuffix}`,
|
||||
`\n//# sourceURL=${mod.id}${sourceMapSuffix}`,
|
||||
)
|
||||
await initModule(
|
||||
context.global,
|
||||
|
@ -1,3 +1,4 @@
|
||||
import path from 'node:path'
|
||||
import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping'
|
||||
import type { ModuleGraph } from '../server/moduleGraph'
|
||||
|
||||
@ -21,10 +22,10 @@ export function ssrRewriteStacktrace(
|
||||
.map((line) => {
|
||||
return line.replace(
|
||||
/^ {4}at (?:(\S.*?)\s\()?(.+?):(\d+)(?::(\d+))?\)?/,
|
||||
(input, varName, url, line, column) => {
|
||||
if (!url) return input
|
||||
(input, varName, id, line, column) => {
|
||||
if (!id) return input
|
||||
|
||||
const mod = moduleGraph.urlToModuleMap.get(url)
|
||||
const mod = moduleGraph.idToModuleMap.get(id)
|
||||
const rawSourceMap = mod?.ssrTransformResult?.map
|
||||
|
||||
if (!rawSourceMap) {
|
||||
@ -35,7 +36,8 @@ export function ssrRewriteStacktrace(
|
||||
|
||||
const pos = originalPositionFor(traced, {
|
||||
line: Number(line) - offset,
|
||||
column: Number(column),
|
||||
// stacktrace's column is 1-indexed, but sourcemap's one is 0-indexed
|
||||
column: Number(column) - 1,
|
||||
})
|
||||
|
||||
if (!pos.source || pos.line == null || pos.column == null) {
|
||||
@ -43,7 +45,9 @@ export function ssrRewriteStacktrace(
|
||||
}
|
||||
|
||||
const trimmedVarName = varName.trim()
|
||||
const source = `${pos.source}:${pos.line}:${pos.column}`
|
||||
const sourceFile = path.resolve(path.dirname(id), pos.source)
|
||||
// stacktrace's column is 1-indexed, but sourcemap's one is 0-indexed
|
||||
const source = `${sourceFile}:${pos.line}:${pos.column + 1}`
|
||||
if (!trimmedVarName || trimmedVarName === 'eval') {
|
||||
return ` at ${source}`
|
||||
} else {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import path from 'node:path'
|
||||
import MagicString from 'magic-string'
|
||||
import type { SourceMap } from 'rollup'
|
||||
import type {
|
||||
@ -285,7 +286,7 @@ async function ssrTransformScript(
|
||||
false,
|
||||
) as SourceMap
|
||||
} else {
|
||||
map.sources = [url]
|
||||
map.sources = [path.basename(url)]
|
||||
// needs to use originalCode instead of code
|
||||
// because code might be already transformed even if map is null
|
||||
map.sourcesContent = [originalCode]
|
||||
|
@ -62,23 +62,36 @@ describe.runIf(isServe)('hmr', () => {
|
||||
describe.runIf(isServe)('stacktrace', () => {
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
for (const sourcemapsEnabled of [false, true]) {
|
||||
test(`stacktrace is correct when sourcemaps is${
|
||||
sourcemapsEnabled ? '' : ' not'
|
||||
} enabled in Node.js`, async () => {
|
||||
const testStacktraceFile = path.resolve(
|
||||
__dirname,
|
||||
'../test-stacktrace.js',
|
||||
)
|
||||
for (const ext of ['js', 'ts']) {
|
||||
for (const sourcemapsEnabled of [false, true]) {
|
||||
test(`stacktrace of ${ext} is correct when sourcemaps is${
|
||||
sourcemapsEnabled ? '' : ' not'
|
||||
} enabled in Node.js`, async () => {
|
||||
const testStacktraceFile = path.resolve(
|
||||
__dirname,
|
||||
'../test-stacktrace.js',
|
||||
)
|
||||
|
||||
const p = await execFileAsync('node', [
|
||||
testStacktraceFile,
|
||||
'' + sourcemapsEnabled,
|
||||
])
|
||||
const line = p.stdout
|
||||
.split('\n')
|
||||
.find((line) => line.includes('Module.error'))
|
||||
expect(line.trim()).toMatch(/[\\/]src[\\/]error\.js:2:9/)
|
||||
})
|
||||
const p = await execFileAsync('node', [
|
||||
testStacktraceFile,
|
||||
'' + sourcemapsEnabled,
|
||||
ext,
|
||||
])
|
||||
const lines = p.stdout
|
||||
.split('\n')
|
||||
.filter((line) => line.includes('Module.error'))
|
||||
|
||||
const reg = new RegExp(
|
||||
path
|
||||
.resolve(__dirname, '../src', `error.${ext}`)
|
||||
.replace(/\\/g, '\\\\') + ':2:9',
|
||||
'i',
|
||||
)
|
||||
|
||||
lines.forEach((line) => {
|
||||
expect(line.trim()).toMatch(reg)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
3
playground/ssr-html/src/error.ts
Normal file
3
playground/ssr-html/src/error.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export function error() {
|
||||
throw new Error('e')
|
||||
}
|
@ -3,8 +3,10 @@ import { fileURLToPath } from 'node:url'
|
||||
import { createServer } from 'vite'
|
||||
|
||||
const isSourceMapEnabled = process.argv[2] === 'true'
|
||||
const ext = process.argv[3]
|
||||
process.setSourceMapsEnabled(isSourceMapEnabled)
|
||||
console.log('# sourcemaps enabled:', isSourceMapEnabled)
|
||||
console.log('# source file extension:', ext)
|
||||
|
||||
const version = (() => {
|
||||
const m = process.version.match(/^v(\d+)\.(\d+)\.\d+$/)
|
||||
@ -31,17 +33,24 @@ const vite = await createServer({
|
||||
appType: 'custom',
|
||||
})
|
||||
|
||||
const mod = await vite.ssrLoadModule('/src/error.js')
|
||||
try {
|
||||
mod.error()
|
||||
} catch (e) {
|
||||
// this should not be called
|
||||
// when sourcemap support for `new Function` is supported and sourcemap is enabled
|
||||
// because the stacktrace is already rewritten by Node.js
|
||||
if (!(isSourceMapEnabled && isFunctionSourceMapSupported)) {
|
||||
vite.ssrFixStacktrace(e)
|
||||
const dir = path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const abs1 = await vite.ssrLoadModule(`/src/error.${ext}`)
|
||||
const abs2 = await vite.ssrLoadModule(path.resolve(dir, `./src/error.${ext}`))
|
||||
const relative = await vite.ssrLoadModule(`./src/error.${ext}`)
|
||||
|
||||
for (const mod of [abs1, abs2, relative]) {
|
||||
try {
|
||||
mod.error()
|
||||
} catch (e) {
|
||||
// this should not be called
|
||||
// when sourcemap support for `new Function` is supported and sourcemap is enabled
|
||||
// because the stacktrace is already rewritten by Node.js
|
||||
if (!(isSourceMapEnabled && isFunctionSourceMapSupported)) {
|
||||
vite.ssrFixStacktrace(e)
|
||||
}
|
||||
console.log(e)
|
||||
}
|
||||
console.log(e)
|
||||
}
|
||||
|
||||
await vite.close()
|
||||
|
@ -308,6 +308,9 @@ export const formatSourcemapForSnapshot = (map: any): any => {
|
||||
delete m.file
|
||||
delete m.names
|
||||
m.sources = m.sources.map((source) => source.replace(root, '/root'))
|
||||
if (m.sourceRoot) {
|
||||
m.sourceRoot = m.sourceRoot.replace(root, '/root')
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user