npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

mfe-runtime-z

v1.2.1

Published

Framework-agnostic micro-frontend runtime (host, event bus, shared state, router sync)

Downloads

333

Readme


NPM JavaScript Style Guide Downloads


Description

mfe-runtime-z is a lightweight, framework-agnostic micro-frontend runtime.

It provides the minimal building blocks needed to run multiple independent frontend applications (micro-frontends) together at runtime, without coupling them through framework internals or build-time federation.

This library focuses on application-level integration, not component sharing.

What it solves

  • Load and mount remote applications dynamically
  • Isolate application lifecycles (mount/unmount/reload) ✅ via Shadow DOM
  • Share state safely between apps
  • Synchronize routing without sharing router instances
  • Communicate via a central event bus
  • Work with any framework (React, Vue, Svelte, Vanilla JS...)

Installation

npm install mfe-runtime-z
# or
yarn add mfe-runtime-z

Core Concepts

Host-driven architecture
  • Each micro-frontend is an independent app
  • The host coordinates loading, routing, and shared services
  • No direct imports between micro-frontends
Runtime contract

Micro-frontends expose a simple runtime contract:

window.myRemoteApp = { mount(el, ctx), unmount(el) }
  • No framework or bundler assumptions.
  • Compatible with React, Vue, Vanilla JS

Usage

Host application
import { MFEHost, createSharedStore } from "mfe-runtime-z"

// shared store example
const authStore = createSharedStore({ user: { name: 'name' } })

// create host with isolate: true for Shadow DOM + error isolation
const host = new MFEHost({
  stores: { auth: authStore },
  navigate: (path) => history.pushState({}, "", path),
  isolate: false, // => shadow
  onRemoteError: (err) => console.error("Remote error:", err)
})

async function init() {
  // load remote apps
  const productRemote = await host.load("http://localhost:3001/remote.js", "productApp")
  const cartRemote = await host.load("http://localhost:3002/remote.js", "cartApp")

  // mount remotes into host container divs
  host.mount(productRemote, document.getElementById("product-root")!, "productApp", { isolate: false }) // shadow
  host.mount(cartRemote, document.getElementById("cart-root")!, "cartApp")

  // // Unmount Shadow DOM remote
  // host.unmount(productRemote, document.getElementById("product-root")!, "productApp")
  // // Unmount normal remote
  // host.unmount(cartRemote, document.getElementById("cart-root")!, "cartApp")
}

init()
Remote application (framework-agnostic)
export function mount(el: ShadowRoot) {
  let count = 0
  const div = document.createElement("div")
  const btn = document.createElement("button")
  const p = document.createElement("p")
  btn.textContent = "Add Item"
  p.textContent = count.toString()
  btn.onclick = () => (p.textContent = (++count).toString())
  div.appendChild(btn)
  div.appendChild(p)
  el.appendChild(div)
}

export function unmount(el: ShadowRoot) {
  el.innerHTML = ""
}

;(window as any).cartApp = { mount, unmount }
Remote application (framework-react-library)
import React from "react"
import ReactDOM from "react-dom/client"
import { createSharedStore } from "mfe-runtime-z"

export const authStore = createSharedStore<{ user: { id: string; name: string } | null }>({
  user: null,
})

export default function App() {
  const [user, setUser] = React.useState(authStore.getState().user)

  React.useEffect(() => {
    const unsubscribe = authStore.subscribe((state) => setUser(state.user))
    return () => unsubscribe()
  }, [])

  const handleLogin = () => {
    authStore.setState({ user: { id: "1", name: "Alice" } })
  }

  const handleLogout = () => {
    authStore.setState({ user: null })
  }

  return (
    <div>
      {user ? (
        <>
          <span>Hello {user.name}</span>
          <button onClick={handleLogout}>Logout</button>
        </>
      ) : (
        <button onClick={handleLogin}>Login</button>
      )}
    </div>
  )
}

// mount function
export function mount(el: HTMLElement, ctx: any) {
  const root = ReactDOM.createRoot(el)
  ;(el as any)._reactRoot = root
  // @ts-ignore
  root.render(<App />) // <- ctx.stores.auth
}

// unmount function
export function unmount(el: HTMLElement) {
  const root = (el as any)._reactRoot
  root?.unmount()
  el.innerHTML = ""
}

// expose to window
;(window as any).productApp = { mount, unmount }

Shared State

import { createSharedStore } from "mfe-runtime-z"

export const store = createSharedStore({
  auth: { user: null }
})

// Subscribe
store.subscribe((state) => console.log("New state:", state))

// Update
store.setState({ auth: { user: { id: 1, name: "Alice" } } })
  • Push-based, no Redux, no shared framework state

Router Synchronization

import { createSharedRouter } from "mfe-runtime-z"

// Remote app context
const router = createSharedRouter({ eventBus, name: "productApp" })

router.go("/cart")
router.onChange((path) => console.log("navigated to", path))

// Listen route changes from host or other remotes
router.onRouteChange((path) => {
  console.log("Remote route changed:", path)
})

// Notify other remotes of route change
router.emitRouteChange("/checkout")
  • Intent-based navigation
  • Host owns the URL
  • No shared router instances

How remote applications are built

