Skip to content

Commit 6b0dfff

Browse files
committed
add ./ to relative paths to make it easier to understand
1 parent 2b7ca40 commit 6b0dfff

File tree

6 files changed

+83
-74
lines changed

6 files changed

+83
-74
lines changed

crates/napi/src/next_api/project.rs

+30-37
Original file line numberDiff line numberDiff line change
@@ -1125,44 +1125,37 @@ pub async fn project_trace_source(
11251125

11261126
let project_root_uri =
11271127
uri_from_file(project.container.project().project_root_path(), None).await? + "/";
1128-
let (file, original_file, is_internal) = if let Some(source_file) =
1129-
original_file.strip_prefix(&project_root_uri)
1130-
{
1131-
// Client code uses file://
1132-
(
1133-
get_relative_path_to(&current_directory_file_url, &original_file)
1134-
// TODO(sokra) remove this to include a ./ here to make it a relative path
1135-
.trim_start_matches("./")
1136-
.to_string(),
1137-
Some(source_file.to_string()),
1138-
false,
1139-
)
1140-
} else if let Some(source_file) =
1141-
original_file.strip_prefix(&*SOURCE_MAP_PREFIX_PROJECT)
1142-
{
1143-
// Server code uses turbopack://[project]
1144-
// TODO should this also be file://?
1145-
(
1146-
get_relative_path_to(
1147-
&current_directory_file_url,
1148-
&format!("{}{}", project_root_uri, source_file),
1128+
let (file, original_file, is_internal) =
1129+
if let Some(source_file) = original_file.strip_prefix(&project_root_uri) {
1130+
// Client code uses file://
1131+
(
1132+
get_relative_path_to(&current_directory_file_url, &original_file),
1133+
Some(source_file.to_string()),
1134+
false,
11491135
)
1150-
// TODO(sokra) remove this to include a ./ here to make it a relative path
1151-
.trim_start_matches("./")
1152-
.to_string(),
1153-
Some(source_file.to_string()),
1154-
false,
1155-
)
1156-
} else if let Some(source_file) = original_file.strip_prefix(SOURCE_MAP_PREFIX) {
1157-
// All other code like turbopack://[turbopack] is internal code
1158-
(source_file.to_string(), None, true)
1159-
} else {
1160-
bail!(
1161-
"Original file ({}) outside project ({})",
1162-
original_file,
1163-
project_root_uri
1164-
)
1165-
};
1136+
} else if let Some(source_file) =
1137+
original_file.strip_prefix(&*SOURCE_MAP_PREFIX_PROJECT)
1138+
{
1139+
// Server code uses turbopack://[project]
1140+
// TODO should this also be file://?
1141+
(
1142+
get_relative_path_to(
1143+
&current_directory_file_url,
1144+
&format!("{}{}", project_root_uri, source_file),
1145+
),
1146+
Some(source_file.to_string()),
1147+
false,
1148+
)
1149+
} else if let Some(source_file) = original_file.strip_prefix(SOURCE_MAP_PREFIX) {
1150+
// All other code like turbopack://[turbopack] is internal code
1151+
(source_file.to_string(), None, true)
1152+
} else {
1153+
bail!(
1154+
"Original file ({}) outside project ({})",
1155+
original_file,
1156+
project_root_uri
1157+
)
1158+
};
11661159

11671160
Ok(Some(StackFrame {
11681161
file,

packages/next/src/client/components/react-dev-overlay/server/middleware-turbopack.ts

+2-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import type { Project, TurbopackStackFrame } from '../../../../build/swc/types'
1919
import { getSourceMapFromFile } from '../internal/helpers/get-source-map-from-file'
2020
import { findSourceMap, type SourceMapPayload } from 'node:module'
2121
import { pathToFileURL } from 'node:url'
22+
import { relativeToCwd } from '../../../../server/lib/stack-trace-utils'
2223

2324
function shouldIgnorePath(modulePath: string): boolean {
2425
return (
@@ -234,9 +235,7 @@ async function nativeTraceSource(
234235
?.replace('__webpack_exports__.', '') ||
235236
'<unknown>',
236237
column: (originalPosition.column ?? 0) + 1,
237-
file: originalPosition.source?.startsWith('file://')
238-
? relativeToCwd(originalPosition.source)
239-
: originalPosition.source,
238+
file: relativeToCwd(originalPosition.source),
240239
lineNumber: originalPosition.line ?? 0,
241240
// TODO: c&p from async createOriginalStackFrame but why not frame.arguments?
242241
arguments: [],
@@ -253,12 +252,6 @@ async function nativeTraceSource(
253252
return undefined
254253
}
255254

256-
function relativeToCwd(file: string): string {
257-
const relPath = path.relative(process.cwd(), url.fileURLToPath(file))
258-
// TODO(sokra) include a ./ here to make it a relative path
259-
return relPath
260-
}
261-
262255
async function createOriginalStackFrame(
263256
project: Project,
264257
frame: TurbopackStackFrame
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { relative, isAbsolute } from 'path'
2+
import { fileURLToPath } from 'url'
3+
4+
// Formats a file url or absolute path as relative path relative to the current working directory.
5+
// It will start with ./ or ../ if it's a relative path.
6+
// It might be an absolute path if it's on a different drive on windows.
7+
// When the argument is not a file url or a absolute path, it will return the argument as is.
8+
export function relativeToCwd(file: string): string
9+
export function relativeToCwd(file: null): null
10+
export function relativeToCwd(file: string | null): string | null
11+
export function relativeToCwd(file: string | null): string | null {
12+
if (!file) {
13+
return file
14+
}
15+
if (file.startsWith('file://')) {
16+
file = fileURLToPath(file)
17+
} else if (!isAbsolute(file)) {
18+
return file
19+
}
20+
const relPath = relative(process.cwd(), file)
21+
if (isAbsolute(relPath)) {
22+
return relPath
23+
}
24+
if (relPath.startsWith('../')) {
25+
return relPath
26+
}
27+
return './' + relPath
28+
}

packages/next/src/server/patch-error-inspect.ts

+6-17
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import {
22
findSourceMap as nativeFindSourceMap,
33
type SourceMapPayload,
44
} from 'module'
5-
import * as path from 'path'
65
import * as url from 'url'
76
import type * as util from 'util'
87
import { SourceMapConsumer as SyncSourceMapConsumer } from 'next/dist/compiled/source-map'
@@ -11,6 +10,7 @@ import { parseStack } from '../client/components/react-dev-overlay/server/middle
1110
import { getOriginalCodeFrame } from '../client/components/react-dev-overlay/server/shared'
1211
import { workUnitAsyncStorage } from './app-render/work-unit-async-storage.external'
1312
import { dim } from '../lib/picocolors'
13+
import { relativeToCwd } from './lib/stack-trace-utils'
1414

1515
type FindSourceMapPayload = (
1616
sourceURL: string
@@ -66,22 +66,11 @@ function frameToString(frame: StackFrame): string {
6666
sourceLocation += `:${frame.column}`
6767
}
6868

69-
let fileLocation: string | null
70-
if (
71-
frame.file !== null &&
72-
frame.file.startsWith('file://') &&
73-
URL.canParse(frame.file)
74-
) {
75-
// If not relative to CWD, the path is ambiguous to IDEs and clicking will prompt to select the file first.
76-
// In a multi-app repo, this leads to potentially larger file names but will make clicking snappy.
77-
// There's no tradeoff for the cases where `dir` in `next dev [dir]` is omitted
78-
// since relative to cwd is both the shortest and snappiest.
79-
fileLocation = path.relative(process.cwd(), url.fileURLToPath(frame.file))
80-
} else if (frame.file !== null && frame.file.startsWith('/')) {
81-
fileLocation = path.relative(process.cwd(), frame.file)
82-
} else {
83-
fileLocation = frame.file
84-
}
69+
// If not relative to CWD, the path is ambiguous to IDEs and clicking will prompt to select the file first.
70+
// In a multi-app repo, this leads to potentially larger file names but will make clicking snappy.
71+
// There's no tradeoff for the cases where `dir` in `next dev [dir]` is omitted
72+
// since relative to cwd is both the shortest and snappiest.
73+
let fileLocation = relativeToCwd(frame.file)
8574

8675
return frame.methodName
8776
? ` at ${frame.methodName} (${fileLocation}${sourceLocation})`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Hide the method name when showing a stack trace in the error overlay or when displaying a stack trace in the console.
2+
export function isHiddenMethodName(methodName: string) {
3+
return /^(?:Object\.|Module\.)?(?:<anonymous>|eval|__TURBOPACK__module__evaluation__)$/.test(
4+
methodName
5+
)
6+
}

test/e2e/app-dir/non-root-project-monorepo/non-root-project-monorepo.test.ts

+11-11
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('non-root-project-monorepo', () => {
6666
if (isTurbopack) {
6767
// TODO the function name should be hidden
6868
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
69-
"app/source-maps-rsc/page.tsx (9:28) @ innerArrowFunction
69+
"./app/source-maps-rsc/page.tsx (9:28) @ innerArrowFunction
7070
7171
7 | }
7272
8 |
@@ -82,9 +82,9 @@ describe('non-root-project-monorepo', () => {
8282
"<unknown>
8383
[project]/apps/web/app/separate-file.ts [app-rsc] (ecmascript) (rsc://React/Server/file://<full-path>/apps/web/.next/server/chunks/ssr/apps_web_8d1c0a._.js (7:7)
8484
innerFunction
85-
app/source-maps-rsc/page.tsx (6:3)
85+
./app/source-maps-rsc/page.tsx (6:3)
8686
Page
87-
app/source-maps-rsc/page.tsx (2:3)"
87+
./app/source-maps-rsc/page.tsx (2:3)"
8888
`)
8989
} else {
9090
// TODO the function name is incorrect
@@ -120,7 +120,7 @@ describe('non-root-project-monorepo', () => {
120120
if (isTurbopack) {
121121
// TODO the function name should be hidden
122122
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
123-
"app/separate-file.ts (1:7) @ [project]/apps/web/app/separate-file.ts [app-client] (ecmascript)
123+
"./app/separate-file.ts (1:7) @ [project]/apps/web/app/separate-file.ts [app-client] (ecmascript)
124124
125125
> 1 | throw new Error('Expected error')
126126
| ^
@@ -129,11 +129,11 @@ describe('non-root-project-monorepo', () => {
129129
expect(normalizeStackTrace(await getRedboxCallStack(browser)))
130130
.toMatchInlineSnapshot(`
131131
"innerArrowFunction
132-
app/source-maps-ssr/page.tsx (11:28)
132+
./app/source-maps-ssr/page.tsx (11:28)
133133
innerFunction
134-
app/source-maps-ssr/page.tsx (8:3)
134+
./app/source-maps-ssr/page.tsx (8:3)
135135
Page
136-
app/source-maps-ssr/page.tsx (4:3)"
136+
./app/source-maps-ssr/page.tsx (4:3)"
137137
`)
138138
} else {
139139
// TODO the function name should be hidden
@@ -173,7 +173,7 @@ describe('non-root-project-monorepo', () => {
173173
if (isTurbopack) {
174174
// TODO the function name should be hidden
175175
expect(await getRedboxSource(browser)).toMatchInlineSnapshot(`
176-
"app/separate-file.ts (1:7) @ [project]/apps/web/app/separate-file.ts [app-client] (ecmascript)
176+
"./app/separate-file.ts (1:7) @ [project]/apps/web/app/separate-file.ts [app-client] (ecmascript)
177177
178178
> 1 | throw new Error('Expected error')
179179
| ^
@@ -182,11 +182,11 @@ describe('non-root-project-monorepo', () => {
182182
expect(normalizeStackTrace(await getRedboxCallStack(browser)))
183183
.toMatchInlineSnapshot(`
184184
"innerArrowFunction
185-
app/source-maps-client/page.tsx (16:28)
185+
./app/source-maps-client/page.tsx (16:28)
186186
innerFunction
187-
app/source-maps-client/page.tsx (13:3)
187+
./app/source-maps-client/page.tsx (13:3)
188188
effectCallback
189-
app/source-maps-client/page.tsx (7:5)"
189+
./app/source-maps-client/page.tsx (7:5)"
190190
`)
191191
} else {
192192
// TODO the function name should be hidden

0 commit comments

Comments
 (0)