Skip to content

Commit

Permalink
Ensure sourcemapping in terminal triggers no dynamic io warnings
Browse files Browse the repository at this point in the history
To reland, we run outside the work-unit context to
avoid triggering these false-positives.
  • Loading branch information
eps1lon committed Oct 25, 2024
1 parent 1c7179e commit 1548da9
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 44 deletions.
6 changes: 3 additions & 3 deletions packages/next/src/server/node-environment.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// This file should be imported before any others. It sets up the environment
// for later imports to work properly.

// Import before anything else so that unexpected errors in other extensions are properly formatted.
import './node-environment-extensions/error-inspect'

import './node-environment-baseline'
// Import as early as possible so that unexpected errors in other extensions are properly formatted.
// Has to come after baseline since error-inspect requires AsyncLocalStorage that baseline provides.
import './node-environment-extensions/error-inspect'
import './node-environment-extensions/random'
import './node-environment-extensions/date'
import './node-environment-extensions/web-crypto'
Expand Down
74 changes: 39 additions & 35 deletions packages/next/src/server/patch-error-inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { SourceMapConsumer as SyncSourceMapConsumer } from 'next/dist/compiled/s
import type { StackFrame } from 'next/dist/compiled/stacktrace-parser'
import { parseStack } from '../client/components/react-dev-overlay/server/middleware'
import { getOriginalCodeFrame } from '../client/components/react-dev-overlay/server/shared'
import { workUnitAsyncStorage } from './app-render/work-unit-async-storage.external'

// TODO: Implement for Edge runtime
const inspectSymbol = Symbol.for('nodejs.util.inspect.custom')
Expand Down Expand Up @@ -186,43 +187,46 @@ export function patchErrorInspect() {
inspectOptions: util.InspectOptions,
inspect: typeof util.inspect
): string {
// Create a new Error object with the source mapping applied and then use native
// Node.js formatting on the result.
const newError =
this.cause !== undefined
? // Setting an undefined `cause` would print `[cause]: undefined`
new Error(this.message, { cause: this.cause })
: new Error(this.message)

// TODO: Ensure `class MyError extends Error {}` prints `MyError` as the name
newError.stack = parseAndSourceMap(this)

for (const key in this) {
if (!Object.prototype.hasOwnProperty.call(newError, key)) {
// @ts-expect-error -- We're copying all enumerable properties.
// So they definitely exist on `this` and obviously have no type on `newError` (yet)
newError[key] = this[key]
// avoid false-positive dynamic i/o warnings e.g. due to usage of `Math.random` in `source-map`.
return workUnitAsyncStorage.exit(() => {
// Create a new Error object with the source mapping applied and then use native
// Node.js formatting on the result.
const newError =
this.cause !== undefined
? // Setting an undefined `cause` would print `[cause]: undefined`
new Error(this.message, { cause: this.cause })
: new Error(this.message)

// TODO: Ensure `class MyError extends Error {}` prints `MyError` as the name
newError.stack = parseAndSourceMap(this)

for (const key in this) {
if (!Object.prototype.hasOwnProperty.call(newError, key)) {
// @ts-expect-error -- We're copying all enumerable properties.
// So they definitely exist on `this` and obviously have no type on `newError` (yet)
newError[key] = this[key]
}
}
}

const originalCustomInspect = (newError as any)[inspectSymbol]
// Prevent infinite recursion.
// { customInspect: false } would result in `error.cause` not using our inspect.
Object.defineProperty(newError, inspectSymbol, {
value: undefined,
enumerable: false,
writable: true,
})
try {
return inspect(newError, {
...inspectOptions,
depth:
(inspectOptions.depth ??
// Default in Node.js
2) - depth,
const originalCustomInspect = (newError as any)[inspectSymbol]
// Prevent infinite recursion.
// { customInspect: false } would result in `error.cause` not using our inspect.
Object.defineProperty(newError, inspectSymbol, {
value: undefined,
enumerable: false,
writable: true,
})
} finally {
;(newError as any)[inspectSymbol] = originalCustomInspect
}
try {
return inspect(newError, {
...inspectOptions,
depth:
(inspectOptions.depth ??
// Default in Node.js
2) - depth,
})
} finally {
;(newError as any)[inspectSymbol] = originalCustomInspect
}
})
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const dynamic = 'force-dynamic'

function logError(cause) {
const error = new Error('Boom', { cause })
console.error(error)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const dynamic = 'force-dynamic'

class UnnamedError extends Error {}
class NamedError extends Error {
name = 'MyError'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
export const dynamic = 'force-dynamic'

function logError() {
const error = new Error('Boom')
console.error(error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
const nextConfig = {
experimental: {
dynamicIO: true,
serverSourceMaps: true,
},
}
Expand Down

0 comments on commit 1548da9

Please sign in to comment.