Remote applications only need to build a single JavaScript file. No Module Federation required.

  • What a remote must provide
  • Build a browser-loadable file (e.g. remote.js)
  • Expose itself on window
  • Implement mount / unmount
  • Minimal remote build (Vite)
// vite.config.ts
export default {
  build: {
    lib: {
      entry: "src/index.ts",
      name: "productApp",
      formats: ["umd"],
      fileName: () => "remote.js",
    },
  },
}

// src/index.ts
import { mount, unmount } from "./app"

// see above
;(window as any).productApp = { mount, unmount }

👉 Copy-paste ✅: minimal remote build, browser-loadable, no Module Federation.


Dev HMR section

Host dev reload
import { MFEHost } from "mfe-runtime-z"
import { createMFEReloadServer } from "mfe-runtime-z/dev"

// Initialize the MFE host runtime
const host = new MFEHost()

// Create a dev reload server to automatically reload remote apps on changes
const startDevReload = createMFEReloadServer(host, {
  productApp: {
    url: "http://localhost:3001/remote.js", // URL of the remote JS file
    global: "productApp",                   // Name of the global mount/unmount object exposed by remote
    el: () => document.getElementById("product-root")!, // DOM container to mount the remote
  },
})

// Only start the dev reload server in development mode
if (process.env.NODE_ENV === "development") {
  startDevReload()
}
Remote dev notify.
// Only run in development
if (import.meta.env.DEV) {
  // Connect to the host's WebSocket dev reload server
  const ws = new WebSocket("ws://localhost:3000/__mfe_reload")

  // Accept HMR updates from Vite
  import.meta.hot?.accept(() => {
    // Notify the host that this remote app has changed and should be reloaded
    ws.send(JSON.stringify({ type: "RELOAD", name: "productApp" }))
  })
}

Plugin API Summary

| Method | Description | | ------------------------------------------------- | ---------------------------------------------------------------------------------------- | | MFEHost.load(url, global) | Load a remote JS bundle from URL. | | MFEHost.mount(remote, el, name, options?) | Mount remote app into a container element, optionally in shadow DOM. | | MFEHost.unmount(remote, el) | Unmount a remote app. | | MFEHost.reloadRemote({ name, url, global, el }) | Reload a remote app (unmount + reload script + mount). | | MFEHost.getEventBus() | Access central event bus for custom events. | | createSharedStore(initial) | Create a shared state store with getState(), setState(), subscribe(). | | createSharedRouter({ eventBus, name }) | Router helper: go(path), onChange(cb), emitRouteChange(path), onRouteChange(cb). |


Features

  • Framework-agnostic micro-frontend runtime
  • Dynamic remote loading
  • Safe lifecycle management
  • Central event bus
  • Shared state with subscriptions
  • Router synchronization
  • Hot reload support for remote apps
  • Shadow DOM + error isolation (optional via isolate: true)
  • No build-time federation required

What this library is NOT

  • ❌ Not a UI component library
  • ❌ Not a replacement for React/Vue routers
  • ❌ Not a build-time module federation tool

Micro-Frontend Runtime Comparison

| Feature / Lib | mfe-runtime-z | Module Federation (Webpack 5) | single-spa | qiankun | | ----------------------------------- | -------------------| ------------------------------- | ---------------- | ---------------- | | Framework-agnostic | ✅ Yes | ❌ Mostly Webpack/JS | ✅ Yes | ✅ Yes | | Runtime loading | ✅ Yes | ❌ Build-time federation only | ✅ Yes | ✅ Yes | | Shadow DOM support | ✅ Optional | ❌ Not built-in | ❌ Not built-in | ✅ Partial | | Shared state / EventBus | ✅ Yes | ❌ Requires external | ✅ Yes | ✅ Yes | | Dynamic mount/unmount | ✅ Yes | ❌ Build-time | ✅ Yes | ✅ Yes | | Dev HMR support | ✅ Yes | ❌ Limited | ⚠️ Needs plugin | ⚠️ Needs plugin | | Bundle size | 🟢 Lightweight | ⚠️ Depends on Webpack setup | 🟡 Medium | 🟡 Medium | | Learning curve | 🟢 Simple | ⚠️ Medium | ⚠️ Medium | ⚠️ Medium | | Build-time federation required? | ❌ No | ✅ Yes | ❌ No | ❌ No |


Flowchart

                ┌────────────────────┐
                │       Host         │
                │--------------------│
                │  - stores          │
                │  - eventBus        │
                │  - navigate()      │
                └────────────────────┘
                          ▲
                          │
            ┌─────────────┴─────────────┐
            │                           │
  ROUTER / EVENTS                    SHARED STORE
            │                           │
            ▼                           ▼
 ┌────────────────────┐         ┌────────────────────┐
 │    Remote App A    │         │    Remote App B    │
 │--------------------│         │--------------------│
 │  - mount(container)│         │  - mount(container)│
 │  - unmount()       │         │  - unmount()       │
 │  - emit events     │         │  - emit events     │
 │  - go(path)        │         │  - go(path)        │
 │  - onChange(cb)    │         │  - onChange(cb)    │
 │  - onRouteChange() │         │  - onRouteChange() │
 │  - use shared store│         │  - use shared store│
 └────────────────────┘         └────────────────────┘

License

MIT