mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[Flight] Wire up async_hooks in Node.js DEV for inspecting Promises (#27840)
This wires up the use of `async_hooks` in the Node build (as well as the Edge build when a global is available) in DEV mode only. This will be used to track debug info about what suspended during an RSC pass. Enabled behind a flag for now.
This commit is contained in:
parent
63310df2b2
commit
8b8d265bd9
|
|
@ -532,6 +532,7 @@ module.exports = {
|
|||
trustedTypes: 'readonly',
|
||||
IS_REACT_ACT_ENVIRONMENT: 'readonly',
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
globalThis: 'readonly',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ import {
|
|||
requestStorage,
|
||||
prepareHostDispatcher,
|
||||
createHints,
|
||||
initAsyncDebugInfo,
|
||||
} from './ReactFlightServerConfig';
|
||||
|
||||
import {
|
||||
|
|
@ -117,6 +118,8 @@ import binaryToComparableString from 'shared/binaryToComparableString';
|
|||
|
||||
import {SuspenseException, getSuspendedThenable} from './ReactFlightThenable';
|
||||
|
||||
initAsyncDebugInfo();
|
||||
|
||||
const ObjectPrototype = Object.prototype;
|
||||
|
||||
type JSONValue =
|
||||
|
|
|
|||
33
packages/react-server/src/ReactFlightServerConfigDebugNode.js
vendored
Normal file
33
packages/react-server/src/ReactFlightServerConfigDebugNode.js
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
import {createAsyncHook, executionAsyncId} from './ReactFlightServerConfig';
|
||||
import {enableAsyncDebugInfo} from 'shared/ReactFeatureFlags';
|
||||
|
||||
// Initialize the tracing of async operations.
|
||||
// We do this globally since the async work can potentially eagerly
|
||||
// start before the first request and once requests start they can interleave.
|
||||
// In theory we could enable and disable using a ref count of active requests
|
||||
// but given that typically this is just a live server, it doesn't really matter.
|
||||
export function initAsyncDebugInfo(): void {
|
||||
if (__DEV__ && enableAsyncDebugInfo) {
|
||||
createAsyncHook({
|
||||
init(asyncId: number, type: string, triggerAsyncId: number): void {
|
||||
// TODO
|
||||
},
|
||||
promiseResolve(asyncId: number): void {
|
||||
// TODO
|
||||
executionAsyncId();
|
||||
},
|
||||
destroy(asyncId: number): void {
|
||||
// TODO
|
||||
},
|
||||
}).enable();
|
||||
}
|
||||
}
|
||||
11
packages/react-server/src/ReactFlightServerConfigDebugNoop.js
vendored
Normal file
11
packages/react-server/src/ReactFlightServerConfigDebugNoop.js
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*
|
||||
* @flow
|
||||
*/
|
||||
|
||||
// Exported for runtimes that don't support Promise instrumentation for async debugging.
|
||||
export function initAsyncDebugInfo(): void {}
|
||||
|
|
@ -11,6 +11,8 @@ import type {Request} from 'react-server/src/ReactFlightServer';
|
|||
|
||||
export * from '../ReactFlightServerConfigBundlerCustom';
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
||||
export type Hints = any;
|
||||
export type HintCode = any;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
|
|
|||
|
|
@ -16,3 +16,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
export const supportsRequestStorage = true;
|
||||
export const requestStorage: AsyncLocalStorage<Request> =
|
||||
new AsyncLocalStorage();
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
|
||||
export const supportsRequestStorage = false;
|
||||
export const requestStorage: AsyncLocalStorage<Request> = (null: any);
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
|
||||
export const supportsRequestStorage = false;
|
||||
export const requestStorage: AsyncLocalStorage<Request> = (null: any);
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
|
||||
export const supportsRequestStorage = false;
|
||||
export const requestStorage: AsyncLocalStorage<Request> = (null: any);
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -16,3 +16,18 @@ export const supportsRequestStorage = typeof AsyncLocalStorage === 'function';
|
|||
export const requestStorage: AsyncLocalStorage<Request> = supportsRequestStorage
|
||||
? new AsyncLocalStorage()
|
||||
: (null: any);
|
||||
|
||||
// We use the Node version but get access to async_hooks from a global.
|
||||
import type {HookCallbacks, AsyncHook} from 'async_hooks';
|
||||
export const createAsyncHook: HookCallbacks => AsyncHook =
|
||||
typeof async_hooks === 'object'
|
||||
? async_hooks.createHook
|
||||
: function () {
|
||||
return ({
|
||||
enable() {},
|
||||
disable() {},
|
||||
}: any);
|
||||
};
|
||||
export const executionAsyncId: () => number =
|
||||
typeof async_hooks === 'object' ? async_hooks.executionAsyncId : (null: any);
|
||||
export * from '../ReactFlightServerConfigDebugNode';
|
||||
|
|
|
|||
|
|
@ -16,3 +16,18 @@ export const supportsRequestStorage = typeof AsyncLocalStorage === 'function';
|
|||
export const requestStorage: AsyncLocalStorage<Request> = supportsRequestStorage
|
||||
? new AsyncLocalStorage()
|
||||
: (null: any);
|
||||
|
||||
// We use the Node version but get access to async_hooks from a global.
|
||||
import type {HookCallbacks, AsyncHook} from 'async_hooks';
|
||||
export const createAsyncHook: HookCallbacks => AsyncHook =
|
||||
typeof async_hooks === 'object'
|
||||
? async_hooks.createHook
|
||||
: function () {
|
||||
return ({
|
||||
enable() {},
|
||||
disable() {},
|
||||
}: any);
|
||||
};
|
||||
export const executionAsyncId: () => number =
|
||||
typeof async_hooks === 'object' ? async_hooks.executionAsyncId : (null: any);
|
||||
export * from '../ReactFlightServerConfigDebugNode';
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
|
||||
export const supportsRequestStorage = false;
|
||||
export const requestStorage: AsyncLocalStorage<Request> = (null: any);
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -14,3 +14,5 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
|
||||
export const supportsRequestStorage = false;
|
||||
export const requestStorage: AsyncLocalStorage<Request> = (null: any);
|
||||
|
||||
export * from '../ReactFlightServerConfigDebugNoop';
|
||||
|
|
|
|||
|
|
@ -16,3 +16,6 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
export const supportsRequestStorage = true;
|
||||
export const requestStorage: AsyncLocalStorage<Request> =
|
||||
new AsyncLocalStorage();
|
||||
|
||||
export {createHook as createAsyncHook, executionAsyncId} from 'async_hooks';
|
||||
export * from '../ReactFlightServerConfigDebugNode';
|
||||
|
|
|
|||
|
|
@ -17,3 +17,6 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
export const supportsRequestStorage = true;
|
||||
export const requestStorage: AsyncLocalStorage<Request> =
|
||||
new AsyncLocalStorage();
|
||||
|
||||
export {createHook as createAsyncHook, executionAsyncId} from 'async_hooks';
|
||||
export * from '../ReactFlightServerConfigDebugNode';
|
||||
|
|
|
|||
|
|
@ -17,3 +17,6 @@ export * from 'react-dom-bindings/src/server/ReactFlightServerConfigDOM';
|
|||
export const supportsRequestStorage = true;
|
||||
export const requestStorage: AsyncLocalStorage<Request> =
|
||||
new AsyncLocalStorage();
|
||||
|
||||
export {createHook as createAsyncHook, executionAsyncId} from 'async_hooks';
|
||||
export * from '../ReactFlightServerConfigDebugNode';
|
||||
|
|
|
|||
|
|
@ -229,6 +229,8 @@ export const enableProfilerNestedUpdatePhase = __PROFILE__;
|
|||
// issues in DEV builds.
|
||||
export const enableDebugTracing = false;
|
||||
|
||||
export const enableAsyncDebugInfo = __EXPERIMENTAL__;
|
||||
|
||||
// Track which Fiber(s) schedule render work.
|
||||
export const enableUpdaterTracking = __PROFILE__;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ export const {
|
|||
// The rest of the flags are static for better dead code elimination.
|
||||
export const disableModulePatternComponents = true;
|
||||
export const enableDebugTracing = false;
|
||||
export const enableAsyncDebugInfo = false;
|
||||
export const enableSchedulingProfiler = __PROFILE__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
export const enableProfilerCommitHooks = __PROFILE__;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import typeof * as ExportsType from './ReactFeatureFlags.native-oss';
|
|||
|
||||
export const debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
export const enableDebugTracing = false;
|
||||
export const enableAsyncDebugInfo = false;
|
||||
export const enableSchedulingProfiler = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = __DEV__;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import typeof * as ExportsType from './ReactFeatureFlags.test-renderer';
|
|||
|
||||
export const debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
export const enableDebugTracing = false;
|
||||
export const enableAsyncDebugInfo = false;
|
||||
export const enableSchedulingProfiler = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import typeof * as ExportsType from './ReactFeatureFlags.test-renderer';
|
|||
|
||||
export const debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
export const enableDebugTracing = false;
|
||||
export const enableAsyncDebugInfo = false;
|
||||
export const enableSchedulingProfiler = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import typeof * as ExportsType from './ReactFeatureFlags.test-renderer.www';
|
|||
|
||||
export const debugRenderPhaseSideEffectsForStrictMode = false;
|
||||
export const enableDebugTracing = false;
|
||||
export const enableAsyncDebugInfo = false;
|
||||
export const enableSchedulingProfiler = false;
|
||||
export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
|
||||
export const enableProfilerTimer = __PROFILE__;
|
||||
|
|
|
|||
|
|
@ -116,5 +116,7 @@ export const forceConcurrentByDefaultForTesting = false;
|
|||
export const useMicrotasksForSchedulingInFabric = false;
|
||||
export const passChildrenWhenCloningPersistedNodes = false;
|
||||
|
||||
export const enableAsyncDebugInfo = false;
|
||||
|
||||
// Flow magic to verify the exports of this file match the original version.
|
||||
((((null: any): ExportsType): FeatureFlagsType): ExportsType);
|
||||
|
|
|
|||
|
|
@ -281,13 +281,7 @@ declare module 'pg/lib/utils' {
|
|||
};
|
||||
}
|
||||
|
||||
declare class AsyncLocalStorage<T> {
|
||||
disable(): void;
|
||||
getStore(): T | void;
|
||||
run(store: T, callback: (...args: any[]) => void, ...args: any[]): void;
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
|
||||
// Node
|
||||
declare module 'async_hooks' {
|
||||
declare class AsyncLocalStorage<T> {
|
||||
disable(): void;
|
||||
|
|
@ -295,8 +289,42 @@ declare module 'async_hooks' {
|
|||
run(store: T, callback: (...args: any[]) => void, ...args: any[]): void;
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
declare interface AsyncResource {}
|
||||
declare function executionAsyncId(): number;
|
||||
declare function executionAsyncResource(): AsyncResource;
|
||||
declare function triggerAsyncId(): number;
|
||||
declare type HookCallbacks = {
|
||||
init?: (
|
||||
asyncId: number,
|
||||
type: string,
|
||||
triggerAsyncId: number,
|
||||
resource: AsyncResource,
|
||||
) => void,
|
||||
before?: (asyncId: number) => void,
|
||||
after?: (asyncId: number) => void,
|
||||
promiseResolve?: (asyncId: number) => void,
|
||||
destroy?: (asyncId: number) => void,
|
||||
};
|
||||
declare class AsyncHook {
|
||||
enable(): this;
|
||||
disable(): this;
|
||||
}
|
||||
declare function createHook(callbacks: HookCallbacks): AsyncHook;
|
||||
}
|
||||
|
||||
// Edge
|
||||
declare class AsyncLocalStorage<T> {
|
||||
disable(): void;
|
||||
getStore(): T | void;
|
||||
run(store: T, callback: (...args: any[]) => void, ...args: any[]): void;
|
||||
enterWith(store: T): void;
|
||||
}
|
||||
|
||||
declare var async_hooks: {
|
||||
createHook(callbacks: any): any,
|
||||
executionAsyncId(): number,
|
||||
};
|
||||
|
||||
declare module 'node:worker_threads' {
|
||||
declare class MessageChannel {
|
||||
port1: MessagePort;
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// jest
|
||||
jest: 'readonly',
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// jest
|
||||
jest: 'readonly',
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ module.exports = {
|
|||
|
||||
// Temp
|
||||
AsyncLocalStorage: 'readonly',
|
||||
async_hooks: 'readonly',
|
||||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ module.exports = [
|
|||
'react-devtools-shared',
|
||||
'react-interactions',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -81,6 +82,7 @@ module.exports = [
|
|||
'react-devtools-shared',
|
||||
'react-interactions',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -117,6 +119,7 @@ module.exports = [
|
|||
'react-devtools-shared',
|
||||
'react-interactions',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -154,6 +157,7 @@ module.exports = [
|
|||
'react-devtools-shared',
|
||||
'react-interactions',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -297,6 +301,7 @@ module.exports = [
|
|||
'react-devtools-shell',
|
||||
'react-devtools-shared',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -330,6 +335,7 @@ module.exports = [
|
|||
'react-devtools-shell',
|
||||
'react-devtools-shared',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
@ -364,6 +370,7 @@ module.exports = [
|
|||
'react-devtools-shared',
|
||||
'react-interactions',
|
||||
'shared/ReactDOMSharedInternals',
|
||||
'react-server/src/ReactFlightServerConfigDebugNode.js',
|
||||
],
|
||||
isFlowTyped: true,
|
||||
isServerSupported: true,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user