From db9f5988d274ce57674c98a2f5648a4b27a928dd Mon Sep 17 00:00:00 2001 From: eps1lon Date: Sat, 26 Oct 2024 22:07:52 +0200 Subject: [PATCH] Use consistent error formatting in terminal --- .../server/middleware-turbopack.ts | 20 -- .../react-dev-overlay/server/middleware.ts | 2 +- .../next/src/server/dev/log-app-dir-error.ts | 32 --- .../lib/router-utils/setup-dev-bundler.ts | 204 +----------------- 4 files changed, 3 insertions(+), 255 deletions(-) delete mode 100644 packages/next/src/server/dev/log-app-dir-error.ts diff --git a/packages/next/src/client/components/react-dev-overlay/server/middleware-turbopack.ts b/packages/next/src/client/components/react-dev-overlay/server/middleware-turbopack.ts index d33123342c8eea..8710e6516a385d 100644 --- a/packages/next/src/client/components/react-dev-overlay/server/middleware-turbopack.ts +++ b/packages/next/src/client/components/react-dev-overlay/server/middleware-turbopack.ts @@ -1,8 +1,6 @@ import type { IncomingMessage, ServerResponse } from 'http' import { badRequest, - findSourcePackage, - getOriginalCodeFrame, internalServerError, json, jsonString, @@ -81,24 +79,6 @@ function createStackFrame(searchParams: URLSearchParams) { } satisfies TurbopackStackFrame } -export async function createOriginalStackFrame( - project: Project, - frame: TurbopackStackFrame -): Promise { - 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, diff --git a/packages/next/src/client/components/react-dev-overlay/server/middleware.ts b/packages/next/src/client/components/react-dev-overlay/server/middleware.ts index fc0cb1ef6688e2..923dbccdf68083 100644 --- a/packages/next/src/client/components/react-dev-overlay/server/middleware.ts +++ b/packages/next/src/client/components/react-dev-overlay/server/middleware.ts @@ -176,7 +176,7 @@ export async function createOriginalStackFrame({ } } -export async function getSourceMapFromCompilation( +async function getSourceMapFromCompilation( id: string, compilation: webpack.Compilation ): Promise { diff --git a/packages/next/src/server/dev/log-app-dir-error.ts b/packages/next/src/server/dev/log-app-dir-error.ts deleted file mode 100644 index bc92f7025fe0ef..00000000000000 --- a/packages/next/src/server/dev/log-app-dir-error.ts +++ /dev/null @@ -1,32 +0,0 @@ -import isError from '../../lib/is-error' -import * as Log from '../../build/output/log' - -export function logAppDirError(err: unknown) { - if (isError(err) && err?.stack) { - const cleanedStack = err.stack.split('\n').map((line: string) => - // Remove 'webpack-internal:' noise from the path - line.replace(/(webpack-internal:\/\/\/|file:\/\/)(\(.*?\)\/)?/, '') - ) - const filteredStack = cleanedStack - // Only display stack frames from the user's code - .filter( - (line: string) => - !/^\s+at.+next[\\/]dist[\\/]compiled/.test(line) && - !/^\s+at.+node_modules[\\/]/.test(line) && - !/^\s+at.+node:internal[\\/]/.test(line) - ) - if (filteredStack.length === 1) { - // This is an error that happened outside of user code, keep full stack - Log.error(`Internal error: ${cleanedStack.join('\n')}`) - } else { - Log.error(filteredStack.join('\n')) - } - if (typeof (err as any).digest !== 'undefined') { - console.error(`digest: ${JSON.stringify((err as any).digest)}`) - } - - if (err.cause) console.error('Cause:', err.cause) - } else { - Log.error(err) - } -} diff --git a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index 1b396f3d6684ac..24e5c09152c6dd 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -10,7 +10,6 @@ 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' @@ -18,7 +17,6 @@ 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' @@ -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, @@ -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, @@ -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, @@ -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('') - ) - - 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 { @@ -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 { @@ -1179,70 +1046,3 @@ export async function setupDevBundler(opts: SetupOpts) { } export type DevBundler = Awaited> - -// Returns a trace rewritten through Turbopack's sourcemaps -async function traceTurbopackErrorStack( - project: Project, - error: Error, - frames: StackFrame[] -): Promise { - 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 `` 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') - ) -}