Skip to content

Commit

Permalink
[Flight] Move bundler configs to use Suspense instead of returning th…
Browse files Browse the repository at this point in the history
…enable (#18367)

* Move bundler configs to use suspense instead of returning thenable

* Fix some Flow types
  • Loading branch information
sebmarkbage committed Mar 22, 2020
1 parent 4b7f849 commit c0cd1be
Show file tree
Hide file tree
Showing 10 changed files with 39 additions and 31 deletions.
1 change: 0 additions & 1 deletion packages/react-client/src/ReactFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import {REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
// import {
// resolveModuleReference,
// preloadModule,
// loadModule,
// requireModule,
// } from './ReactFlightClientHostConfig';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
export {
resolveModuleReference,
preloadModule,
loadModule,
requireModule,
} from 'ReactFlightDOMRelayClientIntegration';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ const ReactFlightDOMRelayClientIntegration = {
return moduleData;
},
preloadModule(moduleReference) {},
loadModule(moduleReference) {
return null;
},
requireModule(moduleReference) {
return getFakeModule();
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -23,40 +23,45 @@ export function resolveModuleReference<T>(
}

type Thenable = {
then(resolve: () => mixed, reject: (mixed) => mixed): mixed,
then(resolve: (any) => mixed, reject?: (Error) => mixed): Thenable,
...
};

// The chunk cache contains all the chunks we've preloaded so far.
// 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];
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type ModuleReference = string;
export type ModuleMetaData = {
id: string,
chunks: Array<string>,
name: string,
};

export function resolveModuleMetaData(
Expand Down
9 changes: 9 additions & 0 deletions packages/react-noop-renderer/src/ReactNoopFlightClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
6 changes: 5 additions & 1 deletion scripts/flow/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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};
10 changes: 1 addition & 9 deletions scripts/flow/react-relay-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -43,17 +38,14 @@ 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,
): ModuleReference<T>;
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;
Expand Down

0 comments on commit c0cd1be

Please sign in to comment.