[dev-overlay] Always show relative paths (#76742)

This commit is contained in:
Sebastian "Sebbie" Silbermann
2025-03-04 09:32:17 +00:00
committed by GitHub
parent 5d53fd00fb
commit 059c255c37
8 changed files with 147 additions and 115 deletions
@@ -34,7 +34,7 @@ function shouldIgnorePath(modulePath: string): boolean {
type IgnorableStackFrame = StackFrame & { ignored: boolean }
const currentSourcesByFile: Map<string, Promise<string | null>> = new Map()
export async function batchedTraceSource(
async function batchedTraceSource(
project: Project,
frame: TurbopackStackFrame
): Promise<{ frame: IgnorableStackFrame; source: string | null } | undefined> {
@@ -316,9 +316,7 @@ async function nativeTraceSource(
?.replace('__WEBPACK_DEFAULT_EXPORT__', 'default')
?.replace('__webpack_exports__.', '') || '<unknown>',
column: (originalPosition.column ?? 0) + 1,
file: originalPosition.source?.startsWith('file://')
? relativeToCwd(originalPosition.source)
: originalPosition.source,
file: originalPosition.source,
lineNumber: originalPosition.line ?? 0,
// TODO: c&p from async createOriginalStackFrame but why not frame.arguments?
arguments: [],
@@ -335,14 +333,9 @@ async function nativeTraceSource(
return undefined
}
function relativeToCwd(file: string): string {
const relPath = path.relative(process.cwd(), url.fileURLToPath(file))
// TODO(sokra) include a ./ here to make it a relative path
return relPath
}
async function createOriginalStackFrame(
project: Project,
projectPath: string,
frame: TurbopackStackFrame
): Promise<OriginalStackFrameResponse | null> {
const traced =
@@ -354,13 +347,31 @@ async function createOriginalStackFrame(
return null
}
let normalizedStackFrameLocation = traced.frame.file
if (
normalizedStackFrameLocation !== null &&
normalizedStackFrameLocation.startsWith('file://')
) {
normalizedStackFrameLocation = path.relative(
projectPath,
url.fileURLToPath(normalizedStackFrameLocation)
)
}
return {
originalStackFrame: traced.frame,
originalStackFrame: {
arguments: traced.frame.arguments,
column: traced.frame.column,
file: normalizedStackFrameLocation,
ignored: traced.frame.ignored,
lineNumber: traced.frame.lineNumber,
methodName: traced.frame.methodName,
},
originalCodeFrame: getOriginalCodeFrame(traced.frame, traced.source),
}
}
export function getOverlayMiddleware(project: Project) {
export function getOverlayMiddleware(project: Project, projectPath: string) {
return async function (
req: IncomingMessage,
res: ServerResponse,
@@ -387,7 +398,11 @@ export function getOverlayMiddleware(project: Project) {
const result: OriginalStackFramesResponse = await Promise.all(
stackFrames.map(async (frame) => {
try {
const stackFrame = await createOriginalStackFrame(project, frame)
const stackFrame = await createOriginalStackFrame(
project,
projectPath,
frame
)
if (stackFrame === null) {
return {
status: 'rejected',
@@ -471,9 +471,19 @@ async function getOriginalStackFrame({
},
})
let defaultNormalizedStackFrameLocation = frame.file
if (
defaultNormalizedStackFrameLocation !== null &&
defaultNormalizedStackFrameLocation.startsWith('file://')
) {
defaultNormalizedStackFrameLocation = path.relative(
rootDirectory,
fileURLToPath(defaultNormalizedStackFrameLocation)
)
}
// This stack frame is used for the one that couldn't locate the source or source mapped frame
const defaultStackFrame: IgnorableStackFrame = {
file: frame.file,
file: defaultNormalizedStackFrameLocation,
lineNumber: frame.lineNumber,
column: frame.column ?? 1,
methodName: frame.methodName,
@@ -161,7 +161,7 @@ export async function createHotReloaderTurbopack(
): Promise<NextJsHotReloaderInterface> {
const dev = true
const buildId = 'development'
const { nextConfig, dir } = opts
const { nextConfig, dir: projectPath } = opts
const { loadBindings } =
require('../../build/swc') as typeof import('../../build/swc')
@@ -172,7 +172,7 @@ export async function createHotReloaderTurbopack(
// works correctly. Normally `run-test` hides output so only will be visible when `--debug` flag is used.
if (process.env.TURBOPACK && isTestMode) {
require('console').log('Creating turbopack project', {
dir,
dir: projectPath,
testMode: isTestMode,
})
}
@@ -207,14 +207,14 @@ export async function createHotReloaderTurbopack(
const project = await bindings.turbo.createProject(
{
projectPath: dir,
projectPath: projectPath,
rootPath:
opts.nextConfig.experimental.turbo?.root ||
opts.nextConfig.outputFileTracingRoot ||
dir,
projectPath,
distDir,
nextConfig: opts.nextConfig,
jsConfig: await getTurbopackJsConfig(dir, nextConfig),
jsConfig: await getTurbopackJsConfig(projectPath, nextConfig),
watch: {
enable: dev,
pollIntervalMs: nextConfig.watchOptions?.pollIntervalMs,
@@ -244,7 +244,7 @@ export async function createHotReloaderTurbopack(
}
)
setBundlerFindSourceMapImplementation(
getSourceMapFromTurbopack.bind(null, project, dir)
getSourceMapFromTurbopack.bind(null, project, projectPath)
)
opts.onDevServerCleanup?.(async () => {
setBundlerFindSourceMapImplementation(() => undefined)
@@ -634,7 +634,7 @@ export async function createHotReloaderTurbopack(
)
const middlewares = [
getOverlayMiddleware(project),
getOverlayMiddleware(project, projectPath),
getSourceMapMiddleware(project),
getNextErrorFeedbackMiddleware(opts.telemetry),
getDevOverlayFontMiddleware(),
@@ -957,7 +957,7 @@ export async function createHotReloaderTurbopack(
> =
definition ??
(await findPagePathData(
dir,
projectPath,
inputPage,
nextConfig.pageExtensions,
opts.pagesDir,
@@ -115,15 +115,15 @@ describe('ReactRefreshLogBox app', () => {
| ^",
"stack": [
"eval index.js (3:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"eval ./app/page.js",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -1468,10 +1468,10 @@ describe('ReactRefreshLogBox app', () => {
"stack": [
"eval index.js (1:7)",
"<FIXME-next-dist-dir>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"eval ./app/server/page.js",
"<FIXME-next-dist-dir>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -1639,15 +1639,15 @@ export default function Home() {
| ^",
"stack": [
"eval app/utils.ts (1:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"eval ./app/page.js",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -131,9 +131,9 @@ describe('ReactRefreshLogBox', () => {
| ^",
"stack": [
"[project]/index.js [ssr] (ecmascript) index.js (3:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -149,18 +149,18 @@ describe('ReactRefreshLogBox', () => {
| ^",
"stack": [
"eval index.js (3:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"eval ./pages/index.js",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -178,9 +178,9 @@ describe('ReactRefreshLogBox', () => {
| ^",
"stack": [
"[project]/index.js [ssr] (ecmascript) index.js (3:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -196,18 +196,18 @@ describe('ReactRefreshLogBox', () => {
| ^",
"stack": [
"eval index.js (3:7)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"eval ./pages/index.js",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -284,8 +284,8 @@ describe('ReactRefreshLogBox', () => {
"stack": [
"FunctionDefault FunctionDefault.js (1:51)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -302,8 +302,8 @@ describe('ReactRefreshLogBox', () => {
"stack": [
"FunctionDefault FunctionDefault.js (1:51)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -413,7 +413,6 @@ describe('ReactRefreshLogBox', () => {
}
})
// Module trace is only available with webpack 5
test('conversion to class component (1)', async () => {
await using sandbox = await createSandbox(next)
const { browser, session } = sandbox
@@ -459,6 +458,8 @@ describe('ReactRefreshLogBox', () => {
`
)
// TODO(veil): ignore-list Webpack runtime (https://linear.app/vercel/issue/NDX-945)
// TODO(veil): Don't bail in Turbopack for sources outside of the project (https://linear.app/vercel/issue/NDX-944)
if (isReact18) {
await expect(browser).toDisplayRedbox(`
{
@@ -472,8 +473,8 @@ describe('ReactRefreshLogBox', () => {
"stack": [
"ClickCount.render Child.js (4:11)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -490,8 +491,8 @@ describe('ReactRefreshLogBox', () => {
"stack": [
"ClickCount.render Child.js (4:11)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -249,6 +249,8 @@ describe('pages/ error recovery', () => {
`
)
// TODO(veil): ignore-list Webpack runtime (https://linear.app/vercel/issue/NDX-945)
// TODO(veil): Don't bail in Turbopack for sources outside of the project (https://linear.app/vercel/issue/NDX-944)
// Somehow we end up with two in React 18 due to React's attempt to recover from this error.
if (isReact18) {
await expect(browser).toDisplayRedbox(`
@@ -263,8 +265,8 @@ describe('pages/ error recovery', () => {
"stack": [
"Child child.js (3:9)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -281,8 +283,8 @@ describe('pages/ error recovery', () => {
"stack": [
"Child child.js (3:9)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -527,6 +529,8 @@ describe('pages/ error recovery', () => {
await expect(session.getRedboxSource()).resolves.toInclude('render() {')
})
// TODO(veil): ignore-list Webpack runtime (https://linear.app/vercel/issue/NDX-945)
// TODO(veil): Don't bail in Turbopack for sources outside of the project (https://linear.app/vercel/issue/NDX-944)
// Somehow we end up with two in React 18 due to React's attempt to recover from this error.
if (isReact18) {
await expect(browser).toDisplayRedbox(`
@@ -541,8 +545,8 @@ describe('pages/ error recovery', () => {
"stack": [
"ClassDefault.render index.js (5:11)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -564,22 +568,22 @@ describe('pages/ error recovery', () => {
`)
} else {
await expect(browser).toDisplayRedbox(`
{
"count": 1,
"description": "Error: nooo",
"environmentLabel": null,
"label": "Unhandled Runtime Error",
"source": "index.js (5:11) @ ClassDefault.render
> 5 | throw new Error('nooo');
| ^",
"stack": [
"ClassDefault.render index.js (5:11)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
],
}
`)
{
"count": 1,
"description": "Error: nooo",
"environmentLabel": null,
"label": "Unhandled Runtime Error",
"source": "index.js (5:11) @ ClassDefault.render
> 5 | throw new Error('nooo');
| ^",
"stack": [
"ClassDefault.render index.js (5:11)",
"Set.forEach <anonymous> (0:0)",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
}
}
})
@@ -627,6 +631,8 @@ describe('pages/ error recovery', () => {
`
)
// TODO(veil): ignore-list Webpack runtime (https://linear.app/vercel/issue/NDX-945)
// TODO(veil): Don't bail in Turbopack for sources outside of the project (https://linear.app/vercel/issue/NDX-944)
// We get an error because Foo didn't import React. Fair.
// Somehow we end up with two in React 18 due to React's attempt to recover from this error.
if (isReact18) {
@@ -642,8 +648,8 @@ describe('pages/ error recovery', () => {
"stack": [
"Foo Foo.js (3:3)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -660,8 +666,8 @@ describe('pages/ error recovery', () => {
"stack": [
"Foo Foo.js (3:3)",
"Set.forEach <anonymous> (0:0)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
"${isTurbopack ? '<FIXME-file-protocol>' : '<FIXME-next-dist-dir>'}",
],
}
`)
@@ -1482,10 +1482,10 @@ describe('Client Navigation', () => {
| ^",
"stack": [
"eval pages/error-in-the-browser-global-scope.js (2:9)",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-file-protocol>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
"<FIXME-next-dist-dir>",
],
}
`)
@@ -171,10 +171,10 @@ describe('non-root-project-monorepo', () => {
expect(normalizeStackTrace(await getRedboxCallStack(browser)))
.toMatchInlineSnapshot(`
"eval app/separate-file.ts (1:7)
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
innerArrowFunction app/source-maps-ssr/page.tsx (16:3)
innerFunction app/source-maps-ssr/page.tsx (12:3)
Page app/source-maps-ssr/page.tsx (6:5)"
@@ -216,10 +216,10 @@ describe('non-root-project-monorepo', () => {
expect(normalizeStackTrace(await getRedboxCallStack(browser)))
.toMatchInlineSnapshot(`
"eval app/separate-file.ts (1:7)
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-file-protocol>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
<FIXME-next-dist-dir>
innerArrowFunction app/source-maps-client/page.tsx (17:3)
innerFunction app/source-maps-client/page.tsx (13:3)
effectCallback app/source-maps-client/page.tsx (7:5)"