diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 35200812420e3..127af725a8a17 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -600,12 +600,16 @@ export interface HmrIdentifiers { identifiers: string[] } -interface TurbopackStackFrame { - column: number | null - file: string +/** @see https://github.com/vercel/next.js/blob/415cd74b9a220b6f50da64da68c13043e9b02995/packages/next-swc/crates/napi/src/next_api/project.rs#L824-L833 */ +export interface TurbopackStackFrame { isServer: boolean - line: number - methodName: string | null + isInternal?: boolean + file: string + /** 1-indexed, unlike source map tokens */ + line?: number + /** 1-indexed, unlike source map tokens */ + column?: number | null + methodName?: string } export type UpdateMessage = diff --git a/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts b/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts index 5d50db00c18cc..2e299d6a14978 100644 --- a/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts +++ b/packages/next/src/build/webpack/plugins/wellknown-errors-plugin/parseNotFoundError.ts @@ -49,18 +49,21 @@ async function getSourceFrame( compilation: any ): Promise<{ frame: string; lineNumber: string; column: string }> { try { - const loc = input.loc - ? input.loc - : input.dependencies.map((d: any) => d.loc).filter(Boolean)[0] + const loc = + input.loc || input.dependencies.map((d: any) => d.loc).filter(Boolean)[0] const originalSource = input.module.originalSource() const result = await createOriginalStackFrame({ - line: loc.start.line, - column: loc.start.column, source: originalSource, rootDirectory: compilation.options.context!, modulePath: fileName, - frame: {}, + frame: { + arguments: [], + file: fileName, + methodName: '', + lineNumber: loc.start.line, + column: loc.start.column, + }, }) return { diff --git a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/CallStackFrame.tsx b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/CallStackFrame.tsx index 8b5613229f79b..5c796f32abb03 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/CallStackFrame.tsx +++ b/packages/next/src/client/components/react-dev-overlay/internal/container/RuntimeError/CallStackFrame.tsx @@ -1,4 +1,3 @@ -import React from 'react' import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' import { getFrameSource, 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 150fd21e2a85e..5768b17925cab 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,47 +1,36 @@ import type { IncomingMessage, ServerResponse } from 'http' -import { findSourcePackage, type OriginalStackFrameResponse } from './shared' +import { + badRequest, + findSourcePackage, + getOriginalCodeFrame, + internalServerError, + json, + noContent, + type OriginalStackFrameResponse, +} from './shared' import fs, { constants as FS } from 'fs/promises' -import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame' import { launchEditor } from '../internal/helpers/launchEditor' - -interface Project { - getSourceForAsset(filePath: string): Promise - traceSource( - stackFrame: TurbopackStackFrame - ): Promise -} - -interface TurbopackStackFrame { - // 1-based - column: number | null - // 1-based - file: string - isServer: boolean - line: number | null - methodName: string | null - isInternal?: boolean -} +import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' +import type { Project, TurbopackStackFrame } from '../../../../build/swc' const currentSourcesByFile: Map> = new Map() export async function batchedTraceSource( project: Project, frame: TurbopackStackFrame -) { +): Promise<{ frame: StackFrame; source: string | null } | undefined> { const file = frame.file ? decodeURIComponent(frame.file) : undefined - if (!file) { - return - } + if (!file) return const sourceFrame = await project.traceSource(frame) - - if (!sourceFrame) { - return - } - - let source - // Don't show code frames for node_modules. These can also often be large bundled files. - if (!sourceFrame.file.includes('node_modules') && !sourceFrame.isInternal) { + if (!sourceFrame) return + + let source = null + // 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) + ) { let sourcePromise = currentSourcesByFile.get(sourceFrame.file) if (!sourcePromise) { sourcePromise = project.getSourceForAsset(sourceFrame.file) @@ -49,7 +38,7 @@ export async function batchedTraceSource( setTimeout(() => { // Cache file reads for 100ms, as frames will often reference the same // files and can be large. - currentSourcesByFile.delete(sourceFrame.file) + currentSourcesByFile.delete(sourceFrame.file!) }, 100) } @@ -59,12 +48,12 @@ export async function batchedTraceSource( return { frame: { file: sourceFrame.file, - lineNumber: sourceFrame.line, - column: sourceFrame.column, + lineNumber: sourceFrame.line ?? 0, + column: sourceFrame.column ?? 0, methodName: sourceFrame.methodName ?? frame.methodName ?? '', arguments: [], }, - source: source ?? null, + source, } } @@ -74,29 +63,15 @@ export async function createOriginalStackFrame( ): Promise { const traced = await batchedTraceSource(project, frame) if (!traced) { - const sourcePackage = findSourcePackage(frame.file) + const sourcePackage = findSourcePackage(frame) if (sourcePackage) return { sourcePackage } return null } return { originalStackFrame: traced.frame, - originalCodeFrame: - traced.source === null - ? null - : codeFrameColumns( - traced.source, - { - start: { - // 1-based, but -1 means start line without highlighting - line: traced.frame.lineNumber ?? -1, - // 1-based, but 0 means whole line without column highlighting - column: traced.frame.column ?? 0, - }, - }, - { forceColor: true } - ), - sourcePackage: findSourcePackage(traced.frame.file), + originalCodeFrame: getOriginalCodeFrame(traced.frame, traced.source), + sourcePackage: findSourcePackage(traced.frame), } } @@ -106,7 +81,7 @@ export function getOverlayMiddleware(project: Project) { const frame = { file: searchParams.get('file') as string, - methodName: searchParams.get('methodName'), + methodName: searchParams.get('methodName') ?? '', line: parseInt(searchParams.get('lineNumber') ?? '0', 10) || 0, column: parseInt(searchParams.get('column') ?? '0', 10) || 0, isServer: searchParams.get('isServer') === 'true', @@ -117,55 +92,32 @@ export function getOverlayMiddleware(project: Project) { try { originalStackFrame = await createOriginalStackFrame(project, frame) } catch (e: any) { - res.statusCode = 500 - res.write(e.message) - res.end() - return + return internalServerError(res, e.message) } - if (originalStackFrame === null) { + if (!originalStackFrame) { res.statusCode = 404 - res.write('Unable to resolve sourcemap') - res.end() - return + return res.end('Unable to resolve sourcemap') } - res.statusCode = 200 - res.setHeader('Content-Type', 'application/json') - res.write(Buffer.from(JSON.stringify(originalStackFrame))) - res.end() - return + return json(res, originalStackFrame) } else if (pathname === '/__nextjs_launch-editor') { - if (!frame.file) { - res.statusCode = 400 - res.write('Bad Request') - res.end() - return - } + if (!frame.file) return badRequest(res) const fileExists = await fs.access(frame.file, FS.F_OK).then( () => true, () => false ) - if (!fileExists) { - res.statusCode = 204 - res.write('No Content') - res.end() - return - } + if (!fileExists) return noContent(res) try { launchEditor(frame.file, frame.line ?? 1, frame.column ?? 1) } catch (err) { console.log('Failed to launch editor:', err) - res.statusCode = 500 - res.write('Internal Server Error') - res.end() - return + return internalServerError(res) } - res.statusCode = 204 - res.end() + noContent(res) } } } 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 9b593fae18d94..66ed55511bff9 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 @@ -1,23 +1,23 @@ -import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame' import { constants as FS, promises as fs } from 'fs' -import type { IncomingMessage, ServerResponse } from 'http' import path from 'path' import { SourceMapConsumer } from 'next/dist/compiled/source-map08' import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' -import url from 'url' -import type webpack from 'webpack' import { getRawSourceMap } from '../internal/helpers/getRawSourceMap' import { launchEditor } from '../internal/helpers/launchEditor' -import { findSourcePackage, type OriginalStackFrameResponse } from './shared' +import { + badRequest, + findSourcePackage, + getOriginalCodeFrame, + internalServerError, + json, + noContent, + type OriginalStackFrameResponse, +} from './shared' export { getServerError } from '../internal/helpers/nodeStackFrames' export { parseStack } from '../internal/helpers/parseStack' -export type OverlayMiddlewareOptions = { - rootDirectory: string - stats(): webpack.Stats | null - serverStats(): webpack.Stats | null - edgeServerStats(): webpack.Stats | null -} +import type { IncomingMessage, ServerResponse } from 'http' +import type webpack from 'webpack' type Source = { map: () => any } | null @@ -29,43 +29,25 @@ function getModuleById( id: string | undefined, compilation: webpack.Compilation ) { - return [...compilation.modules].find((searchModule) => { - const moduleId = getModuleId(compilation, searchModule) - return moduleId === id - }) + return [...compilation.modules].find( + (searchModule) => getModuleId(compilation, searchModule) === id + ) } function findModuleNotFoundFromError(errorMessage: string | undefined) { - const match = errorMessage?.match(/'([^']+)' module/) - return match && match[1] + return errorMessage?.match(/'([^']+)' module/)?.[1] } function getModuleSource(compilation: any, module: any): any { + if (!module) return null return ( - (module && - compilation.codeGenerationResults - .get(module) - ?.sources.get('javascript')) ?? + compilation.codeGenerationResults.get(module)?.sources.get('javascript') ?? null ) } function getSourcePath(source: string) { - // Webpack prefixes certain source paths with this path - if (source.startsWith('webpack:///')) { - return source.substring(11) - } - - // Make sure library name is filtered out as well - if (source.startsWith('webpack://_N_E/')) { - return source.substring(15) - } - - if (source.startsWith('webpack://')) { - return source.substring(10) - } - - return source + return source.replace(/^(webpack:\/\/\/|webpack:\/\/|webpack:\/\/_N_E\/)/, '') } async function findOriginalSourcePositionAndContent( @@ -108,81 +90,45 @@ function findOriginalSourcePositionAndContentFromCompilation( } export async function createOriginalStackFrame({ - line, - column, source, moduleId, modulePath, rootDirectory, frame, errorMessage, - clientCompilation, - serverCompilation, - edgeCompilation, + compilation, }: { - line: number - column: number | null source: any moduleId?: string modulePath?: string rootDirectory: string - frame: any + frame: StackFrame errorMessage?: string - clientCompilation?: webpack.Compilation - serverCompilation?: webpack.Compilation - edgeCompilation?: webpack.Compilation + compilation?: webpack.Compilation }): Promise { + const { lineNumber, column } = frame const moduleNotFound = findModuleNotFoundFromError(errorMessage) const result = await (async () => { if (moduleNotFound) { - let moduleNotFoundResult = null - - if (clientCompilation) { - moduleNotFoundResult = - findOriginalSourcePositionAndContentFromCompilation( - moduleId, - moduleNotFound, - clientCompilation - ) - } - - if (moduleNotFoundResult === null && serverCompilation) { - moduleNotFoundResult = - findOriginalSourcePositionAndContentFromCompilation( - moduleId, - moduleNotFound, - serverCompilation - ) - } - - if (moduleNotFoundResult === null && edgeCompilation) { - moduleNotFoundResult = - findOriginalSourcePositionAndContentFromCompilation( - moduleId, - moduleNotFound, - edgeCompilation - ) - } + if (!compilation) return null - return moduleNotFoundResult + return findOriginalSourcePositionAndContentFromCompilation( + moduleId, + moduleNotFound, + compilation + ) } // This returns 1-based lines and 0-based columns return await findOriginalSourcePositionAndContent(source, { - line, + line: lineNumber ?? 1, column, }) })() - if (result === null) { - return null - } + if (!result?.sourcePosition.source) return null const { sourcePosition, sourceContent } = result - if (!sourcePosition.source) { - return null - } - const filePath = path.resolve( rootDirectory, getSourcePath( @@ -193,7 +139,7 @@ export async function createOriginalStackFrame({ ) ) - const originalFrame: StackFrame = { + const traced = { file: sourceContent ? path.relative(rootDirectory, filePath) : sourcePosition.source, @@ -207,28 +153,12 @@ export async function createOriginalStackFrame({ ?.replace('__WEBPACK_DEFAULT_EXPORT__', 'default') ?.replace('__webpack_exports__.', ''), arguments: [], - } - - const originalCodeFrame: string | null = - !(originalFrame.file?.includes('node_modules') ?? true) && - sourceContent && - sourcePosition.line - ? (codeFrameColumns( - sourceContent, - { - start: { - line: sourcePosition.line, - column: (sourcePosition.column ?? 0) + 1, - }, - }, - { forceColor: true } - ) as string) - : null + } satisfies StackFrame return { - originalStackFrame: originalFrame, - originalCodeFrame, - sourcePackage: findSourcePackage(filePath) ?? null, + originalStackFrame: traced, + originalCodeFrame: getOriginalCodeFrame(traced, sourceContent), + sourcePackage: findSourcePackage(traced), } } @@ -272,45 +202,44 @@ export async function getSourceById( } } -function getOverlayMiddleware(options: OverlayMiddlewareOptions) { +export function getOverlayMiddleware(options: { + rootDirectory: string + stats(): webpack.Stats | null + serverStats(): webpack.Stats | null + edgeServerStats(): webpack.Stats | null +}) { return async function ( req: IncomingMessage, res: ServerResponse, next: Function ) { - const { pathname, query } = url.parse(req.url!, true) + const { pathname, searchParams } = new URL(`http://n${req.url}`) + + const frame = { + file: searchParams.get('file') as string, + methodName: searchParams.get('methodName') as string, + lineNumber: parseInt(searchParams.get('lineNumber') ?? '0', 10) || 0, + column: parseInt(searchParams.get('column') ?? '0', 10) || 0, + arguments: searchParams.getAll('arguments').filter(Boolean), + } satisfies StackFrame + + const isServer = searchParams.get('isServer') === 'true' + const isEdgeServer = searchParams.get('isEdgeServer') === 'true' + const isAppDirectory = searchParams.get('isAppDirectory') === 'true' if (pathname === '/__nextjs_original-stack-frame') { - const frame = query as unknown as StackFrame & { - isEdgeServer: 'true' | 'false' - isServer: 'true' | 'false' - isAppDirectory: 'true' | 'false' - errorMessage: string | undefined - } - const isAppDirectory = frame.isAppDirectory === 'true' - const isServerError = frame.isServer === 'true' - const isEdgeServerError = frame.isEdgeServer === 'true' - const isClientError = !isServerError && !isEdgeServerError + const isClient = !isServer && !isEdgeServer - let sourcePackage = findSourcePackage(frame.file) + let sourcePackage = findSourcePackage(frame) if ( !( - (frame.file?.startsWith('webpack-internal:///') || - frame.file?.startsWith('file://') || - frame.file?.startsWith('webpack://')) && - Boolean(parseInt(frame.lineNumber?.toString() ?? '', 10)) + /^(webpack-internal:\/\/\/|(file|webpack):\/\/)/.test(frame.file) && + frame.lineNumber ) ) { - if (sourcePackage) { - res.statusCode = 200 - res.setHeader('Content-Type', 'application/json') - res.write(Buffer.from(JSON.stringify({ sourcePackage }))) - return res.end() - } - res.statusCode = 400 - res.write('Bad Request') - return res.end() + if (sourcePackage) return json(res, { sourcePackage }) + return badRequest(res) } const moduleId: string = frame.file.replace( @@ -324,136 +253,84 @@ function getOverlayMiddleware(options: OverlayMiddlewareOptions) { let source: Source = null - const clientCompilation = options.stats()?.compilation - const serverCompilation = options.serverStats()?.compilation - const edgeCompilation = options.edgeServerStats()?.compilation + let compilation: webpack.Compilation | undefined + const isFile = frame.file.startsWith('file:') try { - if (isClientError || isAppDirectory) { + if (isClient || isAppDirectory) { + compilation = options.stats()?.compilation // Try Client Compilation first // In `pages` we leverage `isClientError` to check // In `app` it depends on if it's a server / client component and when the code throws. E.g. during HTML rendering it's the server/edge compilation. - source = await getSourceById(isFile, moduleId, clientCompilation) + source = await getSourceById(isFile, moduleId, compilation) } // Try Server Compilation // In `pages` this could be something imported in getServerSideProps/getStaticProps as the code for those is tree-shaken. // In `app` this finds server components and code that was imported from a server component. It also covers when client component code throws during HTML rendering. - if ((isServerError || isAppDirectory) && source === null) { - source = await getSourceById(isFile, moduleId, serverCompilation) + if ((isServer || isAppDirectory) && source === null) { + compilation = options.serverStats()?.compilation + source = await getSourceById(isFile, moduleId, compilation) } // Try Edge Server Compilation // Both cases are the same as Server Compilation, main difference is that it covers `runtime: 'edge'` pages/app routes. - if ((isEdgeServerError || isAppDirectory) && source === null) { - source = await getSourceById(isFile, moduleId, edgeCompilation) + if ((isEdgeServer || isAppDirectory) && source === null) { + compilation = options.edgeServerStats()?.compilation + source = await getSourceById(isFile, moduleId, compilation) } } catch (err) { console.log('Failed to get source map:', err) - res.statusCode = 500 - res.write('Internal Server Error') - return res.end() - } - - if (source == null) { - if (sourcePackage) { - res.statusCode = 200 - res.setHeader('Content-Type', 'application/json') - res.write(Buffer.from(JSON.stringify({ sourcePackage }))) - return res.end() - } - res.statusCode = 204 - res.write('No Content') - return res.end() + return internalServerError(res) } - const frameLine = parseInt(frame.lineNumber?.toString() ?? '', 10) - let frameColumn: number | null = parseInt( - frame.column?.toString() ?? '', - 10 - ) - if (!frameColumn) { - frameColumn = null + if (!source) { + if (sourcePackage) return json(res, { sourcePackage }) + return noContent(res) } try { const originalStackFrameResponse = await createOriginalStackFrame({ - line: frameLine, - column: frameColumn, - source, frame, + source, moduleId, modulePath, rootDirectory: options.rootDirectory, - errorMessage: frame.errorMessage, - clientCompilation: isClientError ? clientCompilation : undefined, - serverCompilation: isServerError ? serverCompilation : undefined, - edgeCompilation: isEdgeServerError ? edgeCompilation : undefined, + compilation, }) if (originalStackFrameResponse === null) { - if (sourcePackage) { - res.statusCode = 200 - res.setHeader('Content-Type', 'application/json') - res.write(Buffer.from(JSON.stringify({ sourcePackage }))) - return res.end() - } - res.statusCode = 204 - res.write('No Content') - return res.end() + if (sourcePackage) return json(res, { sourcePackage }) + return noContent(res) } - res.statusCode = 200 - res.setHeader('Content-Type', 'application/json') - res.write(Buffer.from(JSON.stringify(originalStackFrameResponse))) - return res.end() + return json(res, originalStackFrameResponse) } catch (err) { console.log('Failed to parse source map:', err) - res.statusCode = 500 - res.write('Internal Server Error') - return res.end() + return internalServerError(res) } } else if (pathname === '/__nextjs_launch-editor') { - const frame = query as unknown as StackFrame - - const frameFile = frame.file?.toString() || null - if (frameFile == null) { - res.statusCode = 400 - res.write('Bad Request') - return res.end() - } + if (!frame.file) return badRequest(res) // frame files may start with their webpack layer, like (middleware)/middleware.js const filePath = path.resolve( options.rootDirectory, - frameFile.replace(/^\([^)]+\)\//, '') + frame.file.replace(/^\([^)]+\)\//, '') ) const fileExists = await fs.access(filePath, FS.F_OK).then( () => true, () => false ) - if (!fileExists) { - res.statusCode = 204 - res.write('No Content') - return res.end() - } - - const frameLine = parseInt(frame.lineNumber?.toString() ?? '', 10) || 1 - const frameColumn = parseInt(frame.column?.toString() ?? '', 10) || 1 + if (!fileExists) return noContent(res) try { - await launchEditor(filePath, frameLine, frameColumn) + await launchEditor(filePath, frame.lineNumber, frame.column ?? 1) } catch (err) { console.log('Failed to launch editor:', err) - res.statusCode = 500 - res.write('Internal Server Error') - return res.end() + return internalServerError(res) } - res.statusCode = 204 - return res.end() + return noContent(res) } return next() } } - -export { getOverlayMiddleware } diff --git a/packages/next/src/client/components/react-dev-overlay/server/shared.ts b/packages/next/src/client/components/react-dev-overlay/server/shared.ts index 501e0bc819e9e..a9f098a5703ad 100644 --- a/packages/next/src/client/components/react-dev-overlay/server/shared.ts +++ b/packages/next/src/client/components/react-dev-overlay/server/shared.ts @@ -1,8 +1,10 @@ import type { StackFrame } from 'stacktrace-parser' +import type { ServerResponse } from 'http' +import { codeFrameColumns } from 'next/dist/compiled/babel/code-frame' export type SourcePackage = 'react' | 'next' -export type OriginalStackFrameResponse = { +export interface OriginalStackFrameResponse { originalStackFrame?: StackFrame | null originalCodeFrame?: string | null /** We use this to group frames in the error overlay */ @@ -16,19 +18,91 @@ const reactVendoredRe = /** React the user installed. Used by Pages Router, or user imports in App Router. */ const reactNodeModulesRe = /node_modules[\\/](react|react-dom|scheduler)[\\/]/ -const nextRe = - /(node_modules[\\/]next[\\/]|[\\/].next[\\/]static[\\/]chunks[\\/]webpack\.js$)/ +const nextInternalsRe = + /(node_modules[\\/]next[\\/]|[\\/].next[\\/]static[\\/]chunks[\\/]webpack\.js$|(edge-runtime-webpack|webpack-runtime)\.js$)/ -/** Given a potential file path, it parses which package the file belongs to. */ -export function findSourcePackage( - file: string | null -): SourcePackage | undefined { - if (!file) return +const nextMethodRe = /(^__webpack_.*|node_modules[\\/]next[\\/])/ - // matching React first since vendored would match under `next` too - if (reactVendoredRe.test(file) || reactNodeModulesRe.test(file)) { - return 'react' - } else if (nextRe.test(file)) { - return 'next' +function isInternal(file: string | null) { + if (!file) return false + + return ( + nextInternalsRe.test(file) || + reactVendoredRe.test(file) || + reactNodeModulesRe.test(file) + ) +} + +/** Given a frame, it parses which package it belongs to. */ +export function findSourcePackage({ + file, + methodName, +}: Partial<{ file: string | null; methodName: string | null }>): + | SourcePackage + | undefined { + if (file) { + // matching React first since vendored would match under `next` too + if (reactVendoredRe.test(file) || reactNodeModulesRe.test(file)) { + return 'react' + } else if (nextInternalsRe.test(file)) { + return 'next' + } + } + + if (methodName) { + if (nextMethodRe.test(methodName)) { + return 'next' + } } } + +/** + * It looks up the code frame of the traced source. + * @note It ignores node_modules or Next.js/React internals, as these can often be huge budnled files. + */ +export function getOriginalCodeFrame( + frame: StackFrame, + source: string | null +): string | null | undefined { + if ( + !source || + frame.file?.includes('node_modules') || + isInternal(frame.file) + ) { + return null + } + + return codeFrameColumns( + source, + { + start: { + // 1-based, but -1 means start line without highlighting + line: frame.lineNumber ?? -1, + // 1-based, but 0 means whole line without column highlighting + column: frame.column ?? 0, + }, + }, + { forceColor: true } + ) +} + +export function noContent(res: ServerResponse) { + res.statusCode = 204 + res.end('No Content') +} + +export function badRequest(res: ServerResponse) { + res.statusCode = 400 + res.end('Bad Request') +} + +export function internalServerError(res: ServerResponse, e?: any) { + res.statusCode = 500 + res.end(e ?? 'Internal Server Error') +} + +export function json(res: ServerResponse, data: any) { + res + .setHeader('Content-Type', 'application/json') + .end(Buffer.from(JSON.stringify(data))) +} 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 2ffa2a9a68aae..9f5ffc4bc0b7f 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 @@ -74,7 +74,7 @@ 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 'stacktrace-parser' +import type { StackFrame } from 'next/dist/compiled/stacktrace-parser' export type SetupOpts = { renderServer: LazyRenderServerInstance @@ -929,20 +929,15 @@ async function startWatcher(opts: SetupOpts) { try { originalFrame = await createOriginalStackFrame({ - line: frame.lineNumber, - column: frame.column, source, frame, moduleId, modulePath, rootDirectory: opts.dir, errorMessage: err.message, - serverCompilation: isEdgeCompiler - ? undefined - : hotReloader.serverStats?.compilation, - edgeCompilation: isEdgeCompiler + compilation: isEdgeCompiler ? hotReloader.edgeServerStats?.compilation - : undefined, + : hotReloader.serverStats?.compilation, }) } catch {} }