Skip to content

Architecture Diagrams

Every diagram uses the same running example: the browser is at https://fastflights.com/search, the application namespace is @fastflights, deployed slices live at https://assets.fastflights.com, and the active slice is named search.

The terminology stays deliberately consistent throughout:

  • URL path: /search
  • resolved module specifier: @fastflights/search/index.mjs
  • resolved module URL: https://assets.fastflights.com/search/index.mjs
  • runtime module: the evaluated module whose default export is mounted

The toolkit is held together by five mechanisms. They contribute different things — configuration, browser resolution, deployable ESM, runtime orchestration, and framework lifecycle integration — but they all converge in one browser document.

Five RMC Toolkit mechanisms converging in the browser Manifest, import-map, build, runtime composition, and framework bridge mechanisms feed specific layers of a browser that renders one composed FastFlights application. MANIFEST CONTRACT defineManifest({ ... }) IMPORT-MAP CONTRACT key → remote source Browser-native resolution BUILD CONTRACT dist/search/index.mjs ESM output + external imports RUNTIME COMPOSITION resolveAndMount("/search") Route → import → lifecycle FRAMEWORK BRIDGE createReactAdapter(React) Host lifecycle integration fastflights.com/search DOCUMENT / HEAD <script type="importmap"> stable keys → remote module URLs NATIVE MODULE GRAPH import(match.specifier) fetch + evaluate ESM RUNTIME MOUNT BOUNDARY runtimeModule.mount(target, context) loading · ready · error · cleanup One composed FastFlights application Host shell + mounted Search slice

2. Manifest contract: derive the same module identity everywhere

Section titled “2. Manifest contract: derive the same module identity everywhere”

defineManifest() is executable configuration shared by import-map generation, route resolution, and build externalization. Its value is not merely that fields live together; the same values derive the same module identity at every boundary.

Involves: @rmc-toolkit/core (defineManifest, validateManifest)

Manifest values derive matching module identifiers and URLs The namespace, slice name, entry file, and assets origin derive the resolved module specifier, remote module URL, and build artifact for the search slice. MANIFEST INPUT defineManifest({ namespace: "@fastflights", assetsOrigin: "https://assets.fastflights.com", entryFile: "index.mjs" }) sliceName = "search" same values, three derived contracts ROUTE / IMPORT IDENTITY namespace + sliceName + entryFile @fastflights/search/ index.mjs REMOTE MODULE URL assetsOrigin + sliceName + entryFile https://assets.fastflights.com/ search/index.mjs SLICE BUILD ARTIFACT dist + sliceName + entryFile dist/search/index.mjs PROTECTED INVARIANT The specifier, deployed URL, and build path agree Changing a shared manifest value updates every derived contract

3. Import-map contract: module specifier to module URL

Section titled “3. Import-map contract: module specifier to module URL”

The browser receives an import map before any dependent module executes. Application modules use a prefix mapping; external dependencies use exact, version-pinned mappings.

Involves: @rmc-toolkit/core (createImportMap, resolveImportMapSpecifier), @rmc-toolkit/vite (runtimeComposition, includeRuntimeImportMap)

Import-map prefix and exact-key resolution The application prefix @fastflights maps to the asset origin and resolves the search module specifier, while the exact dependency key @esm.sh/react maps to a pinned esm.sh URL. BROWSER DOCUMENT / <HEAD> <script type="importmap"> { "imports": { "@fastflights/": "https://assets.fastflights.com/", ... } } APPLICATION PREFIX MAPPING import("@fastflights/search/index.mjs") module specifier passed unchanged to import() "@fastflights/" + remainder: "search/index.mjs" https://assets.fastflights.com/search/index.mjs EXACT DEPENDENCY MAPPING import React from "@esm.sh/react" stable dependency specifier "@esm.sh/react" exact key — version stays out of application code https://esm.sh/[email protected] BROWSER MODULE GRAPH One resolved Search module · one resolved React module

4. Build contract: emit the path and preserve browser-owned imports

Section titled “4. Build contract: emit the path and preserve browser-owned imports”

The slice build has two responsibilities: produce the ESM artifact at the path the runtime contract expects, and leave manifest-owned specifiers untouched for the browser to resolve.

Involves: @rmc-toolkit/vite (defineSliceBuild, createRollupExternal)

