next
Version:
The React Framework
170 lines (169 loc) • 7.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
installProcessErrorHandlers: null,
isUnhandledRejectionListenerRegistered: null,
registerUnhandledRejectionListener: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
installProcessErrorHandlers: function() {
return installProcessErrorHandlers;
},
isUnhandledRejectionListenerRegistered: function() {
return isUnhandledRejectionListenerRegistered;
},
registerUnhandledRejectionListener: function() {
return registerUnhandledRejectionListener;
}
});
const _ispostpone = require("../lib/router-utils/is-postpone");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {
__proto__: null
};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
let _global = globalThis;
// The listener function is shared via globalThis so that multiple copies of
// this module (e.g. in the pre-compiled server bundle and in a route module
// bundle) still register and detect a single listener instance.
const UNHANDLED_REJECTION_LISTENER_KEY = Symbol.for('next.unhandledRejectionListener');
function unhandledRejectionListener(reason) {
if ((0, _ispostpone.isPostpone)(reason)) {
// React postpones that are unhandled might end up logged here but they're
// not really errors. They're just part of rendering.
return;
}
// Immediately log the error.
// TODO: Ideally, if we knew that this error was triggered by application
// code, we would suppress it entirely without logging. We can't reliably
// detect all of these, but when cacheComponents is enabled, we could suppress
// at least some of them by waiting to log the error until after all in-
// progress renders have completed. Then, only log errors for which there
// was not a corresponding "rejectionHandled" event.
_log.error('unhandledRejection:', reason);
}
function isUnhandledRejectionListenerRegistered() {
const listener = _global[UNHANDLED_REJECTION_LISTENER_KEY];
return listener !== undefined && process.listeners('unhandledRejection').includes(listener);
}
function registerUnhandledRejectionListener() {
if (isUnhandledRejectionListenerRegistered()) {
return;
}
const listener = _global[UNHANDLED_REJECTION_LISTENER_KEY] ??= unhandledRejectionListener;
process.on('unhandledRejection', listener);
}
function installProcessErrorHandlers(shouldRemoveUncaughtErrorAndRejectionListeners) {
if (!_global.nextInitializedProcessErrorHandlers) {
_global.nextInitializedProcessErrorHandlers = true;
// The conventional wisdom of Node.js and other runtimes is to treat
// unhandled errors as fatal and exit the process.
//
// But Next.js is not a generic JS runtime — it's a specialized runtime for
// React Server Components.
//
// Many unhandled rejections are due to the late-awaiting pattern for
// prefetching data. In Next.js it's OK to call an async function without
// immediately awaiting it, to start the request as soon as possible
// without blocking unncessarily on the result. These can end up
// triggering an "unhandledRejection" if it later turns out that the
// data is not needed to render the page. Example:
//
// const promise = fetchData()
// const shouldShow = await checkCondition()
// if (shouldShow) {
// return <Component promise={promise} />
// }
//
// In this example, `fetchData` is called immediately to start the request
// as soon as possible, but if `shouldShow` is false, then it will be
// discarded without unwrapping its result. If it errors, it will trigger
// an "unhandledRejection" event.
//
// Ideally, we would suppress these rejections completely without warning,
// because we don't consider them real errors. (TODO: Currently we do warn.)
//
// But regardless of whether we do or don't warn, we definitely shouldn't
// crash the entire process.
//
// Even a "legit" unhandled error unrelated to prefetching shouldn't
// prevent the rest of the page from rendering.
//
// So, we're going to intentionally override the default error handling
// behavior of the outer JS runtime to be more forgiving
// Remove any existing "unhandledRejection" and "uncaughtException" handlers.
// This is gated behind an experimental flag until we've considered the impact
// in various deployment environments. It's possible this may always need to
// be configurable.
if (shouldRemoveUncaughtErrorAndRejectionListeners) {
process.removeAllListeners('uncaughtException');
process.removeAllListeners('unhandledRejection');
}
process.on('rejectionHandled', ()=>{
// TODO: See note in the unhandledRejection listener above. In the
// future, we may use the "rejectionHandled" event to de-queue an error
// from being logged.
});
// Unhandled exceptions are errors triggered by non-async functions, so this
// is unrelated to the late-awaiting pattern. However, for similar reasons,
// we still shouldn't crash the process. Just log it.
process.on('uncaughtException', (reason)=>{
if ((0, _ispostpone.isPostpone)(reason)) {
return;
}
console.error(reason);
});
}
// Register the listener unconditionally, and not only during the guarded
// initialization above: a previous registration may have been undone by the
// `removeAllListeners` call of a later `installProcessErrorHandlers` call
// (or by external code), and registering is a no-op if the listener is
// still attached.
registerUnhandledRejectionListener();
}
//# sourceMappingURL=process-error-handlers.js.map