Badge Environment Name on Thrown Errors from the Server (#29846)

When we replay logs we badge them with e.g. `[Server]`. That way it's
easy to identify that the source of the log actually happened on the
Server (RSC). However, when we threw an error we didn't have any such
thing. The error was rethrown on the client and then handled just like
any other client error.

This transfers the `environmentName` in DEV to our restored Error
"sub-class" (conceptually) along with `digest`. That way you can read
`error.environmentName` to print this in your own UI.

I also updated our default for `onCaughtError` (and `onError` in Fizz)
to use the `printToConsole` helper that the Flight Client uses to log it
with the badge format. So by default you get the same experience as
console.error for caught errors:

<img width="810" alt="Screenshot 2024-06-10 at 9 25 12 PM"
src="https://github.com/facebook/react/assets/63648/8490fedc-09f6-4286-9332-fbe6b0faa2d3">

<img width="815" alt="Screenshot 2024-06-10 at 9 39 30 PM"
src="https://github.com/facebook/react/assets/63648/bdcfc554-504a-4b1d-82bf-b717e74975ac">

Unfortunately I can't do the same thing for `onUncaughtError` nor
`onRecoverableError` because they use `reportError` which doesn't have
custom formatting (unless we also prevented default on window.onerror).
However maybe that's ok because 1) you should always have an error
boundary 2) it's not likely that an RSC error can actually recover
because it's not going to be rendered again so shouldn't really happen
outside some parent conditionally rendering maybe.

The other problem with this approach is that the default is no longer
trivial - so reimplementing the default in user space is trickier and
ideally we shouldn't expose our default to be called.
This commit is contained in:
Sebastian Markbåge 2024-06-26 19:27:26 +02:00 committed by GitHub
parent 7045700a6d
commit 349a99a7a3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
34 changed files with 134 additions and 36 deletions

View File

@ -418,13 +418,18 @@ export function createLogAssertion(
let argIndex = 0; let argIndex = 0;
// console.* could have been called with a non-string e.g. `console.error(new Error())` // console.* could have been called with a non-string e.g. `console.error(new Error())`
// eslint-disable-next-line react-internal/safe-string-coercion // eslint-disable-next-line react-internal/safe-string-coercion
String(format).replace(/%s/g, () => argIndex++); String(format).replace(/%s|%c/g, () => argIndex++);
if (argIndex !== args.length) { if (argIndex !== args.length) {
logsMismatchingFormat.push({ if (format.includes('%c%s')) {
format, // We intentionally use mismatching formatting when printing badging because we don't know
args, // the best default to use for different types because the default varies by platform.
expectedArgCount: argIndex, } else {
}); logsMismatchingFormat.push({
format,
args,
expectedArgCount: argIndex,
});
}
} }
// Check for extra component stacks // Check for extra component stacks

View File

@ -3,6 +3,10 @@
module.exports = function shouldIgnoreConsoleError(format, args) { module.exports = function shouldIgnoreConsoleError(format, args) {
if (__DEV__) { if (__DEV__) {
if (typeof format === 'string') { if (typeof format === 'string') {
if (format.startsWith('%c%s')) {
// Looks like a badged error message
args.splice(0, 3);
}
if ( if (
args[0] != null && args[0] != null &&
((typeof args[0] === 'object' && ((typeof args[0] === 'object' &&

View File

@ -7,6 +7,8 @@
* @flow * @flow
*/ */
import {warn, error} from 'shared/consoleWithStackDev';
const badgeFormat = '%c%s%c '; const badgeFormat = '%c%s%c ';
// Same badge styling as DevTools. // Same badge styling as DevTools.
const badgeStyle = const badgeStyle =
@ -63,7 +65,12 @@ export function printToConsole(
); );
} }
// eslint-disable-next-line react-internal/no-production-logging if (methodName === 'error') {
console[methodName].apply(console, newArgs); error.apply(console, newArgs);
return; } else if (methodName === 'warn') {
warn.apply(console, newArgs);
} else {
// eslint-disable-next-line react-internal/no-production-logging
console[methodName].apply(console, newArgs);
}
} }

View File

@ -7,6 +7,8 @@
* @flow * @flow
*/ */
import {warn, error} from 'shared/consoleWithStackDev';
const badgeFormat = '[%s] '; const badgeFormat = '[%s] ';
const pad = ' '; const pad = ' ';
@ -44,7 +46,12 @@ export function printToConsole(
newArgs.splice(offset, 0, badgeFormat, pad + badgeName + pad); newArgs.splice(offset, 0, badgeFormat, pad + badgeName + pad);
} }
// eslint-disable-next-line react-internal/no-production-logging if (methodName === 'error') {
console[methodName].apply(console, newArgs); error.apply(console, newArgs);
return; } else if (methodName === 'warn') {
warn.apply(console, newArgs);
} else {
// eslint-disable-next-line react-internal/no-production-logging
console[methodName].apply(console, newArgs);
}
} }

View File

@ -7,6 +7,8 @@
* @flow * @flow
*/ */
import {warn, error} from 'shared/consoleWithStackDev';
// This flips color using ANSI, then sets a color styling, then resets. // This flips color using ANSI, then sets a color styling, then resets.
const badgeFormat = '\x1b[0m\x1b[7m%c%s\x1b[0m%c '; const badgeFormat = '\x1b[0m\x1b[7m%c%s\x1b[0m%c ';
// Same badge styling as DevTools. // Same badge styling as DevTools.
@ -64,7 +66,12 @@ export function printToConsole(
); );
} }
// eslint-disable-next-line react-internal/no-production-logging if (methodName === 'error') {
console[methodName].apply(console, newArgs); error.apply(console, newArgs);
return; } else if (methodName === 'warn') {
warn.apply(console, newArgs);
} else {
// eslint-disable-next-line react-internal/no-production-logging
console[methodName].apply(console, newArgs);
}
} }

