Skip to content

Commit

Permalink
Pass down ignored field to error overlay (#72925)
Browse files Browse the repository at this point in the history
  • Loading branch information
huozhi authored and wyattjoh committed Nov 28, 2024
1 parent a7fe58f commit 75d6917
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 69 deletions.
7 changes: 7 additions & 0 deletions packages/next/src/build/webpack/config/ignore-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function shouldIgnorePath(modulePath: string): boolean {
return (
modulePath.includes('node_modules') ||
// Only relevant for when Next.js is symlinked e.g. in the Next.js monorepo
modulePath.includes('next/dist')
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { bold, cyan, green, red, yellow } from '../../../../lib/picocolors'
import { SimpleWebpackError } from './simpleWebpackError'
import { createOriginalStackFrame } from '../../../../client/components/react-dev-overlay/server/middleware'
import {
createOriginalStackFrame,
getIgnoredSources,
} from '../../../../client/components/react-dev-overlay/server/middleware'
import type { webpack } from 'next/dist/compiled/webpack/webpack'

// Based on https://github.com/webpack/webpack/blob/fcdd04a833943394bbb0a9eeb54a962a24cc7e41/lib/stats/DefaultStatsFactoryPlugin.js#L422-L431
Expand Down Expand Up @@ -62,6 +65,7 @@ async function getSourceFrame(
source: {
type: 'bundle',
sourceMap,
ignoredSources: getIgnoredSources(sourceMap),
compilation,
moduleId,
modulePath: fileName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const CallStackFrame: React.FC<{

return (
<div data-nextjs-call-stack-frame>
<h3 data-nextjs-frame-expanded={Boolean(frame.expanded)}>
<h3 data-nextjs-frame-expanded={!frame.ignored}>
<HotlinkedText text={formattedMethod} />
</h3>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,29 @@ import { GroupedStackFrames } from './GroupedStackFrames'
export type RuntimeErrorProps = { error: ReadyRuntimeError }

export function RuntimeError({ error }: RuntimeErrorProps) {
const { frames } = error
const { firstFrame, allLeadingFrames, allCallStackFrames } =
React.useMemo(() => {
const filteredFrames = error.frames
// Filter out nodejs internal frames since you can't do anything about them.
// e.g. node:internal/timers shows up pretty often due to timers, but not helpful to users.
// Only present the last line before nodejs internal trace.
.filter((f) => !f.sourceStackFrame.file?.startsWith('node:'))

const firstFirstPartyFrameIndex = filteredFrames.findIndex(
const firstFirstPartyFrameIndex = frames.findIndex(
(entry) =>
entry.expanded &&
!entry.ignored &&
Boolean(entry.originalCodeFrame) &&
Boolean(entry.originalStackFrame)
)

return {
firstFrame: filteredFrames[firstFirstPartyFrameIndex] ?? null,
firstFrame: frames[firstFirstPartyFrameIndex] ?? null,
allLeadingFrames:
firstFirstPartyFrameIndex < 0
? []
: filteredFrames.slice(0, firstFirstPartyFrameIndex),
allCallStackFrames: filteredFrames.slice(firstFirstPartyFrameIndex + 1),
: frames.slice(0, firstFirstPartyFrameIndex),
allCallStackFrames: frames.slice(firstFirstPartyFrameIndex + 1),
}
}, [error.frames])
}, [frames])

const { leadingFramesGroupedByFramework, stackFramesGroupedByFramework } =
React.useMemo(() => {
const leadingFrames = allLeadingFrames.filter((f) => f.expanded)
const leadingFrames = allLeadingFrames.filter((f) => !f.ignored)

return {
stackFramesGroupedByFramework:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface OriginalStackFrame extends OriginalStackFrameResponse {
error: boolean
reason: string | null
external: boolean
expanded: boolean
ignored: boolean
sourceStackFrame: StackFrame
}

Expand Down Expand Up @@ -49,20 +49,15 @@ function getOriginalStackFrame(
error: false,
reason: null,
external: false,
expanded: !Boolean(
/* collapsed */
(source.file?.includes('node_modules') ||
body.originalStackFrame?.file?.includes('node_modules') ||
body.originalStackFrame?.file?.startsWith('[turbopack]/')) ??
true
),
sourceStackFrame: source,
originalStackFrame: body.originalStackFrame,
originalCodeFrame: body.originalCodeFrame || null,
sourcePackage: body.sourcePackage,
ignored: body.originalStackFrame?.ignored || false,
}
}

// TODO: merge this section into ignoredList handling
if (
source.file === '<anonymous>' ||
source.file === 'file://' ||
Expand All @@ -73,23 +68,23 @@ function getOriginalStackFrame(
error: false,
reason: null,
external: true,
expanded: false,
sourceStackFrame: source,
originalStackFrame: null,
originalCodeFrame: null,
sourcePackage: null,
ignored: true,
})
}

return _getOriginalStackFrame().catch((err: Error) => ({
error: true,
reason: err?.message ?? err?.toString() ?? 'Unknown Error',
external: false,
expanded: false,
sourceStackFrame: source,
originalStackFrame: null,
originalCodeFrame: null,
sourcePackage: null,
ignored: false,
}))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,29 @@ import type { Project, TurbopackStackFrame } from '../../../../build/swc/types'
import { getSourceMapFromFile } from '../internal/helpers/get-source-map-from-file'
import { findSourceMap } from 'node:module'

type IgnorableStackFrame = StackFrame & { ignored: boolean }

const currentSourcesByFile: Map<string, Promise<string | null>> = new Map()
export async function batchedTraceSource(
project: Project,
frame: TurbopackStackFrame
): Promise<{ frame: StackFrame; source: string | null } | undefined> {
): Promise<{ frame: IgnorableStackFrame; source: string | null } | undefined> {
const file = frame.file ? decodeURIComponent(frame.file) : undefined
if (!file) return

const sourceFrame = await project.traceSource(frame)
if (!sourceFrame) return

let source = null
let ignored = true
// Don't look up source for node_modules or internals. These can often be large bundled files.
if (
sourceFrame.file &&
!(sourceFrame.file.includes('node_modules') || sourceFrame.isInternal)
!(
sourceFrame.file.includes('node_modules') ||
// isInternal means resource starts with turbopack://[turbopack]
sourceFrame.isInternal
)
) {
let sourcePromise = currentSourcesByFile.get(sourceFrame.file)
if (!sourcePromise) {
Expand All @@ -46,18 +53,22 @@ export async function batchedTraceSource(
currentSourcesByFile.delete(sourceFrame.file!)
}, 100)
}

ignored = false
source = await sourcePromise
}

// TODO: get ignoredList from turbopack source map
const ignorableFrame = {
file: sourceFrame.file,
lineNumber: sourceFrame.line ?? 0,
column: sourceFrame.column ?? 0,
methodName: sourceFrame.methodName ?? frame.methodName ?? '<unknown>',
ignored,
arguments: [],
}

return {
frame: {
file: sourceFrame.file,
lineNumber: sourceFrame.line ?? 0,
column: sourceFrame.column ?? 0,
methodName: sourceFrame.methodName ?? frame.methodName ?? '<unknown>',
arguments: [],
},
frame: ignorableFrame,
source,
}
}
Expand Down
Loading

0 comments on commit 75d6917

Please sign in to comment.