Skip to content

Commit

Permalink
Move extended asyncRequire to open source
Browse files Browse the repository at this point in the history
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
  • Loading branch information
motiz88 authored and facebook-github-bot committed Apr 20, 2023
1 parent 6900e87 commit ac3adce
Showing 1 changed file with 67 additions and 6 deletions.
73 changes: 67 additions & 6 deletions packages/metro-runtime/src/modules/asyncRequire.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,75 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
* @flow strict
* @oncall react_native
*/

'use strict';
type Options = {isPrefetchOnly: boolean, ...};
type MetroRequire = {
(number): mixed,
importAll: number => mixed,
...
};

declare var require: MetroRequire;

const DEFAULT_OPTIONS = {isPrefetchOnly: false};

type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;

declare var __METRO_GLOBAL_PREFIX__: string;

async function asyncRequireImpl(
moduleID: number,
paths: DependencyMapPaths,
options: Options,
): Promise<mixed> {
const loadBundle: (bundlePath: mixed) => Promise<void> =
global[`${__METRO_GLOBAL_PREFIX__}__loadBundleAsync`];

// $FlowExpectedError Flow does not know about Metro's require extensions.
const dynamicRequire = (require: {importAll: mixed => mixed});
module.exports = function (moduleID: mixed): Promise<mixed> {
return Promise.resolve().then(() => dynamicRequire.importAll(moduleID));
if (loadBundle != null) {
const stringModuleID = String(moduleID);
const bundlePath = nullthrows(paths)[stringModuleID];
if (bundlePath != null) {
// NOTE: Errors will be swallowed by asyncRequire.prefetch
await loadBundle(bundlePath);
}
}

if (!options.isPrefetchOnly) {
return require.importAll(moduleID);
}

return undefined;
}

async function asyncRequire(
moduleID: number,
paths: DependencyMapPaths,
moduleName?: string,
): Promise<mixed> {
return asyncRequireImpl(moduleID, paths, DEFAULT_OPTIONS);
}

asyncRequire.prefetch = function (
moduleID: number,
paths: DependencyMapPaths,
moduleName?: string,
): void {
asyncRequireImpl(moduleID, paths, {isPrefetchOnly: true}).then(
() => {},
() => {},
);
};

module.exports = asyncRequire;

// Inline definition to save on a dependency
function nullthrows<T>(value: ?T): T {
if (value == null) {
throw new Error('Unexpected null or undefined');
}
return value;
}

0 comments on commit ac3adce

Please sign in to comment.