[Flight] Move bundler configs to use Suspense instead of returning thenable (#18367)

* Move bundler configs to use suspense instead of returning thenable

* Fix some Flow types
This commit is contained in:
Sebastian Markbåge
2020-03-21 22:28:36 -07:00
committed by GitHub
parent 4b7f8496a8
commit c0cd1be908
10 changed files with 39 additions and 31 deletions

View File

@@ -17,7 +17,6 @@ import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
// import {
// resolveModuleReference,
// preloadModule,
// loadModule,
// requireModule,
// } from './ReactFlightClientHostConfig';

View File

@@ -26,6 +26,8 @@
declare var $$$hostConfig: any;
export opaque type ModuleMetaData = mixed; // eslint-disable-line no-undef
export opaque type ModuleReference<T> = mixed; // eslint-disable-line no-undef
export const resolveModuleReference = $$$hostConfig.resolveModuleReference;
export const preloadModule = $$$hostConfig.preloadModule;
export const requireModule = $$$hostConfig.requireModule;

View File

@@ -10,7 +10,6 @@
export {
resolveModuleReference,
preloadModule,
loadModule,
requireModule,
} from 'ReactFlightDOMRelayClientIntegration';

View File

@@ -18,9 +18,6 @@ const ReactFlightDOMRelayClientIntegration = {
return moduleData;
},
preloadModule(moduleReference) {},
loadModule(moduleReference) {
return null;
},
requireModule(moduleReference) {
return getFakeModule();
},

View File

@@ -7,14 +7,14 @@
* @flow
*/
export type ModuleMetaData = {
export opaque type ModuleMetaData = {
id: string,
chunks: Array<string>,
name: string,
};
// eslint-disable-next-line no-unused-vars
export type ModuleReference<T> = ModuleMetaData;
export opaque type ModuleReference<T> = ModuleMetaData;
export function resolveModuleReference<T>(
moduleData: ModuleMetaData,
@@ -23,7 +23,7 @@ export function resolveModuleReference<T>(
}
type Thenable = {
then(resolve: () => mixed, reject: (mixed) => mixed): mixed,
then(resolve: (any) => mixed, reject?: (Error) => mixed): Thenable,
...
};
@@ -31,32 +31,37 @@ type Thenable = {
// If they're still pending they're a thenable. This map also exists
// in Webpack but unfortunately it's not exposed so we have to
// replicate it in user space. null means that it has already loaded.
const chunkCache: Map<string, null | Thenable> = new Map();
const chunkCache: Map<string, null | Thenable | Error> = new Map();
// Returning null means that all dependencies are fulfilled and we
// can synchronously require the module now. A thenable is returned
// that when resolved, means we can try again.
export function preloadModule<T>(moduleData: ModuleReference<T>): void {
loadModule(moduleData);
}
export function loadModule<T>(moduleData: ModuleReference<T>): null | Thenable {
let chunks = moduleData.chunks;
let anyRemainingThenable = null;
for (let i = 0; i < chunks.length; i++) {
let chunkId = chunks[i];
let entry = chunkCache.get(chunkId);
if (entry === undefined) {
anyRemainingThenable = __webpack_chunk_load__(chunkId);
chunkCache.set(chunkId, anyRemainingThenable);
anyRemainingThenable.then(chunkCache.set.bind(chunkCache, chunkId, null));
} else if (entry !== null) {
anyRemainingThenable = entry;
let thenable = __webpack_chunk_load__(chunkId);
let resolve = chunkCache.set.bind(chunkCache, chunkId, null);
let reject = chunkCache.set.bind(chunkCache, chunkId);
thenable.then(resolve, reject);
chunkCache.set(chunkId, thenable);
}
}
return anyRemainingThenable;
}
export function requireModule<T>(moduleData: ModuleReference<T>): T {
let chunks = moduleData.chunks;
for (let i = 0; i < chunks.length; i++) {
let chunkId = chunks[i];
let entry = chunkCache.get(chunkId);
if (entry !== null) {
// We assume that preloadModule has been called before.
// So we don't expect to see entry being undefined here, that's an error.
// Let's throw either an error or the Promise.
throw entry;
}
}
return __webpack_require__(moduleData.id)[moduleData.name];
}

View File

@@ -18,6 +18,7 @@ export type ModuleReference = string;
export type ModuleMetaData = {
id: string,
chunks: Array<string>,
name: string,
};
export function resolveModuleMetaData(

View File

@@ -27,6 +27,15 @@ const {
close,
} = ReactFlightClient({
supportsBinaryStreams: false,
resolveModuleReference(name: string) {
return name;
},
preloadModule(name: string) {},
requireModule(name: string) {
return function FakeModule() {
return name;
};
},
});
function read<T>(source: Source): ReactModelRoot<T> {

View File

@@ -11,5 +11,5 @@ declare var $$$hostConfig: any;
export opaque type BundlerConfig = mixed; // eslint-disable-line no-undef
export opaque type ModuleReference = mixed; // eslint-disable-line no-undef
export opaque type ModuleMetaData = mixed; // eslint-disable-line no-undef
export opaque type ModuleMetaData: any = mixed; // eslint-disable-line no-undef
export const resolveModuleMetaData = $$$hostConfig.resolveModuleMetaData;

View File

@@ -67,5 +67,9 @@ declare module 'EventListener' {
};
}
declare function __webpack_chunk_load__(id: string): {then(() => mixed): mixed};
type Thenable = {
then(resolve: (mixed) => mixed, reject?: (Error) => mixed): Thenable,
};
declare function __webpack_chunk_load__(id: string): Thenable;
declare function __webpack_require__(id: string): {default: any};

View File

@@ -15,11 +15,6 @@ type JSONValue =
| {[key: string]: JSONValue}
| Array<JSONValue>;
type Thenable = {
then(resolve: () => mixed, reject: (error: Error) => mixed): mixed,
...
};
declare module 'ReactFlightDOMRelayServerIntegration' {
declare export opaque type Destination;
declare export function emitModel(
@@ -43,7 +38,7 @@ declare module 'ReactFlightDOMRelayServerIntegration' {
}
declare module 'ReactFlightDOMRelayClientIntegration' {
declare export opaque type ModuleReference;
declare export opaque type ModuleReference<T>;
declare export opaque type ModuleMetaData;
declare export function resolveModuleReference<T>(
moduleData: ModuleMetaData,
@@ -51,9 +46,6 @@ declare module 'ReactFlightDOMRelayClientIntegration' {
declare export function preloadModule<T>(
moduleReference: ModuleReference<T>,
): void;
declare export function loadModule<T>(
moduleReference: ModuleReference<T>,
): null | Thenable;
declare export function requireModule<T>(
moduleReference: ModuleReference<T>,
): T;