Skip to content

Commit

Permalink
Use consistent error formatting in terminal
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon committed Oct 26, 2024
1 parent d1f7530 commit db9f598
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 255 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { IncomingMessage, ServerResponse } from 'http'
import {
badRequest,
findSourcePackage,
getOriginalCodeFrame,
internalServerError,
json,
jsonString,
Expand Down Expand Up @@ -81,24 +79,6 @@ function createStackFrame(searchParams: URLSearchParams) {
} satisfies TurbopackStackFrame
}

export async function createOriginalStackFrame(
project: Project,
frame: TurbopackStackFrame
): Promise<OriginalStackFrameResponse | null> {
const traced = await batchedTraceSource(project, frame)
if (!traced) {
const sourcePackage = findSourcePackage(frame)
if (sourcePackage) return { sourcePackage }
return null
}

return {
originalStackFrame: traced.frame,
originalCodeFrame: getOriginalCodeFrame(traced.frame, traced.source),
sourcePackage: findSourcePackage(traced.frame),
}
}

export function getOverlayMiddleware(project: Project) {
return async function (
req: IncomingMessage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export async function createOriginalStackFrame({
}
}

export async function getSourceMapFromCompilation(
async function getSourceMapFromCompilation(
id: string,
compilation: webpack.Compilation
): Promise<RawSourceMap | undefined> {
Expand Down
32 changes: 0 additions & 32 deletions packages/next/src/server/dev/log-app-dir-error.ts

This file was deleted.

204 changes: 2 additions & 202 deletions packages/next/src/server/lib/router-utils/setup-dev-bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import type { PropagateToWorkersField } from './types'
import type { NextJsHotReloaderInterface } from '../../dev/hot-reloader-types'

import { createDefineEnv } from '../../../build/swc'
import type { Project } from '../../../build/swc/types'
import fs from 'fs'
import { mkdir } from 'fs/promises'
import url from 'url'
import path from 'path'
import qs from 'querystring'
import Watchpack from 'next/dist/compiled/watchpack'
import { loadEnvConfig } from '@next/env'
import isError, { type NextError } from '../../../lib/is-error'
import findUp from 'next/dist/compiled/find-up'
import { buildCustomRoute } from './filesystem'
import * as Log from '../../../build/output/log'
Expand All @@ -30,7 +28,6 @@ import loadJsConfig from '../../../build/load-jsconfig'
import { createValidFileMatcher } from '../find-page-file'
import { eventCliSession } from '../../../telemetry/events'
import { getDefineEnv } from '../../../build/webpack/plugins/define-env-plugin'
import { logAppDirError } from '../../dev/log-app-dir-error'
import { getSortedRoutes } from '../../../shared/lib/router/utils'
import {
getStaticInfoIncludingLayouts,
Expand All @@ -49,7 +46,6 @@ import { generateInterceptionRoutesRewrites } from '../../../lib/generate-interc

import {
CLIENT_STATIC_FILES_PATH,
COMPILER_NAMES,
DEV_CLIENT_PAGES_MANIFEST,
DEV_CLIENT_MIDDLEWARE_MANIFEST,
PHASE_DEVELOPMENT_SERVER,
Expand All @@ -64,24 +60,11 @@ import {
getPossibleMiddlewareFilenames,
getPossibleInstrumentationHookFilenames,
} from '../../../build/utils'
import {
createOriginalStackFrame,
getSourceMapFromCompilation,
getSourceMapFromFile,
parseStack,
} from '../../../client/components/react-dev-overlay/server/middleware'
import {
batchedTraceSource,
createOriginalStackFrame as createOriginalTurboStackFrame,
} from '../../../client/components/react-dev-overlay/server/middleware-turbopack'
import type { OriginalStackFrameResponse } from '../../../client/components/react-dev-overlay/server/shared'
import { devPageFiles } from '../../../build/webpack/plugins/next-types-plugin/shared'
import type { LazyRenderServerInstance } from '../router-server'
import { HMR_ACTIONS_SENT_TO_BROWSER } from '../../dev/hot-reloader-types'
import { PAGE_TYPES } from '../../../lib/page-types'
import { createHotReloaderTurbopack } from '../../dev/hot-reloader-turbopack'
import { getErrorSource } from '../../../shared/lib/error-source'
import type { StackFrame } from 'next/dist/compiled/stacktrace-parser'
import { generateEncryptionKeyBase64 } from '../../app-render/encryption-utils-server'
import {
ModuleBuildError,
Expand Down Expand Up @@ -994,123 +977,7 @@ async function startWatcher(opts: SetupOpts) {
err: unknown,
type?: 'unhandledRejection' | 'uncaughtException' | 'warning' | 'app-dir'
) {
let usedOriginalStack = false

if (isError(err) && err.stack) {
try {
const frames = parseStack(err.stack!)
// Filter out internal edge related runtime stack
const frame = frames.find(
({ file }) =>
!file?.startsWith('eval') &&
!file?.includes('web/adapter') &&
!file?.includes('web/globals') &&
!file?.includes('sandbox/context') &&
!file?.includes('<anonymous>')
)

let originalFrame: OriginalStackFrameResponse | null = null
let isEdgeCompiler = false
const frameFile = frame?.file
if (frame?.lineNumber && frameFile) {
if (hotReloader.turbopackProject) {
try {
originalFrame = await createOriginalTurboStackFrame(
hotReloader.turbopackProject,
{
file: frameFile,
methodName: frame.methodName,
line: frame.lineNumber ?? 0,
column: frame.column ?? undefined,
isServer: true,
}
)
} catch {}
} else {
const moduleId = frameFile.replace(
/^(webpack-internal:\/\/\/|file:\/\/)/,
''
)
const modulePath = frameFile.replace(
/^(webpack-internal:\/\/\/|file:\/\/)(\(.*\)\/)?/,
''
)

const src = getErrorSource(err as Error)
isEdgeCompiler = src === COMPILER_NAMES.edgeServer
const compilation = (
isEdgeCompiler
? hotReloader.edgeServerStats?.compilation
: hotReloader.serverStats?.compilation
)!

const sourceMap = await (frame.file?.startsWith(path.sep) ||
frame.file?.startsWith('file:')
? getSourceMapFromFile(frame.file)
: getSourceMapFromCompilation(moduleId, compilation))

if (sourceMap) {
try {
originalFrame = await createOriginalStackFrame({
source: {
type: 'bundle',
sourceMap,
compilation,
moduleId,
modulePath,
},
frame,
rootDirectory: opts.dir,
errorMessage: err.message,
})
} catch {}
}
}

if (
originalFrame?.originalCodeFrame &&
originalFrame.originalStackFrame
) {
const { originalCodeFrame, originalStackFrame } = originalFrame
const { file, lineNumber, column, methodName } = originalStackFrame

Log[type === 'warning' ? 'warn' : 'error'](
`${file} (${lineNumber}:${column}) @ ${methodName}`
)

let errorToLog
if (isEdgeCompiler) {
errorToLog = err.message
} else if (isError(err) && hotReloader.turbopackProject) {
const stack = await traceTurbopackErrorStack(
hotReloader.turbopackProject,
err,
frames
)

const error: NextError = new Error(err.message)
error.stack = stack
error.digest = err.digest
errorToLog = error
} else {
errorToLog = err
}

logError(errorToLog, type)
console[type === 'warning' ? 'warn' : 'error'](originalCodeFrame)
usedOriginalStack = true
}
}
} catch (_) {
// failed to load original stack using source maps
// this un-actionable by users so we don't show the
// internal error and only show the provided stack
}
}

if (!usedOriginalStack) {
logError(err, type)
}
logError(err, type)
}

return {
Expand Down Expand Up @@ -1144,7 +1011,7 @@ function logError(
} else if (type === 'warning') {
Log.warn(err)
} else if (type === 'app-dir') {
logAppDirError(err)
Log.error(err)
} else if (type) {
Log.error(`${type}:`, err)
} else {
Expand Down Expand Up @@ -1179,70 +1046,3 @@ export async function setupDevBundler(opts: SetupOpts) {
}

export type DevBundler = Awaited<ReturnType<typeof setupDevBundler>>

// Returns a trace rewritten through Turbopack's sourcemaps
async function traceTurbopackErrorStack(
project: Project,
error: Error,
frames: StackFrame[]
): Promise<string> {
let originalFrames = await Promise.all(
frames.map(async (f) => {
try {
const traced = await batchedTraceSource(project, {
file: f.file!,
methodName: f.methodName,
line: f.lineNumber ?? 0,
column: f.column ?? undefined,
isServer: true,
})

return traced?.frame ?? f
} catch {
return f
}
})
)

return (
error.name +
': ' +
error.message +
'\n' +
originalFrames
.map((f) => {
if (f == null) {
return null
}

let line = ' at'
if (f.methodName != null) {
line += ' ' + f.methodName
}

if (f.file != null) {
const file =
f.file.startsWith('/') ||
// Built-in "filenames" like `<anonymous>` shouldn't be made relative
f.file.startsWith('<') ||
f.file.startsWith('node:')
? f.file
: `./${f.file}`

line += ` (${file}`
if (f.lineNumber != null) {
line += ':' + f.lineNumber

if (f.column != null) {
line += ':' + f.column
}
}
line += ')'
}

return line
})
.filter(Boolean)
.join('\n')
)
}

0 comments on commit db9f598

Please sign in to comment.