0
# Metro Runtime
1
2
Metro Runtime provides essential runtime modules required for evaluating and executing Metro bundles in React Native applications. It enables asynchronous module loading, Hot Module Replacement (HMR), and includes necessary runtime polyfills for cross-platform development.
3
4
## Package Information
5
6
- **Package Name**: metro-runtime
7
- **Package Type**: npm
8
- **Language**: JavaScript (with Flow types)
9
- **Installation**: Automatically included by Metro bundler (no manual installation required)
10
11
## Core Imports
12
13
Metro Runtime modules are automatically included by Metro bundler and typically not imported manually. When needed for custom implementations:
14
15
```javascript
16
// Async module loading (typically available globally as require.importAll)
17
const asyncRequire = require("metro-runtime/modules/asyncRequire");
18
19
// Hot Module Replacement client (development only)
20
const HMRClient = require("metro-runtime/modules/HMRClient");
21
22
// Module stubs for optimization
23
const emptyModule = require("metro-runtime/modules/empty-module"); // exports {}
24
const nullModule = require("metro-runtime/modules/null-module"); // exports null
25
26
// Core require polyfill (injected globally by Metro bundler)
27
// Available as global.__r, global.__d, etc.
28
require("metro-runtime/polyfills/require");
29
30
// Package metadata access
31
const packageInfo = require("metro-runtime/package.json");
32
```
33
34
## Package Metadata Access
35
36
The package.json file is exposed as a direct export for accessing package metadata:
37
38
```javascript { .api }
39
// Package metadata access
40
const packageInfo = require("metro-runtime/package.json");
41
```
42
43
## Private Module Access
44
45
Metro Runtime exposes private modules for internal Metro bundler usage via wildcard patterns:
46
47
- `./private/*` - Maps to `./src/*.js`
48
- `./src/*.js` - Direct access to source files
49
- `./src/*` - Alternative access pattern
50
51
These are typically used by Metro bundler itself and not intended for direct application usage.
52
53
## Basic Usage
54
55
Metro Runtime is typically used automatically by Metro bundler, but can be used directly for custom bundling scenarios:
56
57
```javascript
58
const asyncRequire = require("metro-runtime/modules/asyncRequire");
59
const HMRClient = require("metro-runtime/modules/HMRClient");
60
61
// Load a module asynchronously with bundle splitting support
62
const loadFeature = async () => {
63
const featureModule = await asyncRequire(
64
42, // module ID
65
{ 42: "/bundles/feature.bundle.js" } // path mapping
66
);
67
return featureModule;
68
};
69
70
// Set up HMR client for development
71
const client = new HMRClient("ws://localhost:8081/hot");
72
client.enable();
73
74
client.on("update", (update) => {
75
console.log("Hot update received:", update);
76
});
77
```
78
79
## Architecture
80
81
Metro Runtime is built around several key components:
82
83
- **Async Loading System**: Handles dynamic imports and bundle splitting with support for lazy loading
84
- **HMR Client**: WebSocket-based client for receiving and applying hot updates during development
85
- **Module System Polyfills**: Cross-platform require implementation with React Native compatibility
86
- **Module Stubs**: Empty and null modules for build optimization and conditional loading
87
- **React Fast Refresh Integration**: Component-level hot reloading with state preservation
88
89
## Capabilities
90
91
### Asynchronous Module Loading
92
93
Core functionality for loading modules asynchronously with bundle splitting support. Enables dynamic imports and code splitting in Metro bundles.
94
95
```javascript { .api }
96
// Async module loading with bundle splitting support
97
function asyncRequire(moduleID: number, paths: ?DependencyMapPaths, moduleName?: string): Promise<any>;
98
99
// Synchronous version that may return promise if bundle loading required
100
asyncRequire.unstable_importMaybeSync = function(moduleID: number, paths: ?DependencyMapPaths): Promise<any> | any;
101
102
// Pre-loads bundle without executing module
103
asyncRequire.prefetch = function(moduleID: number, paths: ?DependencyMapPaths, moduleName?: string): void;
104
105
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;
106
```
107
108
[Async Loading](./async-loading.md)
109
110
### Hot Module Replacement Client
111
112
WebSocket-based client for receiving and applying hot updates during development. Provides real-time code updates without losing application state.
113
114
```javascript { .api }
115
// Hot Module Replacement WebSocket client
116
class HMRClient extends EventEmitter {
117
constructor(url: string);
118
close(): void;
119
send(message: string): void;
120
enable(): void;
121
disable(): void;
122
isEnabled(): boolean;
123
hasPendingUpdates(): boolean;
124
}
125
126
type SocketState = 'opening' | 'open' | 'closed';
127
```
128
129
[HMR Client](./hmr-client.md)
130
131
### Require System Polyfill
132
133
Core Metro require system implementation with module loading, HMR support, and development utilities. Provides cross-platform module resolution and loading.
134
135
```javascript { .api }
136
// Core Metro require function (available as global.__r)
137
function metroRequire(moduleId: ModuleID | VerboseModuleNameForDev, maybeNameForDev?: string): Exports;
138
139
// Module definition function (available as global.__d)
140
function define(factory: FactoryFn, moduleId: number, dependencyMap?: DependencyMap, verboseName?: string, inverseDependencies?: InverseDependencyMap): void;
141
142
// Enhanced import functions
143
metroRequire.importDefault = function(moduleId: ModuleID | VerboseModuleNameForDev): any | Exports;
144
metroRequire.importAll = function(moduleId: ModuleID | VerboseModuleNameForDev): any | Exports | {[string]: any};
145
146
// Module ID utilities for segmented bundles
147
metroRequire.unpackModuleId = function(moduleId: ModuleID): {localId: number, segmentId: number};
148
metroRequire.packModuleId = function(value: {localId: number, segmentId: number}): ModuleID;
149
150
type ModuleID = number;
151
type VerboseModuleNameForDev = string;
152
type Exports = any;
153
```
154
155
[Require Polyfill](./require-polyfill.md)
156
157
### Module Stubs
158
159
Provides empty and null module stubs for build optimization and conditional loading scenarios.
160
161
```javascript { .api }
162
// Empty module stub - exports empty object {}
163
const emptyModule = require("metro-runtime/modules/empty-module");
164
165
// Null module stub - exports null
166
const nullModule = require("metro-runtime/modules/null-module");
167
```
168
169
These stubs are used by Metro bundler for:
170
- **Tree shaking optimization**: Replace unused modules with empty stubs
171
- **Conditional compilation**: Provide placeholder modules for platform-specific code
172
- **Build size reduction**: Replace heavy modules with lightweight stubs in certain contexts
173
174
## Types
175
176
Core type definitions used across Metro Runtime:
177
178
```javascript { .api }
179
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;
180
181
type ModuleID = number;
182
type VerboseModuleNameForDev = string;
183
type Exports = any;
184
type RequireFn = (id: ModuleID | VerboseModuleNameForDev) => Exports;
185
186
type FactoryFn = (
187
global: Object,
188
require: RequireFn,
189
metroImportDefault: RequireFn,
190
metroImportAll: RequireFn,
191
moduleObject: {exports: {...}, ...},
192
exports: {...},
193
dependencyMap: ?DependencyMap,
194
) => void;
195
196
// Module system types
197
type DependencyMap = $ReadOnly<ArrayIndexable<ModuleID> & {paths?: {[id: ModuleID]: string}}>;
198
type InverseDependencyMap = {[key: ModuleID]: Array<ModuleID>, ...};
199
type ArrayIndexable<T> = interface {+[indexer: number]: T};
200
201
// Bundle and module types
202
type ModuleMap = $ReadOnlyArray<[number, string]>;
203
204
type Bundle = {
205
+modules: ModuleMap,
206
+post: string,
207
+pre: string,
208
};
209
210
type DeltaBundle = {
211
+added: ModuleMap,
212
+modified: ModuleMap,
213
+deleted: $ReadOnlyArray<number>,
214
};
215
216
type BundleVariant =
217
| {+base: true, +revisionId: string, ...Bundle}
218
| {+base: false, +revisionId: string, ...DeltaBundle};
219
220
type BundleMetadata = {
221
+pre: number,
222
+post: number,
223
+modules: $ReadOnlyArray<[number, number]>,
224
};
225
226
// HMR types
227
type HmrUpdate = {
228
+added: $ReadOnlyArray<HmrModule>,
229
+deleted: $ReadOnlyArray<number>,
230
+isInitialUpdate: boolean,
231
+modified: $ReadOnlyArray<HmrModule>,
232
+revisionId: string,
233
};
234
235
type HmrModule = {
236
+module: [number, string],
237
+sourceMappingURL: string,
238
+sourceURL: string,
239
};
240
241
type FormattedError = {
242
+type: string,
243
+message: string,
244
+errors: Array<{description: string, ...}>,
245
};
246
247
// HMR message types
248
type HmrMessage =
249
| {+type: 'bundle-registered'}
250
| {+type: 'update-start', +body: {+isInitialUpdate: boolean}}
251
| {+type: 'update-done'}
252
| {+type: 'update', +body: HmrUpdate}
253
| {+type: 'error', +body: FormattedError};
254
255
type HmrClientMessage =
256
| {+type: 'register-entrypoints', +entryPoints: Array<string>}
257
| {+type: 'log', +level: 'trace' | 'info' | 'warn' | 'log' | 'group' | 'groupCollapsed' | 'groupEnd' | 'debug', +data: Array<mixed>, +mode: 'BRIDGE' | 'NOBRIDGE'}
258
| {+type: 'log-opt-in'};
259
260
// Development types (DEV only)
261
type HotModuleReloadingData = {
262
_acceptCallback: ?HotModuleReloadingCallback,
263
_disposeCallback: ?HotModuleReloadingCallback,
264
_didAccept: boolean,
265
accept: (callback?: HotModuleReloadingCallback) => void,
266
dispose: (callback?: HotModuleReloadingCallback) => void,
267
};
268
269
type HotModuleReloadingCallback = () => void;
270
```