A microfrontend toolkit: load, mount and connect independently deployed apps written in React, Vue, Svelte, Angular or plain TypeScript, in the browser or as server-rendered islands inside a React page.
🇬🇧 English · 🇹🇷 Türkçe · 🇪🇸 Español · 🇩🇪 Deutsch · 🇫🇷 Français · 🇯🇵 日本語 · 🇨🇳 中文 · 🇮🇹 Italiano · 🇧🇷 Português · 🇮🇳 हिंदी
- 🧩 Framework adapters for React 18/19, Vue 3, Svelte 3-5 and Angular 15+. Each turns a root component into a micro app module with
mount,updateandunmount, one instance per container. - 🛣️ Path-based activation.
activeWhen: '/users/:id'mounts an app on matching paths. Query strings and hashes never unmount it. One matcher (matchPath) serves the orchestrator, the router and the server package. - 🔁 Ordered mounting. Route changes reconcile one at a time; inactive apps unmount before new ones mount, so quick A → B → A navigation leaves only A on the page.
- 🔗 External routers.
orchestrator.connectRouter()follows TanStack Router or React Router.interceptLinks()turns plain<a href>clicks into client navigations. - 🏝️ SSR islands.
TuvixIslandhosts Vue, Svelte, Angular and React micro apps in a server-rendered React page, hydrates them in place, and never rewrites their DOM on re-render. - 🎨 Styled first paint.
@tuvix.js/vitetells your server which stylesheets each island needs, so you link them in<head>. - 📦 Flexible entries. Script URLs,
{ scripts, styles, type }, or loader functions such as() => import('./app'). Parallel loads, retries, timeouts, SRI hashes. - 📡 Shared event bus.
getGlobalBus()returns one bus per page, even across separately bundled apps. - 🔔 Lifecycle events.
tuvix:mounted,tuvix:unmounted,tuvix:error, pluswhenMounted(name)andonLifecycle(). - 🔒 CSS isolation on request.
sandbox: truerenders an app inside a shadow root with its own stylesheets. - 🟦 TypeScript. Every library package ships ESM and CommonJS builds with type declarations.
Tuvix.js does not isolate JavaScript between apps: every app runs in the page's window. Use an <iframe> for untrusted code.
Generate tuvix.js components from natural language with the chatbot on the documentation site.
- Chat model: MiniMax M2.5 via OpenRouter
- Embed model: NVIDIA Nemotron Embed 1B via OpenRouter (RAG retrieval)
- Supports: React, Vue, Svelte, Angular
- Dataset: tuvix-component-dataset on HuggingFace
Try it: AI Generator on the documentation site
# Orchestrator, router, loader, event bus and sandbox
pnpm add tuvix.js
# Adapters, as needed
pnpm add @tuvix.js/react @tuvix.js/vue @tuvix.js/svelte @tuvix.js/angular
# Or scaffold a project
npx create-tuvix-app my-app --template shellimport { createOrchestrator, interceptLinks } from 'tuvix.js';
const orchestrator = createOrchestrator({
router: { mode: 'history', routes: [] },
});
orchestrator.register({
name: 'dashboard',
entry: {
scripts: ['https://cdn.example.com/dashboard/main.js'],
styles: ['https://cdn.example.com/dashboard/main.css'],
type: 'module',
},
container: '#main-content',
activeWhen: '/dashboard/*',
props: { user: 'Guest' },
fallback: '<p>Dashboard is unavailable.</p>',
});
orchestrator.register({
name: 'settings',
entry: () => import('./apps/settings'),
container: '#main-content',
activeWhen: '/settings/*',
});
interceptLinks({ navigate: (path) => orchestrator.navigateTo(path) });
await orchestrator.start();import { createReactMicroApp } from '@tuvix.js/react';
function Dashboard({ user }: { user: string }) {
return <h1>Welcome, {user}</h1>;
}
// Registers itself as "dashboard", so the shell's script entry finds it.
export default createReactMicroApp({ name: 'dashboard', App: Dashboard });Without a framework:
import { defineMicroApp } from 'tuvix.js';
export default defineMicroApp({
name: 'settings',
mount({ container, props }) {
const title = document.createElement('h1');
title.textContent = `Settings for ${String(props?.user ?? 'Guest')}`;
container.replaceChildren(title);
},
unmount({ container }) {
container.replaceChildren();
},
});import { createOrchestrator } from 'tuvix.js';
const orchestrator = createOrchestrator();
await orchestrator.updateAppProps('dashboard', { user: 'Yasin' });A mounted app with update re-renders in place. Otherwise the orchestrator keeps the merged props for the next mount.
import { createOrchestrator } from 'tuvix.js';
import { router } from './router'; // TanStack Router instance
const orchestrator = createOrchestrator(); // no built-in router
orchestrator.connectRouter({
subscribe: (callback) => router.subscribe('onResolved', callback),
getPath: () => router.state.location.pathname,
});
await orchestrator.start();import { TuvixIsland } from '@tuvix.js/react';
import { createSsrSvelteMicroApp } from '@tuvix.js/svelte';
import Footer from './Footer.svelte';
const footer = createSsrSvelteMicroApp({ name: 'footer', App: Footer });
// `footerHtml` comes from renderSvelteToString() in server-only code.
export function Layout({ footerHtml }: { footerHtml?: string }) {
return <TuvixIsland name="footer" app={footer} props={{ year: 2026 }} ssrHtml={footerHtml} fallback={<footer>© 2026</footer>} />;
}During hydration the island reads its HTML from the page, so the client never needs footerHtml. See the SSR Islands guide and examples/with-ssr-islands.
import { onLifecycle, whenMounted } from 'tuvix.js';
onLifecycle('error', ({ name, error }) => console.error(name, error));
const { container, hydrated } = await whenMounted('footer');
container.classList.add(hydrated ? 'hydrated' : 'rendered');import { getGlobalBus } from 'tuvix.js';
const bus = getGlobalBus(); // the same bus the orchestrator passes to mount()
const off = bus.on<{ userId: string }>('user:login', ({ userId }) => console.log(userId));
bus.emit('user:login', { userId: '42' });
off();| Package | Description |
|---|---|
tuvix.js |
Umbrella: core, router, loader, event bus, sandbox |
@tuvix.js/core |
Orchestrator: registration, reconcile, props, connectRouter |
@tuvix.js/router |
History/hash router, matchPath, interceptLinks |
@tuvix.js/loader |
Entry loading and the lifecycle runtime |
@tuvix.js/event-bus |
Pub/sub bus, page-wide getGlobalBus() |
@tuvix.js/sandbox |
CssSandbox (shadow DOM), JsSandbox (proxy window) |
@tuvix.js/react |
React adapter, TuvixReactApp, TuvixIsland, hooks |
@tuvix.js/vue |
Vue 3 adapter, renderVueToString |
@tuvix.js/svelte |
Svelte 3-5 adapter, renderSvelteToString |
@tuvix.js/angular |
Angular 15+ adapter (zoneless), renderAngularToString |
@tuvix.js/vite |
Vite plugin: island stylesheet links for the server-rendered <head> |
@tuvix.js/server |
Server-side composition of HTML fragments, streaming, metrics |
@tuvix.js/module-federation |
Entries backed by webpack Module Federation remotes |
@tuvix.js/devtools |
In-page debug panel |
create-tuvix-app |
Project scaffolding |
tuvix.js/
├── packages/ # the 15 packages above
├── examples/ # runnable examples, see below
├── website/ # documentation site (VitePress, 10 languages)
├── scripts/ # docs and package validators
└── .changeset/ # release notes for the next version
| Example | Shows |
|---|---|
with-ssr-islands |
React host with server-rendered Vue, Svelte, Angular and React islands |
with-react |
React shell and micro apps |
with-vue |
Vue 3 micro apps |
with-svelte |
Svelte micro apps |
with-angular |
Angular micro apps |
with-vanilla |
No framework |
with-multiple-frameworks |
React and Vue in one shell |
with-react-router |
Routing |
with-react-event-bus |
Event bus |
with-react-sandbox |
CSS sandbox |
with-react-devtools |
Devtools panel |
with-module-federation-react |
Module Federation |
with-ssr-react |
Server composition with @tuvix.js/server |
with-ssr-vanilla |
Server composition without a framework |
Shipped:
- Orchestrator with serialized reconciles,
connectRouter, viewport mounting and fallback HTML - Adapters for React, Vue, Svelte 3-5 and Angular (zoneless), with SSR hydration
TuvixIsland, lifecycle events,@tuvix.js/viteisland assets- Server composition with streaming and Prometheus metrics (
@tuvix.js/server) - Module Federation entries, in-page devtools, CLI scaffolding
- Documentation in 10 languages
Planned:
- Hot module reload across micro apps
- Native ESM / import map support
- Edge-aware server composition with stale-while-revalidate fragment caching
- Testing utilities and a mock orchestrator
- Fragment A/B testing
Read the Contributing Guide before you open a pull request.
git clone https://github.com/yasinatesim/tuvix.js.git
cd tuvix.js
pnpm install
pnpm build
pnpm testComing from 0.4? Read the migration guide.
Copyright © 2026 - MIT License. See LICENSE for more information.
This README was generated by markdown-manager 🥲