[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
Sebastian Markbåge committed
Mar 21, 2020 at 22:28 UTC
c0cd1be908c9e2123fa41fb784780dde9babb002
10 files changed
+39
-31
packages/react-client/src/ReactFlightClient.js
-1
@@ -17,7 +17,6 @@ import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
17
// import {
18
// resolveModuleReference,
19
// preloadModule,
20
-// loadModule,
20
// requireModule,
21
// } from './ReactFlightClientHostConfig';
22
packages/react-client/src/forks/ReactFlightClientHostConfig.custom.js
+2
@@ -26,6 +26,8 @@
26
declare var $$$hostConfig: any;
27
28
export opaque type ModuleMetaData = mixed; // eslint-disable-line no-undef
29
+export opaque type ModuleReference<T> = mixed; // eslint-disable-line no-undef
30
+export const resolveModuleReference = $$$hostConfig.resolveModuleReference;
31
export const preloadModule = $$$hostConfig.preloadModule;
32
export const requireModule = $$$hostConfig.requireModule;
33
packages/react-flight-dom-relay/src/ReactFlightDOMRelayClientHostConfig.js
-1
@@ -10,7 +10,6 @@
10
export {
11
resolveModuleReference,
12
preloadModule,
13
- loadModule,
13
requireModule,
14
} from 'ReactFlightDOMRelayClientIntegration';
15
packages/react-flight-dom-relay/src/__mocks__/ReactFlightDOMRelayClientIntegration.js
-3
@@ -18,9 +18,6 @@ const ReactFlightDOMRelayClientIntegration = {
18
return moduleData;
19
},
20
preloadModule(moduleReference) {},
21
- loadModule(moduleReference) {
22
- return null;
23
- },
21
requireModule(moduleReference) {
22
return getFakeModule();
23
},
packages/react-flight-dom-webpack/src/ReactFlightClientWebpackBundlerConfig.js
+20
-15
@@ -7,14 +7,14 @@
7
* @flow
8
*/
9
10
-export type ModuleMetaData = {
10
+export opaque type ModuleMetaData = {
11
id: string,
12
chunks: Array<string>,
13
name: string,
14
};
15
16
// eslint-disable-next-line no-unused-vars
17
-export type ModuleReference<T> = ModuleMetaData;
17
+export opaque type ModuleReference<T> = ModuleMetaData;
18
19
export function resolveModuleReference<T>(
20
moduleData: ModuleMetaData,
@@ -23,7 +23,7 @@ export function resolveModuleReference<T>(
23
}
24
25
type Thenable = {
26
- then(resolve: () => mixed, reject: (mixed) => mixed): mixed,
26
+ then(resolve: (any) => mixed, reject?: (Error) => mixed): Thenable,
27
...
28
};
29
@@ -31,32 +31,37 @@ type Thenable = {
31
// If they're still pending they're a thenable. This map also exists
32
// in Webpack but unfortunately it's not exposed so we have to
33
// replicate it in user space. null means that it has already loaded.
34
-const chunkCache: Map<string, null | Thenable> = new Map();
34
+const chunkCache: Map<string, null | Thenable | Error> = new Map();
35
36
// Returning null means that all dependencies are fulfilled and we
37
// can synchronously require the module now. A thenable is returned
38
// that when resolved, means we can try again.
39
export function preloadModule<T>(moduleData: ModuleReference<T>): void {
40
- loadModule(moduleData);
41
-}
42
-
43
-export function loadModule<T>(moduleData: ModuleReference<T>): null | Thenable {
40
let chunks = moduleData.chunks;
45
- let anyRemainingThenable = null;
41
for (let i = 0; i < chunks.length; i++) {
42
let chunkId = chunks[i];
43
let entry = chunkCache.get(chunkId);
44
if (entry === undefined) {
50
- anyRemainingThenable = __webpack_chunk_load__(chunkId);
51
- chunkCache.set(chunkId, anyRemainingThenable);
52
- anyRemainingThenable.then(chunkCache.set.bind(chunkCache, chunkId, null));
53
- } else if (entry !== null) {
54
- anyRemainingThenable = entry;
45
+ let thenable = __webpack_chunk_load__(chunkId);
46
+ let resolve = chunkCache.set.bind(chunkCache, chunkId, null);
47
+ let reject = chunkCache.set.bind(chunkCache, chunkId);
48
+ thenable.then(resolve, reject);
49
+ chunkCache.set(chunkId, thenable);
50
}
51
}
57
- return anyRemainingThenable;
52
}
53
54
export function requireModule<T>(moduleData: ModuleReference<T>): T {
55
+ let chunks = moduleData.chunks;
56
+ for (let i = 0; i < chunks.length; i++) {
57
+ let chunkId = chunks[i];
58
+ let entry = chunkCache.get(chunkId);
59
+ if (entry !== null) {
60
+ // We assume that preloadModule has been called before.
61
+ // So we don't expect to see entry being undefined here, that's an error.
62
+ // Let's throw either an error or the Promise.
63
+ throw entry;
64
+ }
65
+ }
66
return __webpack_require__(moduleData.id)[moduleData.name];
67
}
packages/react-flight-dom-webpack/src/ReactFlightServerWebpackBundlerConfig.js
+1
@@ -18,6 +18,7 @@ export type ModuleReference = string;
18
export type ModuleMetaData = {
19
id: string,
20
chunks: Array<string>,
21
+ name: string,
22
};
23
24
export function resolveModuleMetaData(
packages/react-noop-renderer/src/ReactNoopFlightClient.js
+9
@@ -27,6 +27,15 @@ const {
27
close,
28
} = ReactFlightClient({
29
supportsBinaryStreams: false,
30
+ resolveModuleReference(name: string) {
31
+ return name;
32
+ },
33
+ preloadModule(name: string) {},
34
+ requireModule(name: string) {
35
+ return function FakeModule() {
36
+ return name;
37
+ };
38
+ },
39
});
40
41
function read<T>(source: Source): ReactModelRoot<T> {
packages/react-server/src/ReactFlightServerBundlerConfigCustom.js
+1
-1
@@ -11,5 +11,5 @@ declare var $$$hostConfig: any;
11
12
export opaque type BundlerConfig = mixed; // eslint-disable-line no-undef
13
export opaque type ModuleReference = mixed; // eslint-disable-line no-undef
14
-export opaque type ModuleMetaData = mixed; // eslint-disable-line no-undef
14
+export opaque type ModuleMetaData: any = mixed; // eslint-disable-line no-undef
15
export const resolveModuleMetaData = $$$hostConfig.resolveModuleMetaData;
scripts/flow/environment.js
+5
-1
@@ -67,5 +67,9 @@ declare module 'EventListener' {
67
};
68
}
69
70
-declare function __webpack_chunk_load__(id: string): {then(() => mixed): mixed};
70
+type Thenable = {
71
+ then(resolve: (mixed) => mixed, reject?: (Error) => mixed): Thenable,
72
+};
73
+
74
+declare function __webpack_chunk_load__(id: string): Thenable;
75
declare function __webpack_require__(id: string): {default: any};
scripts/flow/react-relay-hooks.js
+1
-9
@@ -15,11 +15,6 @@ type JSONValue =
15
| {[key: string]: JSONValue}
16
| Array<JSONValue>;
17
18
-type Thenable = {
19
- then(resolve: () => mixed, reject: (error: Error) => mixed): mixed,
20
- ...
21
-};
22
-
18
declare module 'ReactFlightDOMRelayServerIntegration' {
19
declare export opaque type Destination;
20
declare export function emitModel(
@@ -43,7 +38,7 @@ declare module 'ReactFlightDOMRelayServerIntegration' {
38
}
39
40
declare module 'ReactFlightDOMRelayClientIntegration' {
46
- declare export opaque type ModuleReference;
41
+ declare export opaque type ModuleReference<T>;
42
declare export opaque type ModuleMetaData;
43
declare export function resolveModuleReference<T>(
44
moduleData: ModuleMetaData,
@@ -51,9 +46,6 @@ declare module 'ReactFlightDOMRelayClientIntegration' {
46
declare export function preloadModule<T>(
47
moduleReference: ModuleReference<T>,
48
): void;
54
- declare export function loadModule<T>(
55
- moduleReference: ModuleReference<T>,
56
- ): null | Thenable;
49
declare export function requireModule<T>(
50
moduleReference: ModuleReference<T>,
51
): T;