wu-framework
v3.2.1
Published
Universal Microfrontends Framework - 13 frameworks, zero config, Shadow DOM isolation
Maintainers
Readme
WU Framework
Compose independently built web applications in one shell. WU loads their entries, coordinates mounting, updates and cleanup, and connects them through shared state, events and versioned services. Each application keeps its rendering framework and build toolchain.
Documentation · npm · WU CLI · Examples · Support
Documentation is available in English, Simplified Chinese, Portuguese and Spanish. This README describes 3.2.1; the changelog records release changes.
New in 3.2.0
| Capability | What to use | | --- | --- | | Explicit core composition | Optional subsystem imports and three manifest sources | | Installable applications | Signed .wuapp packages, trust, cache, restore and uninstallation | | Remote applications | Cross-origin iframes and revocable capability ports | | Candidate comparison | Shadow deployment and scoped operation interception | | Visual coordination | Transitions, focus, keep-alive and detachable windows | | Data transfer | Typed drag and drop with grants and keyboard alternatives | | Contract evolution | Version translators for services, RPC and provided objects | | Server rendering | Progressive SSR, response nonces and Trusted Types |
Use WU CLI 1.0.1 for templates targeting this release. The CLI shares WU core between the shell and apps; import optional subsystems explicitly in the shell when using that path. Standard wu-framework imports outside the CLI retain lazy subsystem loading. File manifests remain supported; inline and module-declared manifests are optional.
The remote entry includes TypeScript declarations. Same-origin app composition, remote iframe isolation, and package signature verification provide different guarantees; follow the linked contract for each feature. See upgrade steps before changing an existing workspace.
What you can build
- A product that combines React, Vue, Angular, Svelte or other applications on the same page.
- A gradual migration in which one capability changes framework while the shell and other applications remain in place.
- Dashboards, storefronts and internal tools whose applications exchange events, shared state or typed service requests.
- An Astro or Next shell that composes independently built applications, with SSR and hydration where the chosen integration supports them.
- Optional background computation through Worker services and compatible WASI guests.
WU provides application composition and lifecycle APIs. You still choose the UI frameworks, route ownership, build tools, backend and deployment host.
Direct composition and independent runtimes
mount(name, target) accepts a CSS selector or an actual HTMLElement, including elements inside another Shadow DOM. Recovery and unmount preserve that host. Each new WuCore() owns its default store, memory cache, timing entries and resource hints. Destroying it preserves peer runtimes and their inspector. Explicitly injected stores and caches remain caller-owned.
Register app lifecycles with runtime.define(...) on the appropriate instance. The global wu singleton addresses the shared host. On an independent runtime, await runtime.timelineReady() before recording changes. For persistent caching, explicitly configure a WuCache storage backend and namespace, and clear it when its owner releases it.
Independent cores also expose windowsReady(), detach(), attach(), isDetached() and windowOf(). Await windowsReady() during setup before enabling a popup or PiP button, then call detach() from its click handler. Window coordination belongs to that core; it does not require the global singleton. See the interactive workspace guide.
Install and start a project
npm install wu-frameworkThe package provides ESM, CommonJS, UMD and TypeScript declarations. The core has no runtime package dependencies. Renderer peers are optional: install the renderer dependencies that each application actually uses. The npm package declares Node >=20; application toolchains can require a newer version.
To generate an Astro shell with React and Vue applications:
npm install -g @wu-framework/cli
wu create portal --template react --shell astro
cd portal
wu add vue catalog --no-install
wu install
wu dev --no-openThe quick create command generates files without installing. wu install installs the project's declared dependencies. Native development uses one HTTP origin, normally http://127.0.0.1:3000; it can still use Node compiler helpers and shell builds.
For a production preview, stop the development server, then run:
wu build
wu serve 4100 --mode staticUse SPA mode instead when the shell owns client-side routes. See the CLI manual.
Supported frameworks and custom integrations
The package includes 13 adapter entry points:
| Framework | Import |
| --- | --- |
| React | wu-framework/adapters/react |
| Vue | wu-framework/adapters/vue |
| Angular | wu-framework/adapters/angular |
| Svelte | wu-framework/adapters/svelte |
| Preact | wu-framework/adapters/preact |
| Solid | wu-framework/adapters/solid |
| Lit | wu-framework/adapters/lit |
| Vanilla JavaScript | wu-framework/adapters/vanilla |
| Alpine | wu-framework/adapters/alpine |
| Qwik | wu-framework/adapters/qwik |
| Stencil | wu-framework/adapters/stencil |
| HTMX | wu-framework/adapters/htmx |
| Stimulus | wu-framework/adapters/stimulus |
This list is not a limit on composition. A custom integration can register its own mount, update and unmount lifecycle. Adapter options, rendering requirements and hydration support differ; consult the integration guide and adapter reference.
Astro and Next have separate shell integrations under wu-framework/integrations/astro and wu-framework/integrations/next.
Understand the three pieces
- The shell provides DOM slots, registers application URLs and grants access to shared resources.
- An application manifest identifies the published JavaScript entry and requests its capabilities.
- The application entry registers a lifecycle, directly or through a framework adapter.
The application name must match in all three places. The shell mounts the application after its slot exists.
Shell
Place a slot in the shell's HTML:
<div id="greeting-slot"></div>Run this module in the browser:
import { wu } from 'wu-framework';
await wu.init({
sandbox: 'module',
apps: [{ name: 'greeting', url: '/apps/greeting' }],
});
await wu.mount('greeting', '#greeting-slot');
// To fully remove this application and await teardown:
// await wu.unmount('greeting', { force: true });Manifest
Serve this as /apps/greeting/wu.json:
{
"name": "greeting",
"entry": "assets/greeting.js",
"styleMode": "own-only",
"wu": { "permissions": [] }
}Application entry
Build this source as the manifest's assets/greeting.js:
import { wu } from 'wu-framework';
wu.define('greeting', {
mount(container) {
const paragraph = document.createElement('p');
paragraph.textContent = 'Hello from a WU application';
container.append(paragraph);
},
unmount(container) {
container.replaceChildren();
},
});These are integration files, not a standalone build configuration. The CLI generates that configuration for supported templates. With an existing build setup, publish the manifest and compiled entry at the declared URLs and make every imported dependency browser-resolvable. WU does not transpile source JSX or TypeScript in the browser.
For a script-tag installation, the package also exposes a versioned UMD build:
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/wu-framework.umd.js"></script>Use window.wu from that build. It supplies the runtime; applications still need their own entries, manifests and renderer dependencies.
Application lifecycle and scoped access
wu.init({ apps, ...options }) initializes the host once. wu.mount, wu.update, wu.unmount, wu.hide and wu.show control applications. wu.app(name, config) creates a reusable application wrapper. wu.destroy() releases the runtime.
unmount normally releases a mount reference and can defer teardown; keepAlive preserves the mounted app in a hidden state. Use await wu.unmount(name, { force: true }) when full teardown must finish before proceeding.
An application's mount(container, context) receives context.wu, a scoped facade. Use this facade for application state, events and services. The imported singleton belongs to the trusted shell and has host authority. Keep listener cleanup functions and release external resources during unmount.
Capabilities use two declarations: the application requests a resource in its manifest and the shell grants access in its app configuration. For example:
{
"name": "counter",
"entry": "assets/counter.js",
"wu": {
"permissions": [
{ "capability": "store.read", "resource": "demo.count", "required": true }
]
}
}The corresponding shell app configuration includes:
const counterConfig = {
name: 'counter',
url: '/apps/counter',
grants: [{ capability: 'store.read', resource: 'demo.count' }],
};The shell can set wu.store.set('demo.count', 1). The mounted application reads it with context.wu.store.get('demo.count'). Effective access is the intersection of requests and grants; the facade is revoked when its app lease ends.
The six capability names are store.read, store.write, events.emit, events.subscribe, rpc.call and rpc.provide. Client capabilities do not replace server authentication or domain authorization. See security.
State, events and requests
Choose the primitive that matches the interaction:
| Need | API | Cleanup or constraint |
| --- | --- | --- |
| Read or change shared data | wu.store.get, set, update, batch | Reads are detached snapshots; notifications run in microtasks |
| Observe a state path | wu.store.on(path, callback) | Keep the returned unsubscribe function |
| Announce a fact | wu.emit, wu.on, wu.once, wu.off | Event callbacks receive an envelope; payload is event.data |
| Request an async result | wu.request, wu.handle | Timeouts, AbortSignal, version ranges and caller allow lists |
| Share an object interface | wu.provide, wu.consume | Versioned proxy; provider handle has revoke() |
| Validate a service's inputs and outputs | provideService, consumeService | Optional wu-framework/services module |
For example, in an initialized trusted shell:
const stopListening = wu.on('catalog:selected', event => {
console.log(event.data.productId);
});
wu.emit('catalog:selected', { productId: 'p-42' });
const stopLookup = wu.handle('catalog:lookup', ({ productId }) => ({
productId, available: true,
}), { version: '1.0.0', allow: ['wu-core'] });
const result = await wu.request('catalog:lookup', { productId: 'p-42' }, {
version: '^1', timeout: 3000,
});
console.log(result.available);
stopListening();
stopLookup();Inside applications, use the scoped facade and matching manifest requests/host grants. Events use events.emit/events.subscribe; RPC uses rpc.call/rpc.provide. Provider allow lists independently constrain callers. Read the communication and state references before relying on wildcard subscriptions or replacement behavior.
Validated services and TypeScript inference
Version 3.1.0 adds an optional shared service definition used by the runtime, inferred clients and CLI tooling:
import { wu } from 'wu-framework';
import { schema as s, defineService, provideService, consumeService } from 'wu-framework/services';
const calculator = defineService({
name: 'calculator',
version: '1.0.0',
methods: {
add: {
input: s.object({ left: s.number(), right: s.number() }),
output: s.object({ sum: s.number() }),
},
},
});
// Run after the shell has initialized WU.
const provider = provideService(wu, calculator, {
add({ left, right }) { return { sum: left + right }; },
}, { allow: ['wu-core'] });
const client = consumeService(wu, calculator);
const result = await client.add({ left: 2, right: 3 });
console.log(result.sum); // 5, inferred as number
provider.dispose();Inputs and outputs are checked at provider and consumer boundaries. Schemas are frozen data with a documented subset of types; they do not run arbitrary validators or grant access. Compatibility checking conservatively flags changes to existing method schemas. Output validation happens after the implementation runs and cannot undo its effects.
See service schemas, errors and options. With CLI >=0.6.0, wu contracts types generates declarations from JSON definitions and wu contracts check compares revisions using this same module.
Workers, WASM and WASI
wu-framework/worker runs bounded jobs in fresh module Workers. It supports concurrency and queue limits, deadlines, cancellation, transferable ArrayBuffers, receipts and explicit disposal.
// compute.worker.js — build as a module Worker entry.
import { exposeWorker } from 'wu-framework/worker';
exposeWorker(({ text }) => ({ characters: [...text].length }));The caller owns the service:
import { createWorkerService } from 'wu-framework/worker';
const worker = createWorkerService({
workerUrl: '/workers/compute.js', // URL of the compiled Worker
concurrency: 2,
queueLimit: 8,
timeoutMs: 3000,
maxBytes: 65536,
});
try {
const { value } = await worker.execute({ text: 'Hello WU' });
console.log(value.characters); // 8
} finally {
worker.dispose();
}Connect worker.handle to WU RPC to expose the computation across applications. wu-framework/worker/wasi adds a bounded virtual filesystem and a documented WASI Preview 1 subset for compatible compiled guests. It provides no Node runtime, real filesystem or network imports. Run guests inside a Worker when CPU loops must be interruptible.
A browser Worker is not a security boundary for arbitrary same-origin JavaScript. Consult the Worker/WASI guide for the guest ABI, supported imports, byte/memory limits and cleanup contract.
Rendering, isolation and server integration
- Shadow DOM: establishes a style boundary. DOM ownership and
styleModedetermine who creates and styles the root. module: executes application modules in the host window.strictandeval: use same-origin iframe mechanisms for coexistence and cleanup; they are not containment for hostile code.- SSR:
wu-framework/serverand server adapters provide rendering helpers. Client hydration depends on the renderer/integration, not just on server markup existing. - Astro: import
WuApp.astro,WuAppSSR.astroorWuShell.astrofromwu-framework/integrations/astro/…; perform browser mounting in a processed<script>, not server frontmatter. - Next: the integration exports
WuApp,WuAppSSR,WuMountandWuShellunderwu-framework/integrations/next/…. - Routing: the shell owns page navigation. WU coordinates application lifecycles;
metadata.routesis descriptive metadata.
See sandbox and style behavior, SSR and routing. Preserve framework-specific requirements instead of assuming every adapter has identical hydration or isolation behavior.
Debugging, testing and optional extensions
| Area | Entry points |
| --- | --- |
| Inspect an application | wu.getAppInfo, wu.getSandboxInfo, wu.getManifestDiagnostics |
| Inspect runtime activity | wu.inspect, wu.getStats, wu.showInspector, wu.hideInspector |
| Explain an RPC/contract failure | wu.explainRequest({ appName, channel, version, kind }) |
| Prepare data for a support issue | wu.supportReport() — report-local aliases, counts and no store payloads |
| Loading and overrides | Prefetch, loading strategies, URL overrides and error boundaries |
| Extend lifecycle behavior | wu.hooks and wu.pluginSystem |
| Optional state timeline | await wu.timelineReady() before recording |
| Optional AI integrations | await wu.aiReady(); explicit providers, actions and permissions |
| MCP integration | Bundled wu-mcp-server command and wu-framework/mcp-server subpath |
| Lifecycle conformance | runLifecycleConformance from wu-framework/testing |
explainRequest does not invoke a handler or issue authority. supportReport() returns data locally and sends nothing. The conformance kit runs visible assertions and resource counters supplied by your fixture; it is not automatic whole-browser leak detection. Timeline replay does not reverse network calls or other external effects.
The AI/MCP subsystem is optional. Exposing an action does not authorize backend operations, and API keys should not be embedded in public client bundles. See extensions, MCP setup and security and quality tools.
Documentation map
| Guide | Covers | | --- | --- | | Overview | Runtime architecture and responsibilities | | Configuration | Host configuration, manifests and validation | | Lifecycle | Mount, update, teardown and keep-alive | | Loading | Entries, strategies, prefetch and overrides | | Communication | Events, RPC and object contracts | | Services | Schemas, inferred clients, errors and compatibility | | State | Paths, snapshots, batching and synchronization | | Integrations | Framework adapters and shell composition | | Sandbox | JavaScript modes, DOM ownership and styles | | SSR | Server rendering and hydration | | Security | Capability grants and trust boundaries | | Routing | Shell navigation and application ownership | | Extensions | Hooks, plugins, timeline, AI and MCP | | Worker/WASI | Background execution and portable guests | | Quality | Conformance, explanations and support reports | | Troubleshooting | Failed loads, mounts and diagnostics | | Public API | Methods, exports, types and compatibility notes |
Develop and verify the framework
Install both dependency trees before building from source:
npm ci --include=dev
npm ci --include=dev --prefix mcp-server
npm run build
npm run lint
npm test
npm run test:mcp
npm run test:packagebuild creates all distribution formats and the MCP executable. Rollup is a development dependency; publishing from an uninstalled checkout will fail. The MCP bundle also needs the mcp-server dependency tree. Package tests install the produced tarball and verify ESM, CommonJS, SSR, integrations, adapter imports and TypeScript.
For browser execution checks, install Playwright Chromium with npx playwright install chromium, then run npm run test:worker:browser. On machines with Edge, WU_BROWSER_CHANNEL=msedge selects that browser. See package.json for the current test scripts.
Team, support and license
Report a bug or suggest an improvement · Support independent development
Include package versions, a minimal reproduction, expected behavior and actual behavior in an issue. Review diagnostics before sharing them. WU Framework is MIT licensed.
