Turbopack: Trace edge runtime app render errors through source maps (#62901)
Similar to #62611, this implements error stack translation for edge runtime app render errors. Test Plan: `TURBOPACK=1 pnpm test-dev test/development/app-render-error-log/app-render-error-log.test.ts` Closes PACK-2665
This commit is contained in:
parent
0d3481b6b2
commit
f9aec9005a
7 changed files with 24 additions and 10 deletions
|
@ -4,6 +4,10 @@ import { SpanStatusCode, getTracer } from '../lib/trace/tracer'
|
|||
import { isAbortError } from '../pipe-readable'
|
||||
import { isDynamicUsageError } from '../../export/helpers/is-dynamic-usage-error'
|
||||
|
||||
declare global {
|
||||
var __next_log_error__: undefined | ((err: unknown) => void)
|
||||
}
|
||||
|
||||
export type ErrorHandler = (
|
||||
err: unknown,
|
||||
errorInfo: unknown
|
||||
|
@ -98,12 +102,10 @@ export function createErrorHandler({
|
|||
errorLogger(err).catch(() => {})
|
||||
} else {
|
||||
// The error logger is currently not provided in the edge runtime.
|
||||
// Use `log-app-dir-error` instead.
|
||||
// It won't log the source code, but the error will be more useful.
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const { logAppDirError } =
|
||||
require('../dev/log-app-dir-error') as typeof import('../dev/log-app-dir-error')
|
||||
logAppDirError(err)
|
||||
// Use the exposed `__next_log_error__` instead.
|
||||
// This will trace error traces to the original source code.
|
||||
if (typeof __next_log_error__ === 'function') {
|
||||
__next_log_error__(err)
|
||||
} else {
|
||||
console.error(err)
|
||||
}
|
||||
|
|
|
@ -432,6 +432,7 @@ export default class DevServer extends Server {
|
|||
try {
|
||||
return super.runEdgeFunction({
|
||||
...params,
|
||||
onError: (err) => this.logErrorWithOriginalStack(err, 'app-dir'),
|
||||
onWarning: (warn) => {
|
||||
this.logErrorWithOriginalStack(warn, 'warning')
|
||||
},
|
||||
|
|
|
@ -1815,6 +1815,7 @@ export default class NextNodeServer extends BaseServer {
|
|||
page: string
|
||||
appPaths: string[] | null
|
||||
match?: RouteMatch
|
||||
onError?: (err: unknown) => void
|
||||
onWarning?: (warning: Error) => void
|
||||
}): Promise<FetchEventResult | null> {
|
||||
if (process.env.NEXT_MINIMAL) {
|
||||
|
@ -1890,6 +1891,7 @@ export default class NextNodeServer extends BaseServer {
|
|||
),
|
||||
},
|
||||
useCache: true,
|
||||
onError: params.onError,
|
||||
onWarning: params.onWarning,
|
||||
incrementalCache:
|
||||
(globalThis as any).__incrementalCache ||
|
||||
|
|
|
@ -264,6 +264,12 @@ async function createModuleContext(options: ModuleContextOptions) {
|
|||
},
|
||||
})
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
context.__next_log_error__ = function (err: unknown) {
|
||||
options.onError(err)
|
||||
}
|
||||
}
|
||||
|
||||
context.__next_eval__ = function __next_eval__(fn: Function) {
|
||||
const key = fn.toString()
|
||||
if (!warnedEvals.has(key)) {
|
||||
|
@ -458,6 +464,7 @@ Learn More: https://nextjs.org/docs/messages/edge-dynamic-code-evaluation`),
|
|||
|
||||
interface ModuleContextOptions {
|
||||
moduleName: string
|
||||
onError: (err: unknown) => void
|
||||
onWarning: (warn: Error) => void
|
||||
useCache: boolean
|
||||
distDir: string
|
||||
|
|
|
@ -15,6 +15,7 @@ const FORBIDDEN_HEADERS = [
|
|||
|
||||
type RunnerFn = (params: {
|
||||
name: string
|
||||
onError?: (err: unknown) => void
|
||||
onWarning?: (warn: Error) => void
|
||||
paths: string[]
|
||||
request: NodejsRequestData
|
||||
|
@ -54,6 +55,7 @@ function withTaggedErrors(fn: RunnerFn): RunnerFn {
|
|||
export async function getRuntimeContext(params: {
|
||||
name: string
|
||||
onWarning?: any
|
||||
onError?: (err: unknown) => void
|
||||
useCache: boolean
|
||||
edgeFunctionEntry: any
|
||||
distDir: string
|
||||
|
@ -63,6 +65,7 @@ export async function getRuntimeContext(params: {
|
|||
const { runtime, evaluateInContext } = await getModuleContext({
|
||||
moduleName: params.name,
|
||||
onWarning: params.onWarning ?? (() => {}),
|
||||
onError: params.onError ?? (() => {}),
|
||||
useCache: params.useCache !== false,
|
||||
edgeFunctionEntry: params.edgeFunctionEntry,
|
||||
distDir: params.distDir,
|
||||
|
|
|
@ -33,7 +33,7 @@ createNextDescribe(
|
|||
await check(() => cliOutput, /digest:/)
|
||||
expect(cliOutput).toInclude('Error: boom')
|
||||
expect(cliOutput).toInclude('at fn2 (./app/fn.ts')
|
||||
expect(cliOutput).toInclude('at fn1 (./app/fn.ts')
|
||||
expect(cliOutput).toMatch(/at (Module\.)?fn1 \(\.\/app\/fn\.ts/)
|
||||
expect(cliOutput).toInclude('at EdgePage (./app/edge/page.tsx')
|
||||
|
||||
expect(cliOutput).not.toInclude('webpack-internal')
|
||||
|
|
|
@ -1514,11 +1514,10 @@
|
|||
},
|
||||
"test/development/app-render-error-log/app-render-error-log.test.ts": {
|
||||
"passed": [
|
||||
"app-render-error-log should log the correct values on app-render error"
|
||||
],
|
||||
"failed": [
|
||||
"app-render-error-log should log the correct values on app-render error",
|
||||
"app-render-error-log should log the correct values on app-render error with edge runtime"
|
||||
],
|
||||
"failed": [],
|
||||
"pending": [],
|
||||
"flakey": [],
|
||||
"runtimeError": false
|
||||
|
|
Loading…
Reference in a new issue