0
# Asynchronous Module Loading
1
2
Core functionality for loading modules asynchronously with bundle splitting support. This system enables dynamic imports and code splitting in Metro bundles, allowing for lazy loading of application features and optimized bundle sizes.
3
4
## Capabilities
5
6
### asyncRequire Function
7
8
Loads a module asynchronously, with support for bundle splitting and dynamic loading.
9
10
```javascript { .api }
11
/**
12
* Asynchronously loads a module with bundle splitting support
13
* @param moduleID - Numeric identifier of the module to load
14
* @param paths - Mapping of module IDs to bundle paths for lazy loading
15
* @param moduleName - Optional module name for debugging (unused in implementation)
16
* @returns Promise resolving to the loaded module
17
*/
18
function asyncRequire(
19
moduleID: number,
20
paths: ?DependencyMapPaths,
21
moduleName?: string
22
): Promise<any>;
23
24
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;
25
```
26
27
**Usage Examples:**
28
29
```javascript
30
const asyncRequire = require("metro-runtime/modules/asyncRequire");
31
32
// Load a feature module dynamically
33
const loadDashboard = async () => {
34
const dashboardModule = await asyncRequire(
35
123, // module ID assigned by Metro
36
{ 123: "/bundles/dashboard.bundle.js" }, // bundle path mapping
37
"dashboard" // optional name for debugging
38
);
39
return dashboardModule.default;
40
};
41
42
// Load multiple modules
43
const loadModules = async () => {
44
const [analytics, utils] = await Promise.all([
45
asyncRequire(200, { 200: "/bundles/analytics.js" }),
46
asyncRequire(201, { 201: "/bundles/utils.js" })
47
]);
48
return { analytics, utils };
49
};
50
```
51
52
### unstable_importMaybeSync Method
53
54
Synchronous version of asyncRequire that can still return a promise if the module requires bundle loading.
55
56
```javascript { .api }
57
/**
58
* Loads a module synchronously if available, asynchronously if bundle loading required
59
* @param moduleID - Numeric identifier of the module to load
60
* @param paths - Mapping of module IDs to bundle paths
61
* @returns Either the loaded module directly, or a Promise resolving to it
62
*/
63
asyncRequire.unstable_importMaybeSync = function(
64
moduleID: number,
65
paths: ?DependencyMapPaths
66
): Promise<any> | any;
67
```
68
69
**Usage Examples:**
70
71
```javascript
72
// Import that may be sync or async depending on bundle availability
73
const maybeLoadModule = (moduleId, paths) => {
74
const result = asyncRequire.unstable_importMaybeSync(moduleId, paths);
75
76
if (result instanceof Promise) {
77
// Module requires bundle loading
78
return result.then(module => {
79
console.log("Module loaded asynchronously");
80
return module;
81
});
82
} else {
83
// Module was already available
84
console.log("Module loaded synchronously");
85
return result;
86
}
87
};
88
```
89
90
### prefetch Method
91
92
Pre-loads a bundle without executing the module, useful for optimizing perceived performance.
93
94
```javascript { .api }
95
/**
96
* Pre-loads a bundle without executing the module
97
* @param moduleID - Numeric identifier of the module to prefetch
98
* @param paths - Mapping of module IDs to bundle paths
99
* @param moduleName - Optional module name for debugging (unused)
100
*/
101
asyncRequire.prefetch = function(
102
moduleID: number,
103
paths: ?DependencyMapPaths,
104
moduleName?: string
105
): void;
106
```
107
108
**Usage Examples:**
109
110
```javascript
111
// Prefetch modules that might be needed soon
112
const prefetchFeatures = () => {
113
const bundlePaths = {
114
100: "/bundles/settings.js",
115
101: "/bundles/profile.js",
116
102: "/bundles/notifications.js"
117
};
118
119
// Prefetch all feature bundles
120
asyncRequire.prefetch(100, bundlePaths, "settings");
121
asyncRequire.prefetch(101, bundlePaths, "profile");
122
asyncRequire.prefetch(102, bundlePaths, "notifications");
123
};
124
125
// Prefetch on user interaction
126
button.addEventListener("click", () => {
127
// Start loading the module before user needs it
128
asyncRequire.prefetch(150, { 150: "/bundles/heavy-feature.js" });
129
});
130
```
131
132
## Bundle Loading Mechanics
133
134
The async loading system works by:
135
136
1. **Module ID Resolution**: Each module is assigned a numeric ID by Metro bundler
137
2. **Path Mapping**: The `paths` parameter maps module IDs to their bundle URLs
138
3. **Global Bundle Loader**: Uses `global[__METRO_GLOBAL_PREFIX__ + '__loadBundleAsync']` to load bundles
139
4. **Fallback to Sync**: If no bundle loading is required, falls back to synchronous `require.importAll`
140
141
## Bundle Path Configuration
142
143
Bundle paths in the `paths` parameter should be configured based on your deployment:
144
145
```javascript
146
// Development configuration
147
const devPaths = {
148
42: "http://localhost:8081/bundles/feature.bundle.js"
149
};
150
151
// Production configuration
152
const prodPaths = {
153
42: "https://cdn.example.com/bundles/feature.bundle.js"
154
};
155
156
// React Native configuration
157
const nativePaths = {
158
42: "./bundles/feature.bundle"
159
};
160
```
161
162
## Error Handling
163
164
Bundle loading errors are handled gracefully:
165
166
```javascript
167
const safeAsyncRequire = async (moduleId, paths) => {
168
try {
169
const module = await asyncRequire(moduleId, paths);
170
return module;
171
} catch (error) {
172
console.error(`Failed to load module ${moduleId}:`, error);
173
// Return fallback or default implementation
174
return null;
175
}
176
};
177
```
178
179
## Integration with Metro Bundler
180
181
Metro Runtime's async loading system is designed to work seamlessly with Metro bundler's code splitting:
182
183
- Module IDs are assigned automatically during bundling
184
- Bundle paths are generated based on Metro's splitting configuration
185
- The system handles both web and React Native deployment scenarios
186
- Supports both development and production bundle loading strategies