Skip to content

Commit

Permalink
Use consistent error formatting in terminal (#71909)
Browse files Browse the repository at this point in the history
  • Loading branch information
eps1lon authored Dec 6, 2024
1 parent fdd93c1 commit 98de5db
Show file tree
Hide file tree
Showing 25 changed files with 683 additions and 662 deletions.
12 changes: 11 additions & 1 deletion crates/napi/src/next_api/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::{path::PathBuf, sync::Arc, thread, time::Duration};

use anyhow::{anyhow, bail, Context, Result};
use napi::{
bindgen_prelude::External,
bindgen_prelude::{within_runtime_if_available, External},
threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
JsFunction, Status,
};
Expand Down Expand Up @@ -1204,6 +1204,16 @@ pub async fn project_get_source_map(
Ok(source_map)
}

#[napi]
pub fn project_get_source_map_sync(
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<ProjectInstance>,
file_path: String,
) -> napi::Result<Option<String>> {
within_runtime_if_available(|| {
tokio::runtime::Handle::current().block_on(project_get_source_map(project, file_path))
})
}

/// Runs exit handlers for the project registered using the [`ExitHandler`] API.
#[napi]
pub async fn project_on_exit(
Expand Down
4 changes: 4 additions & 0 deletions packages/next/src/build/swc/generated-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ export function projectGetSourceMap(
project: { __napiType: 'Project' },
filePath: string
): Promise<string | null>
export function projectGetSourceMapSync(
project: { __napiType: 'Project' },
filePath: string
): string | null
/** Runs exit handlers for the project registered using the [`ExitHandler`] API. */
export function projectOnExit(project: { __napiType: 'Project' }): Promise<void>
export function rootTaskDispose(rootTask: { __napiType: 'RootTask' }): void
Expand Down
4 changes: 4 additions & 0 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -759,6 +759,10 @@ function bindingToApi(
return binding.projectGetSourceMap(this._nativeProject, filePath)
}

getSourceMapSync(filePath: string): string | null {
return binding.projectGetSourceMapSync(this._nativeProject, filePath)
}

updateInfoSubscribe(aggregationMs: number) {
return subscribe<TurbopackResult<UpdateMessage>>(true, async (callback) =>
binding.projectUpdateInfoSubscribe(
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/swc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export interface Project {
getSourceForAsset(filePath: string): Promise<string | null>

getSourceMap(filePath: string): Promise<string | null>
getSourceMapSync(filePath: string): string | null

traceSource(
stackFrame: TurbopackStackFrame
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ async function nativeTraceSource(
return undefined
}

export async function createOriginalStackFrame(
async function createOriginalStackFrame(
project: Project,
frame: TurbopackStackFrame
): Promise<OriginalStackFrameResponse | null> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export async function createOriginalStackFrame({
}
}

export async function getSourceMapFromCompilation(
async function getSourceMapFromCompilation(
id: string,
compilation: webpack.Compilation
): Promise<RawSourceMap | undefined> {
Expand Down
59 changes: 58 additions & 1 deletion packages/next/src/server/dev/hot-reloader-turbopack.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Socket } from 'net'
import { mkdir, writeFile } from 'fs/promises'
import { join, extname } from 'path'
import { pathToFileURL } from 'url'

import ws from 'next/dist/compiled/ws'

Expand All @@ -20,6 +21,7 @@ import type {
Endpoint,
WrittenEndpoint,
TurbopackResult,
Project,
} from '../../build/swc/types'
import { createDefineEnv } from '../../build/swc'
import * as Log from '../../build/output/log'
Expand Down Expand Up @@ -85,6 +87,10 @@ import { isAppPageRouteDefinition } from '../route-definitions/app-page-route-de
import { normalizeAppPath } from '../../shared/lib/router/utils/app-paths'
import { getNodeDebugType } from '../lib/utils'
import { isMetadataRouteFile } from '../../lib/metadata/is-metadata-route'
import {
setBundlerFindSourceMapImplementation,
type ModernSourceMapPayload,
} from '../patch-error-inspect'
// import { getSupportedBrowsers } from '../../build/utils'

const wsServer = new ws.Server({ noServer: true })
Expand All @@ -96,6 +102,51 @@ const isTestMode = !!(

const sessionId = Math.floor(Number.MAX_SAFE_INTEGER * Math.random())

/**
* Replaces turbopack://[project] with the specified project in the `source` field.
*/
function rewriteTurbopackSources(
projectRoot: string,
sourceMap: ModernSourceMapPayload
): void {
if ('sections' in sourceMap) {
for (const section of sourceMap.sections) {
rewriteTurbopackSources(projectRoot, section.map)
}
} else {
for (let i = 0; i < sourceMap.sources.length; i++) {
sourceMap.sources[i] = pathToFileURL(
join(
projectRoot,
sourceMap.sources[i].replace(/turbopack:\/\/\[project\]/, '')
)
).toString()
}
}
}

function getSourceMapFromTurbopack(
project: Project,
projectRoot: string,
sourceURL: string
): ModernSourceMapPayload | undefined {
let sourceMapJson: string | null = null

try {
sourceMapJson = project.getSourceMapSync(sourceURL)
} catch (err) {}

if (sourceMapJson === null) {
return undefined
} else {
const payload: ModernSourceMapPayload = JSON.parse(sourceMapJson)
// The sourcemap from Turbopack is not yet written to disk so its `sources`
// are not absolute paths yet. We need to rewrite them to be absolute paths.
rewriteTurbopackSources(projectRoot, payload)
return payload
}
}

export async function createHotReloaderTurbopack(
opts: SetupOpts,
serverFields: ServerFields,
Expand Down Expand Up @@ -185,7 +236,13 @@ export async function createHotReloaderTurbopack(
memoryLimit: opts.nextConfig.experimental.turbo?.memoryLimit,
}
)
opts.onDevServerCleanup?.(() => project.onExit())
setBundlerFindSourceMapImplementation(
getSourceMapFromTurbopack.bind(null, project, dir)
)
opts.onDevServerCleanup?.(async () => {
setBundlerFindSourceMapImplementation(() => undefined)
await project.onExit()
})
const entrypointsSubscription = project.entrypointsSubscribe()

const currentWrittenEntrypoints: Map<EntryKey, WrittenEndpoint> = new Map()
Expand Down
32 changes: 0 additions & 32 deletions packages/next/src/server/dev/log-app-dir-error.ts

This file was deleted.

17 changes: 7 additions & 10 deletions packages/next/src/server/dev/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,10 @@ export default class DevServer extends Server {
// not really errors. They're just part of rendering.
return
}
this.logErrorWithOriginalStack(reason, 'unhandledRejection').catch(
() => {}
)
this.logErrorWithOriginalStack(reason, 'unhandledRejection')
})
process.on('uncaughtException', (err) => {
this.logErrorWithOriginalStack(err, 'uncaughtException').catch(() => {})
this.logErrorWithOriginalStack(err, 'uncaughtException')
})
}

Expand Down Expand Up @@ -559,7 +557,7 @@ export default class DevServer extends Server {
} catch (error) {
const err = getProperError(error)
formatServerError(err)
this.logErrorWithOriginalStack(err).catch(() => {})
this.logErrorWithOriginalStack(err)
if (!res.sent) {
res.statusCode = 500
try {
Expand All @@ -574,11 +572,11 @@ export default class DevServer extends Server {
}
}

protected async logErrorWithOriginalStack(
protected logErrorWithOriginalStack(
err?: unknown,
type?: 'unhandledRejection' | 'uncaughtException' | 'warning' | 'app-dir'
): Promise<void> {
await this.bundlerService.logErrorWithOriginalStack(err, type)
): void {
this.bundlerService.logErrorWithOriginalStack(err, type)
}

protected getPagesManifest(): PagesManifest | undefined {
Expand Down Expand Up @@ -911,7 +909,6 @@ export default class DevServer extends Server {
await super.instrumentationOnRequestError(...args)

const err = args[0]
// Safe catch to avoid floating promises
this.logErrorWithOriginalStack(err, 'app-dir').catch(() => {})
this.logErrorWithOriginalStack(err, 'app-dir')
}
}
6 changes: 2 additions & 4 deletions packages/next/src/server/lib/dev-bundler-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ export class DevBundlerService {
return await this.bundler.hotReloader.ensurePage(definition)
}

public logErrorWithOriginalStack: typeof this.bundler.logErrorWithOriginalStack =
async (...args) => {
return await this.bundler.logErrorWithOriginalStack(...args)
}
public logErrorWithOriginalStack =
this.bundler.logErrorWithOriginalStack.bind(this.bundler)

public async getFallbackErrorComponents(url?: string) {
await this.bundler.hotReloader.buildFallbackError()
Expand Down
7 changes: 6 additions & 1 deletion packages/next/src/server/lib/router-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import path from 'path'
import loadConfig from '../config'
import { serveStatic } from '../serve-static'
import setupDebug from 'next/dist/compiled/debug'
import * as Log from '../../build/output/log'
import { DecodeError } from '../../shared/lib/utils'
import { findPagesDir } from '../../lib/find-pages-dir'
import { setupFsCheck } from './router-utils/filesystem'
Expand Down Expand Up @@ -648,7 +649,11 @@ export async function initialize(opts: {
// not really errors. They're just part of rendering.
return
}
await developmentBundler?.logErrorWithOriginalStack(err, type)
if (type === 'unhandledRejection') {
Log.error('unhandledRejection: ', err)
} else if (type === 'uncaughtException') {
Log.error('uncaughtException: ', err)
}
}

process.on('uncaughtException', logError.bind(null, 'uncaughtException'))
Expand Down
Loading

0 comments on commit 98de5db

Please sign in to comment.