CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-metro-runtime

Module required for evaluating Metro bundles with async loading and HMR support.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

async-loading.mddocs/

Asynchronous Module Loading

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.

Capabilities

asyncRequire Function

Loads a module asynchronously, with support for bundle splitting and dynamic loading.

/**
 * Asynchronously loads a module with bundle splitting support
 * @param moduleID - Numeric identifier of the module to load
 * @param paths - Mapping of module IDs to bundle paths for lazy loading
 * @param moduleName - Optional module name for debugging (unused in implementation)
 * @returns Promise resolving to the loaded module
 */
function asyncRequire(
  moduleID: number,
  paths: ?DependencyMapPaths,
  moduleName?: string
): Promise<any>;

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

Usage Examples:

const asyncRequire = require("metro-runtime/modules/asyncRequire");

// Load a feature module dynamically
const loadDashboard = async () => {
  const dashboardModule = await asyncRequire(
    123, // module ID assigned by Metro
    { 123: "/bundles/dashboard.bundle.js" }, // bundle path mapping
    "dashboard" // optional name for debugging
  );
  return dashboardModule.default;
};

// Load multiple modules
const loadModules = async () => {
  const [analytics, utils] = await Promise.all([
    asyncRequire(200, { 200: "/bundles/analytics.js" }),
    asyncRequire(201, { 201: "/bundles/utils.js" })
  ]);
  return { analytics, utils };
};

unstable_importMaybeSync Method

Synchronous version of asyncRequire that can still return a promise if the module requires bundle loading.

/**
 * Loads a module synchronously if available, asynchronously if bundle loading required
 * @param moduleID - Numeric identifier of the module to load
 * @param paths - Mapping of module IDs to bundle paths
 * @returns Either the loaded module directly, or a Promise resolving to it
 */
asyncRequire.unstable_importMaybeSync = function(
  moduleID: number,
  paths: ?DependencyMapPaths
): Promise<any> | any;

Usage Examples:

// Import that may be sync or async depending on bundle availability
const maybeLoadModule = (moduleId, paths) => {
  const result = asyncRequire.unstable_importMaybeSync(moduleId, paths);
  
  if (result instanceof Promise) {
    // Module requires bundle loading
    return result.then(module => {
      console.log("Module loaded asynchronously");
      return module;
    });
  } else {
    // Module was already available
    console.log("Module loaded synchronously");
    return result;
  }
};

prefetch Method

Pre-loads a bundle without executing the module, useful for optimizing perceived performance.

/**
 * Pre-loads a bundle without executing the module
 * @param moduleID - Numeric identifier of the module to prefetch
 * @param paths - Mapping of module IDs to bundle paths
 * @param moduleName - Optional module name for debugging (unused)
 */
asyncRequire.prefetch = function(
  moduleID: number,
  paths: ?DependencyMapPaths,
  moduleName?: string
): void;

Usage Examples:

// Prefetch modules that might be needed soon
const prefetchFeatures = () => {
  const bundlePaths = {
    100: "/bundles/settings.js",
    101: "/bundles/profile.js",
    102: "/bundles/notifications.js"
  };

  // Prefetch all feature bundles
  asyncRequire.prefetch(100, bundlePaths, "settings");
  asyncRequire.prefetch(101, bundlePaths, "profile");
  asyncRequire.prefetch(102, bundlePaths, "notifications");
};

// Prefetch on user interaction
button.addEventListener("click", () => {
  // Start loading the module before user needs it
  asyncRequire.prefetch(150, { 150: "/bundles/heavy-feature.js" });
});

Bundle Loading Mechanics

The async loading system works by:

  1. Module ID Resolution: Each module is assigned a numeric ID by Metro bundler
  2. Path Mapping: The paths parameter maps module IDs to their bundle URLs
  3. Global Bundle Loader: Uses global[__METRO_GLOBAL_PREFIX__ + '__loadBundleAsync'] to load bundles
  4. Fallback to Sync: If no bundle loading is required, falls back to synchronous require.importAll

Bundle Path Configuration

Bundle paths in the paths parameter should be configured based on your deployment:

// Development configuration
const devPaths = {
  42: "http://localhost:8081/bundles/feature.bundle.js"
};

// Production configuration  
const prodPaths = {
  42: "https://cdn.example.com/bundles/feature.bundle.js"
};

// React Native configuration
const nativePaths = {
  42: "./bundles/feature.bundle"
};

Error Handling

Bundle loading errors are handled gracefully:

const safeAsyncRequire = async (moduleId, paths) => {
  try {
    const module = await asyncRequire(moduleId, paths);
    return module;
  } catch (error) {
    console.error(`Failed to load module ${moduleId}:`, error);
    // Return fallback or default implementation
    return null;
  }
};

Integration with Metro Bundler

Metro Runtime's async loading system is designed to work seamlessly with Metro bundler's code splitting:

  • Module IDs are assigned automatically during bundling
  • Bundle paths are generated based on Metro's splitting configuration
  • The system handles both web and React Native deployment scenarios
  • Supports both development and production bundle loading strategies

docs

async-loading.md

hmr-client.md

index.md

require-polyfill.md

tile.json