Slice build output and dependency externalization defineSliceBuild emits dist/search/index.mjs, while createRollupExternal preserves the @esm.sh/react import in that artifact for the browser import map. ARTIFACT PATH defineSliceBuild({ sliceName: "search" }) Vite library build · ESM format outDir: "dist/search" fileName: () => "index.mjs" → dist/search/index.mjs DEPENDENCY EXTERNALIZATION import React from "@esm.sh/react" source import encountered by Rollup createRollupExternal(manifest) ("@esm.sh/react") → true → import stays in the emitted ESM DEPLOYED SLICE ESM https://assets.fastflights.com/search/index.mjs contains import React from "@esm.sh/react" BROWSER-IMPORTABLE MODULE Matching asset path · shared React resolved once

5. Runtime composition: URL path to mounted runtime module

Section titled “5. Runtime composition: URL path to mounted runtime module”

createRuntimeHost() owns this entire lifecycle. The expanded flow below keeps each value named consistently: the route resolver returns a module specifier, import() passes that same specifier to the browser, and the browser resolves it to a module URL.

Involves: @rmc-toolkit/core (resolveRoute, createRuntimeHost, importModule, unwrapDefault)

Explicit runtime flow from URL path to mounted module The URL path search is resolved to the module specifier @fastflights/search/index.mjs. Dynamic import passes that specifier to the browser, which resolves it through the import map to the asset URL, fetches and evaluates it, unwraps the runtime module, and mounts it into the target. URL PATH"/search" ROUTE RESOLUTIONconst match = resolveRoute(manifest, "/search")Returns a RuntimeRouteMatch — not a URL RESOLVED MODULE SPECIFIERmatch.specifier = "@fastflights/search/index.mjs"This exact string is passed unchanged to import() DYNAMIC IMPORTconst moduleNamespace = await import(match.specifier) BROWSER IMPORT-MAP RESOLUTION"@fastflights/" → "https://assets.fastflights.com/"+ remainder: "search/index.mjs" RESOLVED MODULE URLhttps://assets.fastflights.com/search/index.mjsBrowser fetches and evaluates this ESM resource RUNTIME MODULEconst runtimeModule = moduleNamespace.default MOUNTawait runtimeModule.mount(target, { route: match, manifest })

The public API intentionally collapses that expanded implementation into one operation:

const host = createRuntimeHost({ manifest, target });
await host.resolveAndMount("/search");

It also prevents a stale import from winning after a later navigation, reports loading / ready / error, and calls the mounted module’s cleanup before replacing it.

6. Framework bridge: connect runtime state to host UI

Section titled “6. Framework bridge: connect runtime state to host UI”

The framework adapters do not change module resolution. They connect createRuntimeHost() to a host framework’s lifecycle and reactive state. RMC Toolkit supports two distinct React integration models; they should not be conflated.

Involves: @rmc-toolkit/react (createReactAdapter, createDynamicModuleBoundary), @rmc-toolkit/vue (createVueAdapter)

Framework bridge integration models The DOM lifecycle adapters connect a framework host to a target element and mount-unmount runtime modules. The React DynamicModuleBoundary instead renders a default-exported React component directly inside the host React tree. DOM LIFECYCLE MODEL const { useRuntimeHost } = createReactAdapter(React)Vue uses createVueAdapter(Vue) with the same runtime host const { ref, status } = useRuntimeHost(path, { manifest })<main ref={ref} />status: idle · loading · ready · error RUNTIME MODULE CONTRACTmount(target, context) · unmount()Host controls the target and observes lifecycle state REACT COMPONENT MODEL const { DynamicModuleBoundary } = createDynamicModuleBoundary(React)Factory closes over the host's existing React instance <DynamicModuleBoundary specifier={match.specifier} context={{ route: match, manifest }} />React.lazy + Suspense + error boundary COMPONENT EXPORT CONTRACTexport default function SearchSlice()Rendered directly inside the host React tree SHARED ARCHITECTURAL OUTCOMEOne browser document · one shared module graphA host-controlled composition boundary with explicit lifecycle

The mechanisms disappear into the final product. The browser owns native module resolution and one JavaScript module graph; the host owns the document and composition boundary; the resolved slice contributes the active feature experience.

Final browser-rendered FastFlights application The browser document contains an import map, host shell, shared module graph, runtime mount boundary, and rendered Search slice, producing one coherent FastFlights application. https://fastflights.com/search FastFlights HOST SHELL · ROUTER · PROVIDERS BROWSER MODULE RESOLUTION @fastflights/search/index.mjs → https://assets.fastflights.com/search/index.mjs SHARED MODULE GRAPH @esm.sh/react → https://esm.sh/[email protected] RUNTIME MOUNT TARGET Search flights FromToronto · YYZ ToVancouver · YVR Search flights

The user sees one application. The architecture remains independently buildable and deployable because the contracts between its parts are explicit: manifest values, module specifiers, import-map entries, ESM output paths, runtime lifecycle, and framework integration.

Written by Angelo Vagenas