mirror of
https://github.com/zebrajr/react.git
synced 2025-12-06 12:20:20 +01:00
[Flight] Add DebugInfo for Bundler Chunks (#34226)
This adds a "suspended by" row for each chunk that is referenced from a client reference. So when you select a client component, you can see what bundles will block that client component when loading on the client. This is only done in the browser build since if we added it on the server, it would show up as a blocking resource and while it's possible we expect that a typical server request won't block on loading JS. <img width="664" height="486" alt="Screenshot 2025-08-17 at 3 45 14 PM" src="https://github.com/user-attachments/assets/b1f83445-2a4e-4470-9a20-7cd215ab0482" /> <img width="745" height="678" alt="Screenshot 2025-08-17 at 3 46 58 PM" src="https://github.com/user-attachments/assets/3558eae1-cf34-4e11-9d0e-02ec076356a4" /> Currently this is only included if it ends up wrapped in a lazy like in the typical type position of a Client Component, but there's a general issue that maybe hard references need to transfer their debug info to the parent which can transfer it to the Fiber.
This commit is contained in:
parent
87a45ae37f
commit
0c89b160f6
|
|
@ -468,6 +468,7 @@ module.exports = {
|
|||
files: ['packages/react-server-dom-webpack/**/*.js'],
|
||||
globals: {
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
__webpack_get_script_filename__: 'readonly',
|
||||
__webpack_require__: 'readonly',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
23
packages/react-client/src/ReactFlightClient.js
vendored
23
packages/react-client/src/ReactFlightClient.js
vendored
|
|
@ -55,6 +55,7 @@ import {
|
|||
resolveServerReference,
|
||||
preloadModule,
|
||||
requireModule,
|
||||
getModuleDebugInfo,
|
||||
dispatchHint,
|
||||
readPartialStringChunk,
|
||||
readFinalStringChunk,
|
||||
|
|
@ -790,8 +791,14 @@ function resolveModuleChunk<T>(
|
|||
resolvedChunk.status = RESOLVED_MODULE;
|
||||
resolvedChunk.value = value;
|
||||
if (__DEV__) {
|
||||
// We don't expect to have any debug info for this row.
|
||||
resolvedChunk._debugInfo = null;
|
||||
const debugInfo = getModuleDebugInfo(value);
|
||||
if (debugInfo !== null && resolvedChunk._debugInfo != null) {
|
||||
// Add to the live set if it was already initialized.
|
||||
// $FlowFixMe[method-unbinding]
|
||||
resolvedChunk._debugInfo.push.apply(resolvedChunk._debugInfo, debugInfo);
|
||||
} else {
|
||||
resolvedChunk._debugInfo = debugInfo;
|
||||
}
|
||||
}
|
||||
if (resolveListeners !== null) {
|
||||
initializeModuleChunk(resolvedChunk);
|
||||
|
|
@ -3977,7 +3984,11 @@ function flushComponentPerformance(
|
|||
// Track the root most component of the result for deduping logging.
|
||||
result.component = componentInfo;
|
||||
isLastComponent = false;
|
||||
} else if (candidateInfo.awaited) {
|
||||
} else if (
|
||||
candidateInfo.awaited &&
|
||||
// Skip awaits on client resources since they didn't block the server component.
|
||||
candidateInfo.awaited.env != null
|
||||
) {
|
||||
if (endTime > childrenEndTime) {
|
||||
childrenEndTime = endTime;
|
||||
}
|
||||
|
|
@ -4059,7 +4070,11 @@ function flushComponentPerformance(
|
|||
// Track the root most component of the result for deduping logging.
|
||||
result.component = componentInfo;
|
||||
isLastComponent = false;
|
||||
} else if (candidateInfo.awaited) {
|
||||
} else if (
|
||||
candidateInfo.awaited &&
|
||||
// Skip awaits on client resources since they didn't block the server component.
|
||||
candidateInfo.awaited.env != null
|
||||
) {
|
||||
// If we don't have an end time for an await, that means we aborted.
|
||||
const asyncInfo: ReactAsyncInfo = candidateInfo;
|
||||
const env = response._rootEnvironmentName;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ export const resolveClientReference = $$$config.resolveClientReference;
|
|||
export const resolveServerReference = $$$config.resolveServerReference;
|
||||
export const preloadModule = $$$config.preloadModule;
|
||||
export const requireModule = $$$config.requireModule;
|
||||
export const getModuleDebugInfo = $$$config.getModuleDebugInfo;
|
||||
export const dispatchHint = $$$config.dispatchHint;
|
||||
export const prepareDestinationForModule =
|
||||
$$$config.prepareDestinationForModule;
|
||||
|
|
|
|||
|
|
@ -24,5 +24,6 @@ export const resolveClientReference: any = null;
|
|||
export const resolveServerReference: any = null;
|
||||
export const preloadModule: any = null;
|
||||
export const requireModule: any = null;
|
||||
export const getModuleDebugInfo: any = null;
|
||||
export const prepareDestinationForModule: any = null;
|
||||
export const usedWithSSR = true;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ export const resolveClientReference: any = null;
|
|||
export const resolveServerReference: any = null;
|
||||
export const preloadModule: any = null;
|
||||
export const requireModule: any = null;
|
||||
export const getModuleDebugInfo: any = null;
|
||||
export const dispatchHint: any = null;
|
||||
export const prepareDestinationForModule: any = null;
|
||||
export const usedWithSSR = true;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,12 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
);
|
||||
}
|
||||
|
||||
export function getModuleDebugInfo<T>(metadata: ClientReference<T>): null {
|
||||
throw new Error(
|
||||
'renderToHTML should not have emitted Client References. This is a bug in React.',
|
||||
);
|
||||
}
|
||||
|
||||
export const usedWithSSR = true;
|
||||
|
||||
type HintCode = string;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,11 @@ import type {
|
|||
Thenable,
|
||||
FulfilledThenable,
|
||||
RejectedThenable,
|
||||
ReactDebugInfo,
|
||||
ReactIOInfo,
|
||||
ReactAsyncInfo,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
import type {ModuleLoading} from 'react-client/src/ReactFlightClientConfig';
|
||||
|
||||
export type ServerConsumerModuleMap = string; // Module root path
|
||||
|
|
@ -118,3 +122,93 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
}
|
||||
return moduleExports[metadata.name];
|
||||
}
|
||||
|
||||
// We cache ReactIOInfo across requests so that inner refreshes can dedupe with outer.
|
||||
const moduleIOInfoCache: Map<string, ReactIOInfo> = __DEV__
|
||||
? new Map()
|
||||
: (null: any);
|
||||
|
||||
export function getModuleDebugInfo<T>(
|
||||
metadata: ClientReference<T>,
|
||||
): null | ReactDebugInfo {
|
||||
if (!__DEV__) {
|
||||
return null;
|
||||
}
|
||||
const filename = metadata.specifier;
|
||||
let ioInfo = moduleIOInfoCache.get(filename);
|
||||
if (ioInfo === undefined) {
|
||||
let href;
|
||||
try {
|
||||
// $FlowFixMe
|
||||
href = new URL(filename, document.baseURI).href;
|
||||
} catch (_) {
|
||||
href = filename;
|
||||
}
|
||||
let start = -1;
|
||||
let end = -1;
|
||||
let byteSize = 0;
|
||||
// $FlowFixMe[method-unbinding]
|
||||
if (typeof performance.getEntriesByType === 'function') {
|
||||
// We may be able to collect the start and end time of this resource from Performance Observer.
|
||||
const resourceEntries = performance.getEntriesByType('resource');
|
||||
for (let i = 0; i < resourceEntries.length; i++) {
|
||||
const resourceEntry = resourceEntries[i];
|
||||
if (resourceEntry.name === href) {
|
||||
start = resourceEntry.startTime;
|
||||
end = start + resourceEntry.duration;
|
||||
// $FlowFixMe[prop-missing]
|
||||
byteSize = (resourceEntry.transferSize: any) || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const value = Promise.resolve(href);
|
||||
// $FlowFixMe
|
||||
value.status = 'fulfilled';
|
||||
// Is there some more useful representation for the chunk?
|
||||
// $FlowFixMe
|
||||
value.value = href;
|
||||
// Create a fake stack frame that points to the beginning of the chunk. This is
|
||||
// probably not source mapped so will link to the compiled source rather than
|
||||
// any individual file that goes into the chunks.
|
||||
const fakeStack = new Error('react-stack-top-frame');
|
||||
if (fakeStack.stack.startsWith('Error: react-stack-top-frame')) {
|
||||
// Looks like V8
|
||||
fakeStack.stack =
|
||||
'Error: react-stack-top-frame\n' +
|
||||
// Add two frames since we always trim one off the top.
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)\n' +
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)';
|
||||
} else {
|
||||
// Looks like Firefox or Safari.
|
||||
// Add two frames since we always trim one off the top.
|
||||
fakeStack.stack =
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1\n' +
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1';
|
||||
}
|
||||
ioInfo = ({
|
||||
name: 'script',
|
||||
start: start,
|
||||
end: end,
|
||||
value: value,
|
||||
debugStack: fakeStack,
|
||||
}: ReactIOInfo);
|
||||
if (byteSize > 0) {
|
||||
// $FlowFixMe[cannot-write]
|
||||
ioInfo.byteSize = byteSize;
|
||||
}
|
||||
moduleIOInfoCache.set(filename, ioInfo);
|
||||
}
|
||||
// We could dedupe the async info too but conceptually each request is its own await.
|
||||
const asyncInfo: ReactAsyncInfo = {
|
||||
awaited: ioInfo,
|
||||
};
|
||||
return [asyncInfo];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {Thenable} from 'shared/ReactTypes';
|
||||
import type {Thenable, ReactDebugInfo} from 'shared/ReactTypes';
|
||||
|
||||
import type {ImportMetadata} from '../shared/ReactFlightImportMetadata';
|
||||
|
||||
|
|
@ -80,3 +80,10 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
const moduleExports = parcelRequire(metadata[ID]);
|
||||
return moduleExports[metadata[NAME]];
|
||||
}
|
||||
|
||||
export function getModuleDebugInfo<T>(
|
||||
metadata: ClientReference<T>,
|
||||
): null | ReactDebugInfo {
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import type {
|
|||
Thenable,
|
||||
FulfilledThenable,
|
||||
RejectedThenable,
|
||||
ReactDebugInfo,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
import type {
|
||||
|
|
@ -28,7 +29,10 @@ import {
|
|||
|
||||
import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientConfig';
|
||||
|
||||
import {loadChunk} from 'react-client/src/ReactFlightClientConfig';
|
||||
import {
|
||||
loadChunk,
|
||||
addChunkDebugInfo,
|
||||
} from 'react-client/src/ReactFlightClientConfig';
|
||||
|
||||
export type ServerConsumerModuleMap = null | {
|
||||
[clientId: string]: {
|
||||
|
|
@ -231,3 +235,19 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
}
|
||||
return moduleExports[metadata[NAME]];
|
||||
}
|
||||
|
||||
export function getModuleDebugInfo<T>(
|
||||
metadata: ClientReference<T>,
|
||||
): null | ReactDebugInfo {
|
||||
if (!__DEV__) {
|
||||
return null;
|
||||
}
|
||||
const chunks = metadata[CHUNKS];
|
||||
const debugInfo: ReactDebugInfo = [];
|
||||
let i = 0;
|
||||
while (i < chunks.length) {
|
||||
const chunkFilename = chunks[i++];
|
||||
addChunkDebugInfo(debugInfo, chunkFilename);
|
||||
}
|
||||
return debugInfo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,102 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {
|
||||
ReactDebugInfo,
|
||||
ReactIOInfo,
|
||||
ReactAsyncInfo,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
export function loadChunk(filename: string): Promise<mixed> {
|
||||
return __turbopack_load_by_url__(filename);
|
||||
}
|
||||
|
||||
// We cache ReactIOInfo across requests so that inner refreshes can dedupe with outer.
|
||||
const chunkIOInfoCache: Map<string, ReactIOInfo> = __DEV__
|
||||
? new Map()
|
||||
: (null: any);
|
||||
|
||||
export function addChunkDebugInfo(
|
||||
target: ReactDebugInfo,
|
||||
filename: string,
|
||||
): void {
|
||||
if (!__DEV__) {
|
||||
return;
|
||||
}
|
||||
let ioInfo = chunkIOInfoCache.get(filename);
|
||||
if (ioInfo === undefined) {
|
||||
let href;
|
||||
try {
|
||||
// $FlowFixMe
|
||||
href = new URL(filename, document.baseURI).href;
|
||||
} catch (_) {
|
||||
href = filename;
|
||||
}
|
||||
let start = -1;
|
||||
let end = -1;
|
||||
let byteSize = 0;
|
||||
// $FlowFixMe[method-unbinding]
|
||||
if (typeof performance.getEntriesByType === 'function') {
|
||||
// We may be able to collect the start and end time of this resource from Performance Observer.
|
||||
const resourceEntries = performance.getEntriesByType('resource');
|
||||
for (let i = 0; i < resourceEntries.length; i++) {
|
||||
const resourceEntry = resourceEntries[i];
|
||||
if (resourceEntry.name === href) {
|
||||
start = resourceEntry.startTime;
|
||||
end = start + resourceEntry.duration;
|
||||
// $FlowFixMe[prop-missing]
|
||||
byteSize = (resourceEntry.transferSize: any) || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const value = Promise.resolve(href);
|
||||
// $FlowFixMe
|
||||
value.status = 'fulfilled';
|
||||
// Is there some more useful representation for the chunk?
|
||||
// $FlowFixMe
|
||||
value.value = href;
|
||||
// Create a fake stack frame that points to the beginning of the chunk. This is
|
||||
// probably not source mapped so will link to the compiled source rather than
|
||||
// any individual file that goes into the chunks.
|
||||
const fakeStack = new Error('react-stack-top-frame');
|
||||
if (fakeStack.stack.startsWith('Error: react-stack-top-frame')) {
|
||||
// Looks like V8
|
||||
fakeStack.stack =
|
||||
'Error: react-stack-top-frame\n' +
|
||||
// Add two frames since we always trim one off the top.
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)\n' +
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)';
|
||||
} else {
|
||||
// Looks like Firefox or Safari.
|
||||
// Add two frames since we always trim one off the top.
|
||||
fakeStack.stack =
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1\n' +
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1';
|
||||
}
|
||||
ioInfo = ({
|
||||
name: 'script',
|
||||
start: start,
|
||||
end: end,
|
||||
value: value,
|
||||
debugStack: fakeStack,
|
||||
}: ReactIOInfo);
|
||||
if (byteSize > 0) {
|
||||
// $FlowFixMe[cannot-write]
|
||||
ioInfo.byteSize = byteSize;
|
||||
}
|
||||
chunkIOInfoCache.set(filename, ioInfo);
|
||||
}
|
||||
// We could dedupe the async info too but conceptually each request is its own await.
|
||||
const asyncInfo: ReactAsyncInfo = {
|
||||
awaited: ioInfo,
|
||||
};
|
||||
target.push(asyncInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,16 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {ReactDebugInfo} from 'shared/ReactTypes';
|
||||
|
||||
export function loadChunk(filename: string): Promise<mixed> {
|
||||
return __turbopack_load_by_url__(filename);
|
||||
}
|
||||
|
||||
export function addChunkDebugInfo(
|
||||
target: ReactDebugInfo,
|
||||
filename: string,
|
||||
): void {
|
||||
// We don't emit any debug info on the server since we assume the loading
|
||||
// of the bundle is insignificant on the server.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ global.__webpack_require__ = function (id) {
|
|||
}
|
||||
return webpackClientModules[id] || webpackServerModules[id];
|
||||
};
|
||||
global.__webpack_get_script_filename__ = function (id) {
|
||||
return id;
|
||||
};
|
||||
|
||||
const previousCompile = Module.prototype._compile;
|
||||
|
||||
|
|
|
|||
|
|
@ -160,3 +160,9 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
}
|
||||
return moduleExports[metadata.name];
|
||||
}
|
||||
|
||||
export function getModuleDebugInfo<T>(metadata: ClientReference<T>): null {
|
||||
// We don't emit any debug info on the server since we assume the loading
|
||||
// of the bundle is insignificant on the server.
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import type {
|
|||
Thenable,
|
||||
FulfilledThenable,
|
||||
RejectedThenable,
|
||||
ReactDebugInfo,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
import type {
|
||||
|
|
@ -28,7 +29,10 @@ import {
|
|||
|
||||
import {prepareDestinationWithChunks} from 'react-client/src/ReactFlightClientConfig';
|
||||
|
||||
import {loadChunk} from 'react-client/src/ReactFlightClientConfig';
|
||||
import {
|
||||
loadChunk,
|
||||
addChunkDebugInfo,
|
||||
} from 'react-client/src/ReactFlightClientConfig';
|
||||
|
||||
export type ServerConsumerModuleMap = null | {
|
||||
[clientId: string]: {
|
||||
|
|
@ -251,3 +255,20 @@ export function requireModule<T>(metadata: ClientReference<T>): T {
|
|||
}
|
||||
return moduleExports[metadata[NAME]];
|
||||
}
|
||||
|
||||
export function getModuleDebugInfo<T>(
|
||||
metadata: ClientReference<T>,
|
||||
): null | ReactDebugInfo {
|
||||
if (!__DEV__) {
|
||||
return null;
|
||||
}
|
||||
const chunks = metadata[CHUNKS];
|
||||
const debugInfo: ReactDebugInfo = [];
|
||||
let i = 0;
|
||||
while (i < chunks.length) {
|
||||
const chunkId = chunks[i++];
|
||||
const chunkFilename = chunks[i++];
|
||||
addChunkDebugInfo(debugInfo, chunkId, chunkFilename);
|
||||
}
|
||||
return debugInfo;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,12 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {
|
||||
ReactDebugInfo,
|
||||
ReactIOInfo,
|
||||
ReactAsyncInfo,
|
||||
} from 'shared/ReactTypes';
|
||||
|
||||
const chunkMap: Map<string, string> = new Map();
|
||||
|
||||
/**
|
||||
|
|
@ -26,3 +32,98 @@ export function loadChunk(chunkId: string, filename: string): Promise<mixed> {
|
|||
chunkMap.set(chunkId, filename);
|
||||
return __webpack_chunk_load__(chunkId);
|
||||
}
|
||||
|
||||
// We cache ReactIOInfo across requests so that inner refreshes can dedupe with outer.
|
||||
const chunkIOInfoCache: Map<string, ReactIOInfo> = __DEV__
|
||||
? new Map()
|
||||
: (null: any);
|
||||
|
||||
export function addChunkDebugInfo(
|
||||
target: ReactDebugInfo,
|
||||
chunkId: string,
|
||||
filename: string,
|
||||
): void {
|
||||
if (!__DEV__) {
|
||||
return;
|
||||
}
|
||||
let ioInfo = chunkIOInfoCache.get(chunkId);
|
||||
if (ioInfo === undefined) {
|
||||
const scriptFilename = __webpack_get_script_filename__(chunkId);
|
||||
let href;
|
||||
try {
|
||||
// $FlowFixMe
|
||||
href = new URL(scriptFilename, document.baseURI).href;
|
||||
} catch (_) {
|
||||
href = scriptFilename;
|
||||
}
|
||||
let start = -1;
|
||||
let end = -1;
|
||||
let byteSize = 0;
|
||||
// $FlowFixMe[method-unbinding]
|
||||
if (typeof performance.getEntriesByType === 'function') {
|
||||
// We may be able to collect the start and end time of this resource from Performance Observer.
|
||||
const resourceEntries = performance.getEntriesByType('resource');
|
||||
for (let i = 0; i < resourceEntries.length; i++) {
|
||||
const resourceEntry = resourceEntries[i];
|
||||
if (resourceEntry.name === href) {
|
||||
start = resourceEntry.startTime;
|
||||
end = start + resourceEntry.duration;
|
||||
// $FlowFixMe[prop-missing]
|
||||
byteSize = (resourceEntry.transferSize: any) || 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
const value = Promise.resolve(href);
|
||||
// $FlowFixMe
|
||||
value.status = 'fulfilled';
|
||||
// $FlowFixMe
|
||||
value.value = {
|
||||
chunkId: chunkId,
|
||||
href: href,
|
||||
// Is there some more useful representation for the chunk?
|
||||
};
|
||||
// Create a fake stack frame that points to the beginning of the chunk. This is
|
||||
// probably not source mapped so will link to the compiled source rather than
|
||||
// any individual file that goes into the chunks.
|
||||
const fakeStack = new Error('react-stack-top-frame');
|
||||
if (fakeStack.stack.startsWith('Error: react-stack-top-frame')) {
|
||||
// Looks like V8
|
||||
fakeStack.stack =
|
||||
'Error: react-stack-top-frame\n' +
|
||||
// Add two frames since we always trim one off the top.
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)\n' +
|
||||
' at Client Component Bundle (' +
|
||||
href +
|
||||
':1:1)';
|
||||
} else {
|
||||
// Looks like Firefox or Safari.
|
||||
// Add two frames since we always trim one off the top.
|
||||
fakeStack.stack =
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1\n' +
|
||||
'Client Component Bundle@' +
|
||||
href +
|
||||
':1:1';
|
||||
}
|
||||
ioInfo = ({
|
||||
name: 'script',
|
||||
start: start,
|
||||
end: end,
|
||||
value: value,
|
||||
debugStack: fakeStack,
|
||||
}: ReactIOInfo);
|
||||
if (byteSize > 0) {
|
||||
// $FlowFixMe[cannot-write]
|
||||
ioInfo.byteSize = byteSize;
|
||||
}
|
||||
chunkIOInfoCache.set(chunkId, ioInfo);
|
||||
}
|
||||
// We could dedupe the async info too but conceptually each request is its own await.
|
||||
const asyncInfo: ReactAsyncInfo = {
|
||||
awaited: ioInfo,
|
||||
};
|
||||
target.push(asyncInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,17 @@
|
|||
* @flow
|
||||
*/
|
||||
|
||||
import type {ReactDebugInfo} from 'shared/ReactTypes';
|
||||
|
||||
export function loadChunk(chunkId: string, filename: string): Promise<mixed> {
|
||||
return __webpack_chunk_load__(chunkId);
|
||||
}
|
||||
|
||||
export function addChunkDebugInfo(
|
||||
target: ReactDebugInfo,
|
||||
chunkId: string,
|
||||
filename: string,
|
||||
): void {
|
||||
// We don't emit any debug info on the server since we assume the loading
|
||||
// of the bundle is insignificant on the server.
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,6 +146,7 @@ declare module 'EventListener' {
|
|||
}
|
||||
|
||||
declare function __webpack_chunk_load__(id: string): Promise<mixed>;
|
||||
declare function __webpack_get_script_filename__(id: string): string;
|
||||
declare const __webpack_require__: ((id: string) => any) & {
|
||||
u: string => string,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ module.exports = {
|
|||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
__webpack_get_script_filename__: 'readonly',
|
||||
__webpack_require__: 'readonly',
|
||||
|
||||
// Flight Turbopack
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ module.exports = {
|
|||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
__webpack_get_script_filename__: 'readonly',
|
||||
__webpack_require__: 'readonly',
|
||||
|
||||
// Flight Turbopack
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ module.exports = {
|
|||
|
||||
// Flight Webpack
|
||||
__webpack_chunk_load__: 'readonly',
|
||||
__webpack_get_script_filename__: 'readonly',
|
||||
__webpack_require__: 'readonly',
|
||||
|
||||
// Flight Turbopack
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user