### npm Package Resolution Example Source: https://www.reactnative.run/docs/resolution Explains how paths not starting with '.' or '/' are treated as npm packages. This includes direct package names, subpaths, and scoped packages. ```javascript require("react") → npm package "react" require("lodash/chunk") → npm package "lodash", subpath "/chunk" require("@expo/vector-icons") → scoped npm package ``` -------------------------------- ### Example URL Mappings Source: https://www.reactnative.run/docs/esm-server Illustrates how different URL formats map to package, version, and subpath parameters. ```plaintext URL| Package| Version| Subpath ---|---|---|--- `/pkg/lodash`| lodash| latest| - `/pkg/lodash@4.17.21`| lodash| 4.17.21| - `/pkg/react-dom/client`| react-dom| latest| /client `/pkg/react-dom@19/client`| react-dom| 19| /client `/pkg/@scope/name@1.0/sub`| @scope/name| 1.0| /sub ``` -------------------------------- ### Bundler.bundle() Method Source: https://www.reactnative.run/docs/api/bundler Bundles the project starting from a specified entry file and returns the complete bundle as a string. ```APIDOC ## Bundler.bundle() ### Description Bundles the project starting from `entryFile`. Returns the complete bundle as a string. ### Method `async bundle(entryFile: string): Promise` ### Endpoint N/A (Method of the Bundler class) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript const code = await bundler.bundle("/index.ts"); // code is a self-executing bundle string with inline source map ``` ### Response #### Success Response (200) - **code** (string) - The complete bundle as a string, including an inline source map. #### Response Example ``` // Example of bundle string (truncated) "var process = globalThis.process || {};\nprocess.env = process.env || {};\nprocess.env.NODE_ENV = process.env.NODE_ENV || \"development\";\n// ... rest of the bundled code ...\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,..." ``` ### Bundle Process 1. Walks the dependency graph from the entry file 2. Runs the plugin + transformer pipeline on each file 3. Rewrites relative `require()` calls to absolute paths 4. Fetches any npm packages from the ESM server 5. Emits a self-executing CommonJS bundle with combined source map ``` -------------------------------- ### Local Development Commands Source: https://www.reactnative.run/docs/esm-server Instructions for installing dependencies, running the server in development mode with auto-reloading, and running in production mode. Specifies the default server address. ```bash cd reactnative-esm npm install npm run dev # with auto-reload npm start # production # Server runs on http://localhost:5200 ``` -------------------------------- ### Example: Module Aliases Plugin Source: https://www.reactnative.run/docs/api/plugins An example demonstrating how to use the `moduleAliases` and `shimModules` hooks to alias 'react-native' to 'react-native-web' and provide a shim for 'expo-haptics'. ```APIDOC ## Example: Module Aliases ```javascript const expoWebPlugin: BundlerPlugin = { name: "expo-web", moduleAliases() { return { "react-native": "react-native-web", }; }, shimModules() { return { "expo-haptics": "module.exports = { impactAsync() {}, selectionAsync() {} };", }; }, }; ``` ``` -------------------------------- ### POST /bundle-deps Source: https://www.reactnative.run/docs/batch-fetching Submits a list of dependencies to be installed, bundled, and returned as a single JavaScript response. This is used when a cache miss occurs for the GET request. ```APIDOC ## POST /bundle-deps ### Description Installs all dependencies, bundles each package with esbuild, and returns a single concatenated JS response. This is used when the dependency bundle is not found in the cache. ### Method POST ### Endpoint `/bundle-deps` ### Parameters #### Request Body - **hash** (string) - Required - The SHA-256 hash of the sorted dependencies. - **dependencies** (object) - Required - An object where keys are package names and values are their versions. - **package_name** (string) - Required - The version of the dependency. ### Request Example ```json { "hash": "a1b2c3d4e5f67890", "dependencies": { "react": "19.1.0", "react-dom": "19.1.0", "expo-router": "~6.0.12", "expo": "~54.0.33" } } ``` ### Response #### Success Response (200) - **body** (string) - A concatenated JavaScript string containing all bundled dependencies, delimited by `// @dep-start` and `// @dep-end` markers. #### Response Example ```javascript // @dep-bundle a1b2c3d4e5f67890 // @dep-manifest {"react":"19.1.0","expo-router":"6.0.12",...} // @dep-count 18 // @dep-start react var __module = (() => { /* esbuild IIFE bundle */ })(); if (typeof __module !== "undefined") { module.exports = __module; } // @dep-end react // @dep-start react-dom ... // @dep-end react-dom ``` ``` -------------------------------- ### Writing an API Route Handler Source: https://www.reactnative.run/docs/api-routes Example of GET and POST handlers for an API route. Supports dynamic segments and JSON responses. ```typescript // /app/api/hello+api.ts export function GET(request: Request) { return Response.json({ message: "Hello from the API!", timestamp: Date.now(), }); } export function POST(request: Request) { const body = await request.json(); return Response.json({ received: body, echo: true, }); } ``` -------------------------------- ### Example: Transform Output Plugin Source: https://www.reactnative.run/docs/api/plugins An example of a plugin that uses the `transformOutput` hook to add a console log statement at the beginning of each module. ```APIDOC ## Example: Transform Hook ```javascript const loggingPlugin: BundlerPlugin = { name: "logging", transformOutput({ code, filename }) { // Add a log statement at the top of every module return { code: `console.log("Loading: ${filename}");\n${code}`, }; }, }; ``` ``` -------------------------------- ### Logging Plugin Example Source: https://www.reactnative.run/docs/api/plugins An example of a custom plugin that uses the `transformOutput` hook to add a `console.log` statement at the beginning of each module. ```javascript const loggingPlugin: BundlerPlugin = { name: "logging", transformOutput({ code, filename }) { // Add a log statement at the top of every module return { code: `console.log("Loading: ${filename}");\n${code}`, }; }, }; ``` -------------------------------- ### Index File Resolution Example Source: https://www.reactnative.run/docs/resolution Illustrates how the resolver looks for index files (e.g., index.ts) when a path resolves to a directory. This allows importing directories directly. ```javascript /src/components → not found /src/components/index.ts → found! ✓ ``` -------------------------------- ### Resolver Configuration Example Source: https://www.reactnative.run/docs/resolution Shows how to configure the resolver, including setting custom source extensions and defining path aliases for cleaner imports. Path aliases are typically used for organizing project structure. ```typescript const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"], paths: { "@/*": ["./*"], // TypeScript path aliases }, }, // ... }; ``` -------------------------------- ### Expo Web Plugin Example Source: https://www.reactnative.run/docs/api/plugins An example of a custom plugin that aliases `react-native` to `react-native-web` and shims `expo-haptics` with mock functions. ```javascript const expoWebPlugin: BundlerPlugin = { name: "expo-web", moduleAliases() { return { "react-native": "react-native-web", }; }, shimModules() { return { "expo-haptics": "module.exports = { impactAsync() {}, selectionAsync() {} };", }; }, }; ``` -------------------------------- ### Babel-based Custom Transformer Example Source: https://www.reactnative.run/docs/transformation An example of a custom transformer using Babel for JavaScript, TypeScript, and React compilation. Ensure `@babel/standalone` is installed. ```typescript import { transform } from "@babel/standalone"; const babelTransformer: Transformer = { transform({ src, filename }) { const presets = ["env"]; if (filename.endsWith(".tsx") || filename.endsWith(".ts")) { presets.push("typescript"); } if (filename.endsWith(".tsx") || filename.endsWith(".jsx")) { presets.push("react"); } const result = transform(src, { filename, presets, sourceType: "module" }); return { code: result.code }; } }; ``` -------------------------------- ### Version Pinning Header Example Source: https://www.reactnative.run/docs/esm-server Shows the X-Externals header format used for version pinning of externalized dependencies. This header prevents version mismatches in transitive dependencies. ```json X-Externals: {"react":"19.1.0","react-dom":"19.1.0","memoize-one":"4.1.0"} ``` -------------------------------- ### POST /bundle-deps Request Body Example Source: https://www.reactnative.run/docs/batch-fetching Shows the JSON payload structure for the POST /bundle-deps endpoint, including the hash and a list of dependencies with their versions. ```json { "hash": "a1b2c3d4e5f67890", "dependencies": { "react": "19.1.0", "react-dom": "19.1.0", "expo-router": "~6.0.12", "expo": "~54.0.33" } } ``` -------------------------------- ### Install browser-metro Package Source: https://www.reactnative.run/docs Install the browser-metro library using npm. This is the core bundler for the client-side React Native development environment. ```bash npm install browser-metro ``` -------------------------------- ### Run Local ESM Server Source: https://www.reactnative.run/docs/quick-start Set up and start a local ESM package server for development using npm commands. This server runs on http://localhost:5200. ```bash cd reactnative-esm npm install npm start # Server runs on http://localhost:5200 ``` -------------------------------- ### Bundle Project Entry File Source: https://www.reactnative.run/docs/api/bundler Bundles the entire project starting from a specified entry file. Returns the complete, self-executing bundle as a string with an inline source map. ```typescript const code = await bundler.bundle("/index.ts"); // code is a self-executing bundle string with inline source map ``` -------------------------------- ### Relative Import Resolution Example Source: https://www.reactnative.run/docs/resolution Demonstrates how relative import paths are resolved based on the importing file's directory. './' resolves from the current directory, and '../' resolves from the parent directory. ```javascript require("./utils") → resolves from /src/ require("../lib") → resolves from / ``` -------------------------------- ### List All Files in VirtualFS Source: https://www.reactnative.run/docs/api/virtual-fs Get an array of all file paths currently stored in the VirtualFS. The order of files in the returned array is not guaranteed. ```typescript vfs.list(); // ["/index.js", "/utils.js"] ``` -------------------------------- ### Extension Resolution Example Source: https://www.reactnative.run/docs/resolution Shows how the resolver attempts to find a file by trying configured source extensions. The default extensions include ts, tsx, js, and jsx. ```javascript /src/utils → not found /src/utils.ts → found! ✓ ``` -------------------------------- ### Set Default Environment Variables Source: https://www.reactnative.run/docs/api/bundler Configures the bundle preamble to set default environment variables like NODE_ENV. This setup is applied to every emitted bundle. ```javascript var process = globalThis.process || {}; process.env = process.env || {}; process.env.NODE_ENV = process.env.NODE_ENV || "development"; ``` -------------------------------- ### Extension-Specific Routing Transformer Example Source: https://www.reactnative.run/docs/transformation A custom transformer that routes transformations based on file extensions, falling back to the TypeScript transformer for unknown types. ```typescript const routingTransformer: Transformer = { transform({ src, filename }) { const ext = filename.slice(filename.lastIndexOf(".")); switch (ext) { case ".svelte": return svelteTransformer.transform({ src, filename }); case ".vue": return vueTransformer.transform({ src, filename }); default: return typescriptTransformer.transform({ src, filename }); } } }; ``` -------------------------------- ### GET /bundle-deps/:hash Source: https://www.reactnative.run/docs/batch-fetching Retrieves a cached bundle of dependencies if it exists. This endpoint is designed for CDN caching with a long max-age. ```APIDOC ## GET /bundle-deps/:hash ### Description Returns the cached bundle if it exists. Served with `Cache-Control: public, max-age=31536000, immutable` for CDN caching. Returns 404 if not cached. ### Method GET ### Endpoint `/bundle-deps/:hash` ### Parameters #### Path Parameters - **hash** (string) - Required - The SHA-256 hash of the sorted dependencies. ``` -------------------------------- ### FileMap Interface and Example Source: https://www.reactnative.run/docs/virtual-fs Defines the structure of a FileMap, which is a plain object mapping absolute file paths to their source code content. Used to represent a project's files in memory. ```typescript interface FileMap { [path: string]: string; // absolute path → source code } const files: FileMap = { "/index.tsx": 'import App from "./App";\n...', "/App.tsx": 'export default function App() { return ; }', "/package.json": '{ "dependencies": { "react": "^19" } }', }; ``` -------------------------------- ### Plugin resolveRequest Hook Example Source: https://www.reactnative.run/docs/resolution Demonstrates how plugins can intercept and modify module resolution using the `resolveRequest` hook. This allows for custom logic like redirecting module names. ```typescript const myPlugin: BundlerPlugin = { name: "my-plugin", resolveRequest(context, moduleName) { if (moduleName === "react-native") { return "react-native-web"; // redirect } return null; // fall through to default resolution }, }; ``` -------------------------------- ### Create DataBxPath Plugin Source: https://www.reactnative.run/docs/api/plugins A built-in plugin that injects `data-bx-path` attributes into JSX elements for click-to-source functionality. Lowercase HTML tags get `data-bx-path`, while uppercase component tags use `dataSet`. ```javascript import { createDataBxPathPlugin } from "browser-metro"; const plugin = createDataBxPathPlugin(); // Use in config: plugins: [plugin] ``` -------------------------------- ### Load Tailwind CSS via CDN Source: https://www.reactnative.run/docs/assets Projects using Tailwind CSS can load it via CDN in the preview iframe. This setup allows for immediate use of Tailwind utility classes. ```html ``` -------------------------------- ### Bundler Initialization and Usage Source: https://www.reactnative.run/docs/api/bundler Demonstrates how to initialize the Bundler with a VirtualFS and BundlerConfig, and how to use it to bundle an entry file. ```APIDOC ## Bundler Initialization and Usage ### Description Initializes the main one-shot bundler class, which takes a `VirtualFS` and `BundlerConfig`, walks the dependency graph, transforms files, fetches npm packages, and emits an executable bundle with an appended inline source map. ### Usage ```typescript import { Bundler, VirtualFS, typescriptTransformer } from "browser-metro"; import type { BundlerConfig } from "browser-metro"; const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: typescriptTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, }; const bundler = new Bundler(vfs, config); ``` ``` -------------------------------- ### Initialize Bundler with Configuration Source: https://www.reactnative.run/docs/api/bundler Configure the bundler with source extensions, a transformer, and a package server URL. Requires a VirtualFS instance. ```typescript import { Bundler, VirtualFS, typescriptTransformer } from "browser-metro"; import type { BundlerConfig } from "browser-metro"; const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: typescriptTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, }; const bundler = new Bundler(vfs, config); ``` -------------------------------- ### Initialize VirtualFS with Files Source: https://www.reactnative.run/docs/api/virtual-fs Instantiate the VirtualFS class with an initial map of file paths and their content. Ensure necessary imports are included. ```typescript import { VirtualFS } from "browser-metro"; import type { FileMap } from "browser-metro"; const files: FileMap = { "/index.js": 'console.log("hello");', "/utils.js": 'module.exports = { add: (a, b) => a + b };', }; const vfs = new VirtualFS(files); ``` -------------------------------- ### Perform Initial Full Build Source: https://www.reactnative.run/docs/api/incremental-bundler Call `build()` to perform the initial, complete bundling of your application. This method must be executed before any subsequent `rebuild()` calls. The result contains the full bundle string and indicates a 'full' build type. ```typescript const result = await bundler.build("/index.tsx"); // result.bundle -- full bundle string // result.type -- "full" // result.hmrUpdate -- null (initial build) ``` -------------------------------- ### IncrementalBundler Initialization Source: https://www.reactnative.run/docs/api/incremental-bundler Demonstrates how to initialize the IncrementalBundler with a configuration. ```APIDOC ## IncrementalBundler Initialization ### Description Initializes the IncrementalBundler with a virtual file system and configuration. ### Usage ```typescript import { IncrementalBundler, VirtualFS, reactRefreshTransformer } from "browser-metro"; const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: reactRefreshTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, hmr: { enabled: true, reactRefresh: true }, plugins: [myPlugin], }; const bundler = new IncrementalBundler(vfs, config); ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response None ``` -------------------------------- ### Bundle Preamble and Environment Variable Injection Source: https://www.reactnative.run/docs/api/bundler Explains the bundle preamble that sets up `process.env` and how environment variables are injected via the `env` config option. ```APIDOC ## Bundle Preamble and Environment Variable Injection ### Description Every emitted bundle is prefixed with a preamble that sets up `process.env`. The `env` config option injects environment variables, with security filtering for public prefixes. ### Bundle Preamble ```javascript var process = globalThis.process || {}; process.env = process.env || {}; process.env.NODE_ENV = process.env.NODE_ENV || "development"; ``` ### Environment Variable Injection The `env` config option injects environment variables. For security, only vars with public prefixes are included: * `EXPO_PUBLIC_*` * `NEXT_PUBLIC_*` ### Configuration Example ```typescript const config: BundlerConfig = { // ... env: { EXPO_PUBLIC_API_URL: "https://api.example.com", SECRET_KEY: "abc123", // filtered out }, }; ``` ``` -------------------------------- ### VirtualFS API Usage Source: https://www.reactnative.run/docs/virtual-fs Demonstrates common operations on the VirtualFS, including reading, writing, checking existence, listing files, and retrieving the internal file map. Ensure 'browser-metro' is imported. ```javascript import { VirtualFS } from "browser-metro"; const vfs = new VirtualFS(files); // Read a file vfs.read("/index.tsx"); // returns content string or undefined // Write a file (create or overwrite) vfs.write("/new-file.ts", "export const x = 1;"); // Check existence vfs.exists("/index.tsx"); // true // List all files vfs.list(); // ["/index.tsx", "/App.tsx", "/package.json", "/new-file.ts"] // Get a copy of the internal file map vfs.toFileMap(); // { "/index.tsx": "...", ... } // Find entry file (tries /index.js, /index.ts, /index.tsx, /index.jsx) vfs.getEntryFile(); // "/index.tsx" ``` -------------------------------- ### Initialize Browser-Metro Bundler Source: https://www.reactnative.run/docs/batch-fetching Instantiate the Bundler with custom resolver, transformer, and server configurations. The `bundle()` method internally calls `prefetchDependencies()`. ```javascript import { Bundler, VirtualFS, typescriptTransformer } from "browser-metro"; const bundler = new Bundler(vfs, { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: typescriptTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, }); // bundle() automatically calls prefetchDependencies() internally const code = await bundler.bundle("/index.tsx"); ``` -------------------------------- ### Initialize IncrementalBundler Source: https://www.reactnative.run/docs/api/incremental-bundler Instantiate the IncrementalBundler with a configuration object. Ensure the `sourceExts` in the resolver include your project's file extensions. The `server.packageServerUrl` should point to your package server. ```typescript import { IncrementalBundler, VirtualFS, reactRefreshTransformer } from "browser-metro"; const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: reactRefreshTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, hmr: { enabled: true, reactRefresh: true }, plugins: [myPlugin], }; const bundler = new IncrementalBundler(vfs, config); ``` -------------------------------- ### VirtualFS Constructor Source: https://www.reactnative.run/docs/api/virtual-fs Initializes a new VirtualFS instance with an optional initial file map. ```APIDOC ## Constructor Initializes a new VirtualFS instance. ### Parameters #### Request Body - **files** (FileMap) - Optional - An object where keys are file paths and values are file contents. ``` -------------------------------- ### VirtualFS API Source: https://www.reactnative.run/docs/virtual-fs Demonstrates the core methods available on the VirtualFS class for interacting with the in-memory filesystem. ```APIDOC ## VirtualFS API ### Description Provides an in-memory filesystem that the bundler operates against, making the entire system portable and browser-compatible. ### Initialization ```javascript import { VirtualFS } from "browser-metro"; // Assuming 'files' is a FileMap object like: // const files = { "/index.tsx": "...", "/App.tsx": "..." }; const vfs = new VirtualFS(files); ``` ### Methods #### `read(path: string): string | undefined` Reads the content of a file from the virtual filesystem. #### `write(path: string, content: string): void` Writes content to a file in the virtual filesystem. Creates the file if it doesn't exist, or overwrites it if it does. #### `exists(path: string): boolean` Checks if a file exists at the given path. #### `list(): string[]` Returns an array of all file paths currently in the virtual filesystem. #### `toFileMap(): FileMap` Returns a copy of the internal `FileMap` object, representing the entire filesystem state. #### `getEntryFile(): string | undefined` Finds and returns the path to the entry file. It tries common entry file names like `/index.js`, `/index.ts`, `/index.tsx`, and `/index.jsx` in order. ``` -------------------------------- ### Batch Dependency Fetching Workflow Diagram Source: https://www.reactnative.run/docs/batch-fetching Visualizes the client-server interaction for batch dependency fetching, including cache hits and misses. ```text Client CDN (Cloudflare) ESM Server │ │ │ ├─ SHA-256 hash of deps ──────────►│ │ │ GET /bundle-deps/:hash │ │ │ ├─ cache hit? ────► return │ │ ├─ cache miss ────────────►│ 404 │ │ │ ├─ POST /bundle-deps ────────────────────────────────────────►│ │ { hash, dependencies } │ npm install all │ │ bundle each pkg │◄───────────────────────────── single JS response ───────────┤ │ │ │ │ (next request, same deps) │ │ ├─ GET /bundle-deps/:hash ────────►│ │ │◄──── instant from CDN ───────────┤ │ ``` -------------------------------- ### Transformation pipeline stages Source: https://www.reactnative.run/docs/architecture Illustrates the three-stage transformation process for source files, including pre-transform hooks, core transformation with Sucrase, and post-transform hooks. ```text Original source (.tsx/.ts/.jsx/.js) │ ▼ ┌──────────────────────┐ │ Pre-transform hooks │ BundlerPlugin.transformSource() │ (JSX still intact) │ e.g. data-bx-path injection └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Core transform │ Transformer.transform() │ (Sucrase) │ TS types stripped, JSX → createElement └──────────┬───────────┘ │ ▼ ┌──────────────────────┐ │ Post-transform hooks│ BundlerPlugin.transformOutput() │ (CommonJS output) │ e.g. React Refresh registration └──────────────────────┘ ``` -------------------------------- ### IncrementalBundler Build Method Source: https://www.reactnative.run/docs/api/incremental-bundler Details on how to perform an initial full build using the `build` method. ```APIDOC ## POST /build ### Description Performs the initial full build of the project. This method must be called before `rebuild()`. ### Method POST ### Endpoint `/build` ### Parameters #### Path Parameters None #### Query Parameters - **entryFile** (string) - Required - The entry file for the build (e.g., "/index.tsx"). #### Request Body None ### Request Example None ### Response #### Success Response (200) - **bundle** (string) - The full bundle string. - **type** (string) - The build type, "full" for the initial build. - **hmrUpdate** (null) - Always null for the initial build. #### Response Example ```json { "bundle": "// Your bundle code here...", "type": "full", "hmrUpdate": null } ``` ``` -------------------------------- ### Plugin Hooks Overview Source: https://www.reactnative.run/docs/api/plugins An overview of the available plugin hooks, their execution phase, and common use cases. ```APIDOC ## Plugin Hooks | Hook | Phase | Use Case | |---|---|---| | `transformSource` | Before Sucrase | Modify raw JSX/TS source (e.g. inject attributes) | | `transformOutput` | After Sucrase | Modify CJS output (e.g. add instrumentation) | | `resolveRequest` | Module resolution | Custom resolution logic | | `moduleAliases` | Pre-fetch | Redirect `require("A")` to package B | | `shimModules` | Pre-fetch | Replace npm packages with inline code | **Plugin ordering matters**: plugins run in array order. ``` -------------------------------- ### VirtualFS Methods Source: https://www.reactnative.run/docs/api/virtual-fs Reference for the methods available on the VirtualFS class. ```APIDOC ## Methods ### `read(path: string): string | undefined` Returns the file contents, or `undefined` if the file doesn't exist. #### Parameters #### Path Parameters - **path** (string) - Required - The path to the file to read. ### `write(path: string, content: string): void` Creates or overwrites a file. #### Parameters #### Path Parameters - **path** (string) - Required - The path to the file to write. - **content** (string) - Required - The content to write to the file. ### `exists(path: string): boolean` Checks if a file exists. #### Parameters #### Path Parameters - **path** (string) - Required - The path to the file to check. ### `list(): string[]` Returns all file paths currently in the virtual file system. ### `getEntryFile(): string | null` Returns the first matching entry file from a predefined list (`/index.js`, `/index.ts`, `/index.tsx`, `/index.jsx`). Returns `null` if none are found. ### `toFileMap(): FileMap` Returns a copy of the internal file map. ``` -------------------------------- ### Global Polyfills for Development and Environment Source: https://www.reactnative.run/docs/shims These global polyfills are prepended to every module to ensure compatibility in browser environments. They set up `__DEV__` and `process.env.NODE_ENV`. ```javascript if (typeof __DEV__ === 'undefined') globalThis.__DEV__ = true; if (typeof global === 'undefined') globalThis.global = globalThis; ``` ```javascript var process = globalThis.process || {}; process.env = process.env || {}; process.env.NODE_ENV = process.env.NODE_ENV || "development"; ``` -------------------------------- ### Cache Directory Structure Source: https://www.reactnative.run/docs/esm-server Illustrates the file structure of the cache directory, showing how bundled packages and their external JSON manifests are stored. Subpaths are indicated by double underscores. ```plaintext cache/ lodash@4.17.21.js lodash@4.17.21.externals.json react-dom@19.1.0__client.js # subpath "/" → "__" react-dom@19.1.0__client.externals.json ``` -------------------------------- ### URL Format for Package Server Source: https://www.reactnative.run/docs/esm-server Defines the URL structure for requesting packages from the ESM Package Server. Supports package name, version, and subpath. ```plaintext GET /pkg/[@][/] ``` -------------------------------- ### FileMap structure for VirtualFS Source: https://www.reactnative.run/docs/architecture Represents the in-memory file system, mapping absolute paths to their source code strings. Used for loading project files. ```json { "/index.ts": "import { greet } from './utils';\n...", "/utils.ts": "export function greet(name: string) {...}", "/package.json": "{ \"dependencies\": {} }" } ``` -------------------------------- ### Batch Dependency Response Format Source: https://www.reactnative.run/docs/batch-fetching Illustrates the structure of the concatenated JavaScript response from the batch dependency fetcher, using specific markers for individual packages. ```javascript // @dep-bundle a1b2c3d4e5f67890 // @dep-manifest {"react":"19.1.0","expo-router":"6.0.12",...} // @dep-count 18 // @dep-start react var __module = (() => { /* esbuild IIFE bundle */ })(); if (typeof __module !== "undefined") { module.exports = __module; } // @dep-end react // @dep-start react-dom ... // @dep-end react-dom // @dep-start react-dom/client ... // @dep-end react-dom/client ``` -------------------------------- ### EditorFS Overview Source: https://www.reactnative.run/docs/virtual-fs Describes the EditorFS, which extends VirtualFS with features for tracking changes and managing updates for a responsive editing experience. ```APIDOC ## EditorFS ### Description The `EditorFS` wraps `VirtualFS` and adds functionality crucial for interactive editing environments like playgrounds. ### Features - **Dirty Tracking**: Keeps track of which files have been modified since the last synchronization. - **Debounced Flushes**: Batches rapid file edits into single update messages sent to the bundler worker, improving performance. - **Worker Communication**: Sends `watch-update` messages containing `ContentChange[]` arrays to the bundler worker, informing it of file modifications. ### Purpose These features collectively ensure that the user interface remains responsive during typing, even while the bundler is processing changes in the background. ``` -------------------------------- ### IncrementalBundler Rebuild Method Source: https://www.reactnative.run/docs/api/incremental-bundler Explains how to incrementally rebuild the bundle based on file changes using `rebuild`. ```APIDOC ## POST /rebuild ### Description Incrementally rebuilds the bundle based on a list of file changes. This method can return a Hot Module Replacement (HMR) update. ### Method POST ### Endpoint `/rebuild` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **changes** (FileChange[]) - Required - An array of objects, each describing a file change (e.g., `{ path: "/App.tsx", type: "update" }`). ### Request Example ```json { "changes": [ { "path": "/App.tsx", "type": "update" } ] } ``` ### Response #### Success Response (200) - **bundle** (string) - The full bundle string (fallback). - **hmrUpdate** (HmrUpdate | null) - An object containing HMR update information, or null if no HMR update is available. - **type** (string) - The build type, "incremental" if HMR update is present. - **rebuiltModules** (string[]) - List of modules that were rebuilt. - **removedModules** (string[]) - List of modules that were removed. - **buildTime** (number) - Time taken for the rebuild in milliseconds. #### Response Example ```json { "bundle": "// Fallback bundle code...", "hmrUpdate": { "updatedModules": { "123": "// New code for module 123..." }, "removedModules": [], "requiresReload": false }, "type": "incremental", "rebuiltModules": ["123"], "removedModules": [], "buildTime": 50 } ``` ``` -------------------------------- ### BundlerConfig Interface Source: https://www.reactnative.run/docs/api/types Configuration object for the bundler, including resolver, transformer, and server settings. ```APIDOC ## BundlerConfig Interface ### Description Defines the configuration structure for the bundler, encompassing resolver settings, transformer, server details, HMR options, plugins, environment variables, and router shim. ### Interface ```typescript interface BundlerConfig { resolver: ResolverConfig; transformer: Transformer; server: { packageServerUrl: string }; hmr?: { enabled: boolean; reactRefresh?: boolean }; plugins?: BundlerPlugin[]; env?: Record; routerShim?: boolean; } ``` ``` -------------------------------- ### HMR End-to-End Flow Diagram Source: https://www.reactnative.run/docs/hmr Visual representation of the Hot Module Replacement process from editor keystroke to UI update, including intermediate steps like file watching, bundling, and runtime execution. ```text Editor (keystroke) │ ▼ EditorFS.write() │ detects change, debounces ▼ Worker receives "watch-update" message │ with ContentChange[] (path, type, content) ▼ IncrementalBundler.rebuild(changes) │ 1. Invalidate changed module caches │ 2. Re-transform only changed files │ 3. Walk any new local deps │ 4. Fetch any new npm packages │ 5. Clean up orphaned modules │ 6. Emit full bundle (for fallback) │ 7. Build HmrUpdate with per-module code ▼ Worker posts "hmr-update" to parent │ updatedModules, removedModules, bundle (fallback) ▼ App broadcasts to iframe via postMessage ▼ Iframe HMR runtime receives "hmr-update" │ 1. Find accept boundaries (walk reverse deps) │ 2. Run dispose callbacks │ 3. Replace module factories │ 4. Delete removed modules │ 5. Re-execute boundary modules │ 6. React Refresh: performReactRefresh() ▼ UI updates without page reload ``` -------------------------------- ### Basic Browser-Metro Bundling Source: https://www.reactnative.run/docs/quick-start Configure and use the Bundler from browser-metro to bundle a virtual filesystem. This is useful for in-browser bundling of React Native projects. ```typescript import { Bundler, VirtualFS, typescriptTransformer } from "browser-metro"; import type { BundlerConfig, FileMap } from "browser-metro"; // 1. Create a virtual filesystem const files: FileMap = { "/index.ts": 'import { greet } from "./utils";\nconsole.log(greet("World"));', "/utils.ts": 'export function greet(name: string) { return "Hello, " + name; }', }; const vfs = new VirtualFS(files); // 2. Configure the bundler const config: BundlerConfig = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: typescriptTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, }; // 3. Bundle const bundler = new Bundler(vfs, config); const code = await bundler.bundle("/index.ts"); // 4. Execute (e.g. in an iframe) ``` -------------------------------- ### Expo Router Split Entry Architecture Source: https://www.reactnative.run/docs/expo-router Illustrates the split entry architecture for Expo Router, separating the route context (`__expo_ctx.js`) from the main entry point (`index.tsx`). The context file is plain JavaScript to avoid React Refresh boundaries, ensuring HMR updates propagate correctly. ```javascript var modules = { "./(tabs)/...": require("..."), ... }; module.exports = ctx ``` ```typescript const ctx = require( "./__expo_ctx" ); function App() { return ; } registerRootComponent(App) ``` -------------------------------- ### FileMap Interface Source: https://www.reactnative.run/docs/api/types Maps absolute file paths to their source code. ```typescript interface FileMap { [path: string]: string; // absolute path → source code } ``` -------------------------------- ### Source Map Utilities Source: https://www.reactnative.run/docs/source-maps A set of utility functions are available for working with source maps, including encoding/decoding VLQ, manipulating mappings, merging per-module maps, and serializing them as inline data URLs. ```javascript `encodeVLQ` / `decodeVLQ` ``` ```javascript `decodeMappings` / `encodeMappings` ``` ```javascript `buildCombinedSourceMap` ``` ```javascript `inlineSourceMap` ``` ```javascript `shiftSourceMapOrigLines` ``` -------------------------------- ### Iframe Source Map API Source: https://www.reactnative.run/docs/source-maps The iframe exposes a `window.__SM` API for registering and resolving source maps. Use `__SM.init` for the initial bundle, `__SM.add` for HMR updates, and `__SM.resolve` to map runtime error positions to original file locations. ```javascript __SM.init(url, mapData) ``` ```javascript __SM.add(url, mapData) ``` ```javascript __SM.resolve(url, line, col) ``` -------------------------------- ### IncrementalBundler UpdateFS Method Source: https://www.reactnative.run/docs/api/incremental-bundler How to update the internal file system representation before rebuilding. ```APIDOC ## PUT /updateFS ### Description Replaces the internal VirtualFS used by the bundler. This should be called after modifying files and before calling `rebuild()`. ### Method PUT ### Endpoint `/updateFS` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **fs** (VirtualFS) - Required - The new VirtualFS instance to use. ### Request Example ```typescript // Assuming 'newVirtualFS' is a modified VirtualFS instance bundler.updateFS(newVirtualFS); ``` ### Response None (This is a void method) #### Success Response (200) None #### Response Example None ``` -------------------------------- ### Write File Content with VirtualFS Source: https://www.reactnative.run/docs/api/virtual-fs Create a new file or overwrite an existing one in the VirtualFS with the provided content. This operation does not return a value. ```typescript vfs.write("/newfile.js", "module.exports = 42;"); ``` -------------------------------- ### FileChange Interface Source: https://www.reactnative.run/docs/api/types Represents a change to a file, including its path and type (create, update, delete). ```typescript interface FileChange { path: string; type: "create" | "update" | "delete"; } ``` -------------------------------- ### Check File Existence with VirtualFS Source: https://www.reactnative.run/docs/api/virtual-fs Verify if a file exists within the VirtualFS. Returns true if the file is present, and false otherwise. ```typescript vfs.exists("/index.js"); // true vfs.exists("/nope"); // false ``` -------------------------------- ### BundlerConfig Interface Source: https://www.reactnative.run/docs/api/types Configuration object for the bundler, including resolver, transformer, server, and plugin settings. ```typescript interface BundlerConfig { resolver: ResolverConfig; transformer: Transformer; server: { packageServerUrl: string }; hmr?: { enabled: boolean; reactRefresh?: boolean }; plugins?: BundlerPlugin[]; env?: Record; routerShim?: boolean; } ``` -------------------------------- ### IncrementalBuildResult Type Source: https://www.reactnative.run/docs/api/types Result of an incremental build, including bundle output and HMR updates. ```APIDOC ## IncrementalBuildResult Type ### Description Contains the result of an incremental build operation, including the generated bundle, potential HMR updates, build type, rebuilt/removed modules, and build time. ### Interface ```typescript interface IncrementalBuildResult { bundle: string; hmrUpdate: HmrUpdate | null; type: "full" | "incremental"; rebuiltModules: string[]; removedModules: string[]; buildTime: number; } ``` ``` -------------------------------- ### Bundler.transformFile() Method Source: https://www.reactnative.run/docs/api/bundler Transforms a single file using the configured transformer, useful for one-off transforms outside of bundling. ```APIDOC ## Bundler.transformFile() ### Description Transforms a single file using the configured transformer (including plugin hooks). Useful for one-off transforms outside of bundling. ### Method `transformFile(filename: string, src: string): string` ### Endpoint N/A (Method of the Bundler class) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript const jsCode = bundler.transformFile("/app.tsx", tsxSource); ``` ### Response #### Success Response (200) - **jsCode** (string) - The transformed JavaScript code. #### Response Example ```javascript // Example of transformed JS code (truncated) "use strict"; var _jsxFileName = "/app.tsx"; // ... rest of the transformed JS code ... ``` -------------------------------- ### FileMap Interface Source: https://www.reactnative.run/docs/virtual-fs Defines the structure of a FileMap, which is a plain JavaScript object used to represent the project's files and their content. ```APIDOC ## FileMap ### Description A `FileMap` is the simplest possible representation of a project's files, used as the underlying data structure for `VirtualFS`. ### Interface ```typescript interface FileMap { [path: string]: string; // absolute path → source code } ``` ### Example ```javascript const files: FileMap = { "/index.tsx": "import App from \"./App\";\n...", "/App.tsx": "export default function App() { return ; }", "/package.json": "{ \"dependencies\": { \"react\": \"^19\" } }", }; ``` ### Notes - All paths must be absolute (start with `/`). - Directory structure is inferred from file paths; directories are not first-class objects. ``` -------------------------------- ### ContentChange Interface Source: https://www.reactnative.run/docs/api/types Represents a change in file content, including path, type, and optional content. ```typescript interface ContentChange { path: string; type: "create" | "update" | "delete"; content?: string; // omitted for delete } ``` -------------------------------- ### IncrementalBuildResult Interface Source: https://www.reactnative.run/docs/api/incremental-bundler Defines the structure of the result returned by `build()` and `rebuild()`. It includes the full bundle, potential HMR updates, module information, and build time. ```typescript interface IncrementalBuildResult { bundle: string; // full bundle (always available as fallback) hmrUpdate: HmrUpdate | null; // null for initial build type: "full" | "incremental"; rebuiltModules: string[]; removedModules: string[]; buildTime: number; // milliseconds } ``` -------------------------------- ### IncrementalBuildResult Interface Source: https://www.reactnative.run/docs/api/types Result of an incremental build, containing the bundle, HMR updates, and module information. ```typescript interface IncrementalBuildResult { bundle: string; hmrUpdate: HmrUpdate | null; type: "full" | "incremental"; rebuiltModules: string[]; removedModules: string[]; buildTime: number; } ``` -------------------------------- ### FileMap Type Source: https://www.reactnative.run/docs/api/types Represents a mapping from file paths to their source code content. ```APIDOC ## FileMap Type ### Description Represents a mapping where keys are absolute file paths and values are their corresponding source code strings. ### Interface ```typescript interface FileMap { [path: string]: string; // absolute path → source code } ``` ``` -------------------------------- ### ResolverConfig Interface Source: https://www.reactnative.run/docs/api/types Configuration for the module resolver, including source extensions and path mappings. ```APIDOC ## ResolverConfig Interface ### Description Configuration object for the module resolver, specifying allowed source file extensions and custom path mappings (similar to tsconfig `paths`). ### Interface ```typescript interface ResolverConfig { sourceExts: string[]; paths?: Record; // tsconfig "paths" } ``` ``` -------------------------------- ### Browser-Metro Bundling with HMR Source: https://www.reactnative.run/docs/quick-start Utilize IncrementalBundler for bundling with Hot Module Replacement (HMR) and React Refresh enabled. This allows for live updates without full reloads. ```typescript import { IncrementalBundler, VirtualFS, reactRefreshTransformer } from "browser-metro"; const config = { resolver: { sourceExts: ["ts", "tsx", "js", "jsx"] }, transformer: reactRefreshTransformer, server: { packageServerUrl: "https://esm.reactnative.run" }, hmr: { enabled: true, reactRefresh: true }, }; const bundler = new IncrementalBundler(vfs, config); const initial = await bundler.build("/index.ts"); // On file change: const result = await bundler.rebuild([ { path: "/utils.ts", type: "update" } ]); if (result.hmrUpdate && !result.hmrUpdate.requiresReload) { // Send HMR update to iframe } else { // Full reload needed } ``` -------------------------------- ### ModuleMap Type Source: https://www.reactnative.run/docs/api/types Maps module IDs to their transformed source code. ```APIDOC ## ModuleMap Type ### Description Represents a mapping from module identifiers to their transformed source code, typically used after processing. ### Interface ```typescript interface ModuleMap { [id: string]: string; // module ID → transformed source } ``` ```