Skip to content

Commit ac3adce

Browse files
motiz88facebook-github-bot
authored andcommitted
Move extended asyncRequire to open source
Summary: Changelog: * **[Feature]**: Support custom `__loadBundleAsync` implementations in the default `asyncRequire` function. See the [lazy bundling RFC](https://github.com/react-native-community/discussions-and-proposals/blob/main/proposals/0605-lazy-bundling.md) for more details. Reviewed By: huntie Differential Revision: D43600050 fbshipit-source-id: f99b5c4f33bd39be522e072d5f4744122277355c
1 parent 6900e87 commit ac3adce

File tree

1 file changed

+67
-6
lines changed

1 file changed

+67
-6
lines changed

packages/metro-runtime/src/modules/asyncRequire.js

+67-6
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,75 @@
44
* This source code is licensed under the MIT license found in the
55
* LICENSE file in the root directory of this source tree.
66
*
7+
* @flow strict-local
78
* @format
8-
* @flow strict
9+
* @oncall react_native
910
*/
1011

11-
'use strict';
12+
type Options = {isPrefetchOnly: boolean, ...};
13+
type MetroRequire = {
14+
(number): mixed,
15+
importAll: number => mixed,
16+
...
17+
};
18+
19+
declare var require: MetroRequire;
20+
21+
const DEFAULT_OPTIONS = {isPrefetchOnly: false};
22+
23+
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;
24+
25+
declare var __METRO_GLOBAL_PREFIX__: string;
26+
27+
async function asyncRequireImpl(
28+
moduleID: number,
29+
paths: DependencyMapPaths,
30+
options: Options,
31+
): Promise<mixed> {
32+
const loadBundle: (bundlePath: mixed) => Promise<void> =
33+
global[`${__METRO_GLOBAL_PREFIX__}__loadBundleAsync`];
1234

13-
// $FlowExpectedError Flow does not know about Metro's require extensions.
14-
const dynamicRequire = (require: {importAll: mixed => mixed});
15-
module.exports = function (moduleID: mixed): Promise<mixed> {
16-
return Promise.resolve().then(() => dynamicRequire.importAll(moduleID));
35+
if (loadBundle != null) {
36+
const stringModuleID = String(moduleID);
37+
const bundlePath = nullthrows(paths)[stringModuleID];
38+
if (bundlePath != null) {
39+
// NOTE: Errors will be swallowed by asyncRequire.prefetch
40+
await loadBundle(bundlePath);
41+
}
42+
}
43+
44+
if (!options.isPrefetchOnly) {
45+
return require.importAll(moduleID);
46+
}
47+
48+
return undefined;
49+
}
50+
51+
async function asyncRequire(
52+
moduleID: number,
53+
paths: DependencyMapPaths,
54+
moduleName?: string,
55+
): Promise<mixed> {
56+
return asyncRequireImpl(moduleID, paths, DEFAULT_OPTIONS);
57+
}
58+
59+
asyncRequire.prefetch = function (
60+
moduleID: number,
61+
paths: DependencyMapPaths,
62+
moduleName?: string,
63+
): void {
64+
asyncRequireImpl(moduleID, paths, {isPrefetchOnly: true}).then(
65+
() => {},
66+
() => {},
67+
);
1768
};
69+
70+
module.exports = asyncRequire;
71+
72+
// Inline definition to save on a dependency
73+
function nullthrows<T>(value: ?T): T {
74+
if (value == null) {
75+
throw new Error('Unexpected null or undefined');
76+
}
77+
return value;
78+
}

0 commit comments

Comments
 (0)