Module required for evaluating Metro bundles with async loading and HMR support.
npx @tessl/cli install tessl/npm-metro-runtime@0.83.0Metro 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.
Metro Runtime modules are automatically included by Metro bundler and typically not imported manually. When needed for custom implementations:
// Async module loading (typically available globally as require.importAll)
const asyncRequire = require("metro-runtime/modules/asyncRequire");
// Hot Module Replacement client (development only)
const HMRClient = require("metro-runtime/modules/HMRClient");
// Module stubs for optimization
const emptyModule = require("metro-runtime/modules/empty-module"); // exports {}
const nullModule = require("metro-runtime/modules/null-module"); // exports null
// Core require polyfill (injected globally by Metro bundler)
// Available as global.__r, global.__d, etc.
require("metro-runtime/polyfills/require");
// Package metadata access
const packageInfo = require("metro-runtime/package.json");The package.json file is exposed as a direct export for accessing package metadata:
// Package metadata access
const packageInfo = require("metro-runtime/package.json");Metro Runtime exposes private modules for internal Metro bundler usage via wildcard patterns:
./private/* - Maps to ./src/*.js./src/*.js - Direct access to source files./src/* - Alternative access patternThese are typically used by Metro bundler itself and not intended for direct application usage.
Metro Runtime is typically used automatically by Metro bundler, but can be used directly for custom bundling scenarios:
const asyncRequire = require("metro-runtime/modules/asyncRequire");
const HMRClient = require("metro-runtime/modules/HMRClient");
// Load a module asynchronously with bundle splitting support
const loadFeature = async () => {
const featureModule = await asyncRequire(
42, // module ID
{ 42: "/bundles/feature.bundle.js" } // path mapping
);
return featureModule;
};
// Set up HMR client for development
const client = new HMRClient("ws://localhost:8081/hot");
client.enable();
client.on("update", (update) => {
console.log("Hot update received:", update);
});Metro Runtime is built around several key components:
Core functionality for loading modules asynchronously with bundle splitting support. Enables dynamic imports and code splitting in Metro bundles.
// Async module loading with bundle splitting support
function asyncRequire(moduleID: number, paths: ?DependencyMapPaths, moduleName?: string): Promise<any>;
// Synchronous version that may return promise if bundle loading required
asyncRequire.unstable_importMaybeSync = function(moduleID: number, paths: ?DependencyMapPaths): Promise<any> | any;
// Pre-loads bundle without executing module
asyncRequire.prefetch = function(moduleID: number, paths: ?DependencyMapPaths, moduleName?: string): void;
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;WebSocket-based client for receiving and applying hot updates during development. Provides real-time code updates without losing application state.
// Hot Module Replacement WebSocket client
class HMRClient extends EventEmitter {
constructor(url: string);
close(): void;
send(message: string): void;
enable(): void;
disable(): void;
isEnabled(): boolean;
hasPendingUpdates(): boolean;
}
type SocketState = 'opening' | 'open' | 'closed';Core Metro require system implementation with module loading, HMR support, and development utilities. Provides cross-platform module resolution and loading.
// Core Metro require function (available as global.__r)
function metroRequire(moduleId: ModuleID | VerboseModuleNameForDev, maybeNameForDev?: string): Exports;
// Module definition function (available as global.__d)
function define(factory: FactoryFn, moduleId: number, dependencyMap?: DependencyMap, verboseName?: string, inverseDependencies?: InverseDependencyMap): void;
// Enhanced import functions
metroRequire.importDefault = function(moduleId: ModuleID | VerboseModuleNameForDev): any | Exports;
metroRequire.importAll = function(moduleId: ModuleID | VerboseModuleNameForDev): any | Exports | {[string]: any};
// Module ID utilities for segmented bundles
metroRequire.unpackModuleId = function(moduleId: ModuleID): {localId: number, segmentId: number};
metroRequire.packModuleId = function(value: {localId: number, segmentId: number}): ModuleID;
type ModuleID = number;
type VerboseModuleNameForDev = string;
type Exports = any;Provides empty and null module stubs for build optimization and conditional loading scenarios.
// Empty module stub - exports empty object {}
const emptyModule = require("metro-runtime/modules/empty-module");
// Null module stub - exports null
const nullModule = require("metro-runtime/modules/null-module");These stubs are used by Metro bundler for:
Core type definitions used across Metro Runtime:
type DependencyMapPaths = ?$ReadOnly<{[moduleID: number | string]: mixed}>;
type ModuleID = number;
type VerboseModuleNameForDev = string;
type Exports = any;
type RequireFn = (id: ModuleID | VerboseModuleNameForDev) => Exports;
type FactoryFn = (
global: Object,
require: RequireFn,
metroImportDefault: RequireFn,
metroImportAll: RequireFn,
moduleObject: {exports: {...}, ...},
exports: {...},
dependencyMap: ?DependencyMap,
) => void;
// Module system types
type DependencyMap = $ReadOnly<ArrayIndexable<ModuleID> & {paths?: {[id: ModuleID]: string}}>;
type InverseDependencyMap = {[key: ModuleID]: Array<ModuleID>, ...};
type ArrayIndexable<T> = interface {+[indexer: number]: T};
// Bundle and module types
type ModuleMap = $ReadOnlyArray<[number, string]>;
type Bundle = {
+modules: ModuleMap,
+post: string,
+pre: string,
};
type DeltaBundle = {
+added: ModuleMap,
+modified: ModuleMap,
+deleted: $ReadOnlyArray<number>,
};
type BundleVariant =
| {+base: true, +revisionId: string, ...Bundle}
| {+base: false, +revisionId: string, ...DeltaBundle};
type BundleMetadata = {
+pre: number,
+post: number,
+modules: $ReadOnlyArray<[number, number]>,
};
// HMR types
type HmrUpdate = {
+added: $ReadOnlyArray<HmrModule>,
+deleted: $ReadOnlyArray<number>,
+isInitialUpdate: boolean,
+modified: $ReadOnlyArray<HmrModule>,
+revisionId: string,
};
type HmrModule = {
+module: [number, string],
+sourceMappingURL: string,
+sourceURL: string,
};
type FormattedError = {
+type: string,
+message: string,
+errors: Array<{description: string, ...}>,
};
// HMR message types
type HmrMessage =
| {+type: 'bundle-registered'}
| {+type: 'update-start', +body: {+isInitialUpdate: boolean}}
| {+type: 'update-done'}
| {+type: 'update', +body: HmrUpdate}
| {+type: 'error', +body: FormattedError};
type HmrClientMessage =
| {+type: 'register-entrypoints', +entryPoints: Array<string>}
| {+type: 'log', +level: 'trace' | 'info' | 'warn' | 'log' | 'group' | 'groupCollapsed' | 'groupEnd' | 'debug', +data: Array<mixed>, +mode: 'BRIDGE' | 'NOBRIDGE'}
| {+type: 'log-opt-in'};
// Development types (DEV only)
type HotModuleReloadingData = {
_acceptCallback: ?HotModuleReloadingCallback,
_disposeCallback: ?HotModuleReloadingCallback,
_didAccept: boolean,
accept: (callback?: HotModuleReloadingCallback) => void,
dispose: (callback?: HotModuleReloadingCallback) => void,
};
type HotModuleReloadingCallback = () => void;