View File

@ -1730,6 +1730,7 @@ function resolveErrorDev(
digest: string, digest: string,
message: string, message: string,
stack: string, stack: string,
env: string,
): void { ): void {
if (!__DEV__) { if (!__DEV__) {
// These errors should never make it into a build so we don't need to encode them in codes.json // These errors should never make it into a build so we don't need to encode them in codes.json
@ -1769,6 +1770,7 @@ function resolveErrorDev(
} }
(error: any).digest = digest; (error: any).digest = digest;
(error: any).environmentName = env;
const errorWithDigest: ErrorWithDigest = (error: any); const errorWithDigest: ErrorWithDigest = (error: any);
const chunks = response._chunks; const chunks = response._chunks;
const chunk = chunks.get(id); const chunk = chunks.get(id);
@ -2056,6 +2058,8 @@ function resolveConsoleEntry(
task.run(callStack); task.run(callStack);
return; return;
} }
// TODO: Set the current owner so that consoleWithStackDev adds the component
// stack during the replay - if needed.
} }
const rootTask = response._debugRootTask; const rootTask = response._debugRootTask;
if (rootTask != null) { if (rootTask != null) {
@ -2198,6 +2202,7 @@ function processFullRow(
errorInfo.digest, errorInfo.digest,
errorInfo.message, errorInfo.message,
errorInfo.stack, errorInfo.stack,
errorInfo.env,
); );
} else { } else {
resolveErrorProd(response, id, errorInfo.digest); resolveErrorProd(response, id, errorInfo.digest);

View File

@ -127,6 +127,7 @@ describe('ReactFlight', () => {
this.props.expectedMessage, this.props.expectedMessage,
); );
expect(this.state.error.digest).toBe('a dev digest'); expect(this.state.error.digest).toBe('a dev digest');
expect(this.state.error.environmentName).toBe('Server');
} else { } else {
expect(this.state.error.message).toBe( expect(this.state.error.message).toBe(
'An error occurred in the Server Components render. The specific message is omitted in production' + 'An error occurred in the Server Components render. The specific message is omitted in production' +
@ -143,6 +144,7 @@ describe('ReactFlight', () => {
expectedDigest = '[]'; expectedDigest = '[]';
} }
expect(this.state.error.digest).toContain(expectedDigest); expect(this.state.error.digest).toContain(expectedDigest);
expect(this.state.error.environmentName).toBe(undefined);
expect(this.state.error.stack).toBe( expect(this.state.error.stack).toBe(
'Error: ' + this.state.error.message, 'Error: ' + this.state.error.message,
); );

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigBrowser'; export * from 'react-client/src/ReactClientConsoleConfigBrowser';
export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM'; export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM';
export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMBrowser'; export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMBrowser';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigBrowser'; export * from 'react-client/src/ReactClientConsoleConfigBrowser';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackBrowser'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackBrowser';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackBrowser'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackBrowser';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigBrowser'; export * from 'react-client/src/ReactClientConsoleConfigBrowser';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackBrowser'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackBrowser';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackBrowser'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackBrowser';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigPlain'; export * from 'react-client/src/ReactClientConsoleConfigPlain';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export type Response = any; export type Response = any;

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackServer'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackServer';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackServer'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackServer';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigWeb'; export * from 'react-client/src/ReactFlightClientStreamConfigWeb';
export * from 'react-client/src/ReactFlightClientConsoleConfigBrowser'; export * from 'react-client/src/ReactClientConsoleConfigBrowser';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';
export type Response = any; export type Response = any;

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactFlightClientStreamConfigNode';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM'; export * from 'react-server-dom-esm/src/ReactFlightClientConfigBundlerESM';
export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMServer'; export * from 'react-server-dom-esm/src/ReactFlightClientConfigTargetESMServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactFlightClientStreamConfigNode';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopack';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackServer'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerTurbopackServer';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactFlightClientStreamConfigNode';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerNode'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigBundlerNode';
export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer'; export * from 'react-server-dom-turbopack/src/ReactFlightClientConfigTargetTurbopackServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactFlightClientStreamConfigNode';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpack';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackServer'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerWebpackServer';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer';

View File

@ -8,7 +8,7 @@
*/ */
export * from 'react-client/src/ReactFlightClientStreamConfigNode'; export * from 'react-client/src/ReactFlightClientStreamConfigNode';
export * from 'react-client/src/ReactFlightClientConsoleConfigServer'; export * from 'react-client/src/ReactClientConsoleConfigServer';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerNode'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigBundlerNode';
export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer'; export * from 'react-server-dom-webpack/src/ReactFlightClientConfigTargetWebpackServer';
export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM'; export * from 'react-dom-bindings/src/shared/ReactFlightClientConfigDOM';

View File

@ -635,6 +635,11 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
NotPendingTransition: (null: TransitionStatus), NotPendingTransition: (null: TransitionStatus),
resetFormInstance(form: Instance) {}, resetFormInstance(form: Instance) {},
printToConsole(methodName, args, badgeName) {
// eslint-disable-next-line react-internal/no-production-logging
console[methodName].apply(console, args);
},
}; };
const hostConfig = useMutation const hostConfig = useMutation

View File

@ -20,6 +20,8 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
import {enableOwnerStacks} from 'shared/ReactFeatureFlags'; import {enableOwnerStacks} from 'shared/ReactFeatureFlags';
import {printToConsole} from './ReactFiberConfig';
// Side-channel since I'm not sure we want to make this part of the public API // Side-channel since I'm not sure we want to make this part of the public API
let componentName: null | string = null; let componentName: null | string = null;
let errorBoundaryName: null | string = null; let errorBoundaryName: null | string = null;
@ -94,13 +96,33 @@ export function defaultOnCaughtError(
}.`; }.`;
if (enableOwnerStacks) { if (enableOwnerStacks) {
console.error( if (
'%o\n\n%s\n\n%s\n', typeof error === 'object' &&
error, error !== null &&
componentNameMessage, typeof error.environmentName === 'string'
recreateMessage, ) {
// We let our consoleWithStackDev wrapper add the component stack to the end. // This was a Server error. We print the environment name in a badge just like we do with
); // replays of console logs to indicate that the source of this throw as actually the Server.
printToConsole(
'error',
[
'%o\n\n%s\n\n%s\n',
error,
componentNameMessage,
recreateMessage,
// We let our consoleWithStackDev wrapper add the component stack to the end.
],
error.environmentName,
);
} else {
console.error(
'%o\n\n%s\n\n%s\n',
error,
componentNameMessage,
recreateMessage,
// We let our consoleWithStackDev wrapper add the component stack to the end.
);
}
} else { } else {
// The current Fiber is disconnected at this point which means that console printing // The current Fiber is disconnected at this point which means that console printing
// cannot add a component stack since it terminates at the deletion node. This is not // cannot add a component stack since it terminates at the deletion node. This is not

View File

@ -8,3 +8,4 @@
*/ */
export * from 'react-art/src/ReactFiberConfigART'; export * from 'react-art/src/ReactFiberConfigART';
export * from 'react-client/src/ReactClientConsoleConfigBrowser';

View File

@ -80,6 +80,7 @@ export const suspendInstance = $$$config.suspendInstance;
export const waitForCommitToBeReady = $$$config.waitForCommitToBeReady; export const waitForCommitToBeReady = $$$config.waitForCommitToBeReady;
export const NotPendingTransition = $$$config.NotPendingTransition; export const NotPendingTransition = $$$config.NotPendingTransition;
export const resetFormInstance = $$$config.resetFormInstance; export const resetFormInstance = $$$config.resetFormInstance;
export const printToConsole = $$$config.printToConsole;
// ------------------- // -------------------
// Microtasks // Microtasks

View File

@ -8,3 +8,4 @@
*/ */
export * from 'react-dom-bindings/src/client/ReactFiberConfigDOM'; export * from 'react-dom-bindings/src/client/ReactFiberConfigDOM';
export * from 'react-client/src/ReactClientConsoleConfigBrowser';

View File

@ -8,3 +8,4 @@
*/ */
export * from 'react-native-renderer/src/ReactFiberConfigFabric'; export * from 'react-native-renderer/src/ReactFiberConfigFabric';
export * from 'react-client/src/ReactClientConsoleConfigPlain';

View File

@ -8,3 +8,4 @@
*/ */
export * from 'react-native-renderer/src/ReactFiberConfigNative'; export * from 'react-native-renderer/src/ReactFiberConfigNative';
export * from 'react-client/src/ReactClientConsoleConfigPlain';

View File

@ -8,3 +8,4 @@
*/ */
export * from 'react-test-renderer/src/ReactFiberConfigTestHost'; export * from 'react-test-renderer/src/ReactFiberConfigTestHost';
export * from 'react-client/src/ReactClientConsoleConfigPlain';

View File

@ -78,6 +78,7 @@ import {
resetResumableState, resetResumableState,
completeResumableState, completeResumableState,
emitEarlyPreloads, emitEarlyPreloads,
printToConsole,
} from './ReactFizzConfig'; } from './ReactFizzConfig';
import { import {
constructClassInstance, constructClassInstance,
@ -363,7 +364,17 @@ export opaque type Request = {
const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800; const DEFAULT_PROGRESSIVE_CHUNK_SIZE = 12800;
function defaultErrorHandler(error: mixed) { function defaultErrorHandler(error: mixed) {
console['error'](error); // Don't transform to our wrapper if (
typeof error === 'object' &&
error !== null &&
typeof error.environmentName === 'string'
) {
// This was a Server error. We print the environment name in a badge just like we do with
// replays of console logs to indicate that the source of this throw as actually the Server.
printToConsole('error', [error], error.environmentName);
} else {
console['error'](error); // Don't transform to our wrapper
}
return null; return null;
} }

View File

@ -2774,11 +2774,18 @@ function emitErrorChunk(
if (__DEV__) { if (__DEV__) {
let message; let message;
let stack = ''; let stack = '';
let env = request.environmentName();
try { try {
if (error instanceof Error) { if (error instanceof Error) {
// eslint-disable-next-line react-internal/safe-string-coercion // eslint-disable-next-line react-internal/safe-string-coercion
message = String(error.message); message = String(error.message);
stack = getStack(error); stack = getStack(error);
const errorEnv = (error: any).environmentName;
if (typeof errorEnv === 'string') {
// This probably came from another FlightClient as a pass through.
// Keep the environment name.
env = errorEnv;
}
} else if (typeof error === 'object' && error !== null) { } else if (typeof error === 'object' && error !== null) {
message = describeObjectForErrorMessage(error); message = describeObjectForErrorMessage(error);
} else { } else {
@ -2788,7 +2795,7 @@ function emitErrorChunk(
} catch (x) { } catch (x) {
message = 'An error occurred but serializing the error message failed.'; message = 'An error occurred but serializing the error message failed.';
} }
errorInfo = {digest, message, stack}; errorInfo = {digest, message, stack, env};
} else { } else {
errorInfo = {digest}; errorInfo = {digest};
} }

View File

@ -40,6 +40,8 @@ export const isPrimaryRenderer = false;
export const supportsRequestStorage = false; export const supportsRequestStorage = false;
export const requestStorage: AsyncLocalStorage<Request | void> = (null: any); export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);
export const printToConsole = $$$config.printToConsole;
export const resetResumableState = $$$config.resetResumableState; export const resetResumableState = $$$config.resetResumableState;
export const completeResumableState = $$$config.completeResumableState; export const completeResumableState = $$$config.completeResumableState;
export const getChildFormatContext = $$$config.getChildFormatContext; export const getChildFormatContext = $$$config.getChildFormatContext;

View File

@ -10,6 +10,8 @@ import type {Request} from 'react-server/src/ReactFizzServer';
export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
export * from 'react-client/src/ReactClientConsoleConfigServer';
// For now, we get this from the global scope, but this will likely move to a module. // For now, we get this from the global scope, but this will likely move to a module.
export const supportsRequestStorage = typeof AsyncLocalStorage === 'function'; export const supportsRequestStorage = typeof AsyncLocalStorage === 'function';
export const requestStorage: AsyncLocalStorage<Request | void> = export const requestStorage: AsyncLocalStorage<Request | void> =

View File

@ -10,5 +10,7 @@ import type {Request} from 'react-server/src/ReactFizzServer';
export * from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy'; export * from 'react-dom-bindings/src/server/ReactFizzConfigDOMLegacy';
export * from 'react-client/src/ReactClientConsoleConfigPlain';
export const supportsRequestStorage = false; export const supportsRequestStorage = false;
export const requestStorage: AsyncLocalStorage<Request | void> = (null: any); export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);

View File

@ -13,6 +13,8 @@ import type {Request} from 'react-server/src/ReactFizzServer';
export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
export * from 'react-client/src/ReactClientConsoleConfigServer';
export const supportsRequestStorage = true; export const supportsRequestStorage = true;
export const requestStorage: AsyncLocalStorage<Request | void> = export const requestStorage: AsyncLocalStorage<Request | void> =
new AsyncLocalStorage(); new AsyncLocalStorage();

View File

@ -10,5 +10,7 @@ import type {Request} from 'react-server/src/ReactFizzServer';
export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM'; export * from 'react-dom-bindings/src/server/ReactFizzConfigDOM';
export * from 'react-client/src/ReactClientConsoleConfigBrowser';
export const supportsRequestStorage = false; export const supportsRequestStorage = false;
export const requestStorage: AsyncLocalStorage<Request | void> = (null: any); export const requestStorage: AsyncLocalStorage<Request | void> = (null: any);