Skip to content

yasinatesim/tuvix.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

199 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tuvix.js Logo

Tuvix.js

A lightweight and flexible microfrontend framework for building scalable, independently deployable frontend applications.
Tuvix.js merges multiple frontend applications into a seamless, unified user experience - just like its name suggests.

🇬🇧 English · 🇹🇷 Türkçe · 🇪🇸 Español · 🇩🇪 Deutsch · 🇫🇷 Français · 🇯🇵 日本語 · 🇨🇳 中文 · 🇮🇹 Italiano · 🇧🇷 Português · 🇮🇳 हिंदी


✨ Features

  • 🧩 Framework Agnostic - Use React, Vue, Svelte, Angular or Vanilla JS
  • 📦 Independent Deployment - Deploy each micro app separately
  • 🔗 Dynamic Module Loading - Load micro frontends on demand
  • 🛣️ Built-in Routing - Seamless routing across micro apps
  • 📡 Inter-App Communication - Event bus for cross-app messaging
  • Lightweight - Zero runtime dependencies, minimal core
  • 🔄 Lifecycle Management - Mount, unmount, update hooks
  • 🔒 Type-Safe - Full TypeScript support with strict types

🤖 AI Component Generator

Generate tuvix.js components from natural language using our built-in AI chatbot.

  • Chat model: MiniMax M2.5 via OpenRouter (free API, no self-hosting required)
  • 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


📦 Installation

# All-in-one package
npm install tuvix.js

# Or install individual packages
npm install @tuvix.js/core @tuvix.js/router

🚀 Quick Start

Host (Shell) Application

import { createOrchestrator } from 'tuvix.js';

const orchestrator = createOrchestrator({
  router: {
    mode: 'history',
    routes: [
      { path: '/dashboard/*', app: 'dashboard' },
      { path: '/settings/*', app: 'settings' },
    ],
  },
});

orchestrator.register({
  name: 'dashboard',
  entry: 'https://cdn.example.com/dashboard/main.js',
  container: '#main-content',
  activeWhen: '/dashboard/*',
});

orchestrator.register({
  name: 'settings',
  entry: 'https://cdn.example.com/settings/main.js',
  container: '#main-content',
  activeWhen: '/settings/*',
});

orchestrator.start();

Micro Frontend App

import { defineMicroApp } from 'tuvix.js';

let titleEl: HTMLHeadingElement | null = null;

export default defineMicroApp({
  name: 'dashboard',

  bootstrap() {
    // One-time setup before first mount (e.g. preload data)
    console.log('Dashboard bootstrapped');
  },

  mount({ container, props }) {
    container.innerHTML = `<h1>Welcome, ${props?.user ?? 'Guest'}!</h1>`;
    titleEl = container.querySelector('h1');
  },

  unmount({ container }) {
    titleEl = null;
    container.innerHTML = '';
  },

  // Triggered when the shell calls orchestrator.updateAppProps(name, props).
  // Patch the live DOM in place — no remount, no flash.
  update({ props }) {
    if (titleEl) {
      titleEl.textContent = `Welcome, ${props?.user ?? 'Guest'}!`;
    }
  },
});

🔄 Updating Props at Runtime

Pass new props to a mounted micro app without remounting:

// Push updated props from the shell — invokes the micro app's update() hook
await orchestrator.updateAppProps('dashboard', {
  user: 'Yasin',
  theme: 'dark',
});

Props are merged with the original config props. If the app does not implement update(), the new props are stored and applied on the next mount.


🧭 Lifecycle Control (Manual)

// Manually mount / unmount apps outside of route reconciliation
await orchestrator.mountApp('dashboard');
await orchestrator.unmountApp('dashboard');

// Inspect current state
orchestrator.getAppStatus('dashboard');     // 'mounted' | 'mounting' | 'error' | ...
orchestrator.getMountedApps();              // ['dashboard']
orchestrator.getRegisteredApps();           // ['dashboard', 'settings']

// Tear everything down (idempotent — safe to call multiple times)
await orchestrator.destroy();

🌉 Bridging an External Router

If you already use TanStack Router, Next.js App Router, or React Router, skip config.router entirely and let your existing router drive Tuvix.js via reconcile(path):

const orchestrator = createOrchestrator(); // no router config

orchestrator.register({
  name: 'dashboard',
  entry: '/dashboard.js',
  container: '#main',
  activeWhen: '/dashboard/*',
});

await orchestrator.start();

// After every navigation, tell tuvix.js what the current path is
tanstackRouter.subscribe('onLoad', () => {
  orchestrator.reconcile(window.location.pathname);
});

👁️ Lazy Mounting (Viewport)

Defer expensive micro apps until their container scrolls into view:

orchestrator.register({
  name: 'comments',
  entry: '/comments.js',
  container: '#comments-section',
  mountWhenVisible: true, // mounts on first IntersectionObserver hit
});

🛟 Fallback HTML on Load Failure

orchestrator.register({
  name: 'reports',
  entry: '/reports.js',
  container: '#reports',
  activeWhen: '/reports/*',
  fallback: '<p class="error">Reports temporarily unavailable.</p>',
});

⚡ Prefetching Strategies

const orchestrator = createOrchestrator({
  router: { /* ... */ },
  prefetch: {
    strategy: 'idle', // 'immediate' | 'idle' | 'hover' | 'none' (default)
  },
});
Strategy When bundles are fetched
immediate Right after start()
idle During the next browser idle window (requestIdleCallback)
hover After the user's first mouseover anywhere on the page
none Never (default) — load on demand only

🔌 Inter-App Communication

import { createEventBus } from 'tuvix.js';

const bus = createEventBus();

// App A — emit event
bus.emit('user:login', { userId: 42, name: 'Ahmet' });

// App B — subscribe (returns an unsubscribe function)
const unsubscribe = bus.on('user:login', (data) => {
  console.log(`${data.name} logged in!`);
});

// Fire once and auto-unsubscribe
bus.once('app:ready', () => console.log('ready'));

// Listen to every event for debugging
bus.onAny((event, data) => console.log('[bus]', event, data));

// Cleanup
unsubscribe();

The orchestrator exposes its own bus via orchestrator.getEventBus() so all registered apps share a single channel automatically.


🛣️ Routing

import { createRouter } from 'tuvix.js';

const router = createRouter({
  mode: 'history', // or 'hash'
  base: '/',       // optional base path
  routes: [
    { path: '/dashboard/*', app: 'dashboard' },
    { path: '/users/:id', app: 'users' },
    { path: '/settings', app: 'settings', exact: true },
  ],
});

// Programmatic navigation
await router.push('/dashboard/overview');
await router.replace('/users/42');
router.back();

// Navigation guards (return false to cancel)
const off = router.beforeEach(async ({ from, to }) => {
  if (to.startsWith('/admin') && !isAdmin()) return false;
});

// React to changes
router.onChange(({ from, to, toRoute }) => {
  console.log(`navigated ${from}${to}`, toRoute?.params);
});

// Or use the orchestrator's built-in navigation helper
await orchestrator.navigateTo('/settings');

🏗️ Architecture

┌─────────────────────────────────────────────┐
│              Tuvix.js Shell                  │
│  ┌─────────────────────────────────────────┐│
│  │            Orchestrator                 ││
│  │  ┌──────────┐ ┌──────────┐ ┌─────────┐ ││
│  │  │ Router   │ │Event Bus │ │ Loader  │ ││
│  │  └──────────┘ └──────────┘ └─────────┘ ││
│  └─────────────────────────────────────────┘│
│                                             │
│  ┌───────┐  ┌───────┐  ┌───────┐          │
│  │ App A │  │ App B │  │ App C │  ...      │
│  │(React)│  │ (Vue) │  │(Svelte│          │
│  └───────┘  └───────┘  └───────┘          │
└─────────────────────────────────────────────┘

📦 Packages

Package Description
tuvix.js All-in-one umbrella package
@tuvix.js/core Core orchestrator with lifecycle management
@tuvix.js/router URL-based micro app routing
@tuvix.js/event-bus Inter-app communication event bus
@tuvix.js/loader Dynamic module loader
@tuvix.js/sandbox CSS/JS isolation (Shadow DOM + Proxy)
@tuvix.js/react React 18+ bindings & hooks
@tuvix.js/vue Vue 3 bindings & composables
@tuvix.js/svelte Svelte 3-5 bindings
@tuvix.js/angular Angular 15+ bindings
create-tuvix-app CLI scaffolding tool
@tuvix.js/devtools In-page debug panel
@tuvix.js/server Server-side composition
@tuvix.js/module-federation Webpack Module Federation integration

📁 Project Structure

tuvix.js/
├── packages/
│   ├── core/               # @tuvix.js/core
│   ├── router/             # @tuvix.js/router
│   ├── event-bus/          # @tuvix.js/event-bus
│   ├── loader/             # @tuvix.js/loader
│   ├── sandbox/            # @tuvix.js/sandbox
│   ├── react/              # @tuvix.js/react
│   ├── vue/                # @tuvix.js/vue
│   ├── svelte/             # @tuvix.js/svelte
│   ├── angular/            # @tuvix.js/angular
│   ├── cli/                # create-tuvix-app
│   ├── devtools/           # @tuvix.js/devtools
│   ├── server/             # @tuvix.js/server
│   ├── module-federation/  # @tuvix.js/module-federation
│   └── tuvix/              # tuvix.js (umbrella)
├── examples/
│   ├── with-angular/              # Angular 15+ example
│   ├── with-module-federation-react/ # Module Federation + React example
│   ├── with-multiple-frameworks/  # Multiple frameworks example
│   ├── with-react/                # React 18+ example
│   ├── with-react-devtools/       # React + DevTools example
│   ├── with-react-event-bus/      # React + Event Bus example
│   ├── with-react-router/         # React + Router example
│   ├── with-react-sandbox/        # React + Sandbox example
│   ├── with-ssr-react/            # SSR + React example
│   ├── with-ssr-vanilla/          # SSR + Vanilla JS example
│   ├── with-svelte/               # Svelte 5 example
│   ├── with-vanilla/              # Vanilla JS example
│   └── with-vue/                  # Vue 3 example
├── website/                # Documentation site (VitePress, 10 languages)
├── .github/                # CI/CD workflows
├── package.json            # Root workspace config
├── pnpm-workspace.yaml
├── tsconfig.base.json
└── vitest.config.ts

🗺️ Roadmap

✅ Completed

  • Core orchestrator
  • Lifecycle management
  • Dynamic module loading
  • Event bus
  • URL routing with history/hash modes
  • CSS/JS sandbox isolation
  • CLI scaffolding tool (npx create-tuvix-app)
  • DevTools browser extension
  • Server-side composition (@tuvix.js/server)
  • Module federation support
  • Framework bindings (React, Vue, Svelte, Angular)
  • i18n documentation (10 languages)
  • Example tests & CI coverage for examples

🔜 Coming Soon

Core Runtime

  • Hot module reload across micro apps
  • Shared state management adapter (Zustand / Pinia adapter layer)
  • Plugin system & middleware API
  • Native ESM / importmap support
  • Intersection Observer–based viewport mounting - lazy-mount apps only when their container scrolls into view, reducing initial JS execution cost

Server-Side Rendering

  • BigPipe-style streaming SSR - send the shell HTML immediately over chunked transfer encoding, then stream each micro-app fragment as it resolves; dramatically reduces Time To First Byte compared to the current synchronous composeHTML approach
  • Pre-compiled shell templates - compile the slot-injection template once at server startup rather than per request
  • Critical CSS extraction - inline above-the-fold styles in SSR responses for faster Largest Contentful Paint
  • Edge/CDN-aware server composition with stale-while-revalidate fragment caching

Resilience

  • Fail-safe fallback fragments - declarative per-app fallback HTML shown automatically when a micro-app fails to load or exceeds its timeout; keeps the page usable even when one service is down
  • Fragment A/B testing - register multiple versions of a micro-app and select at runtime via cookie matcher or custom predicate, enabling gradual rollouts without redeploying the shell

Observability

  • Prometheus-compatible metrics endpoint (/metrics) from @tuvix.js/server - track mount/unmount counts, load durations, and error rates per app
  • Visual dependency graph in DevTools
  • VS Code extension for DevTools integration

Developer Experience

  • Testing utilities & mock orchestrator
  • Storybook integration for micro app isolation
  • Preloading & prefetching strategies (already partially available via prefetch.strategy config)

🧪 Examples

Ready-to-run examples for each supported framework are available in the examples/ directory:

Example Framework Path
Angular Example Angular 15+ examples/with-angular/
Module Federation + React Example React 18+ examples/with-module-federation-react/
Multiple Frameworks Example Mixed examples/with-multiple-frameworks/
React Example React 18+ examples/with-react/
React + DevTools Example React 18+ examples/with-react-devtools/
React + Event Bus Example React 18+ examples/with-react-event-bus/
React + Router Example React 18+ examples/with-react-router/
React + Sandbox Example React 18+ examples/with-react-sandbox/
SSR + React Example React 18+ examples/with-ssr-react/
SSR + Vanilla JS Example No framework examples/with-ssr-vanilla/
Svelte Example Svelte 5 examples/with-svelte/
Vanilla JS Example No framework examples/with-vanilla/
Vue Example Vue 3 examples/with-vue/

Each example demonstrates:

  • A shell (host) application that boots the orchestrator
  • Two micro frontend apps registered and loaded dynamically
  • Inter-app communication via the event bus

🤝 Contributing

Contributions are welcome! Please read the Contributing Guide before submitting a PR.

# Clone the repo
git clone https://github.com/yasinatesim/tuvix.js.git

# Install dependencies
pnpm install

# Build all packages
pnpm build

# Run tests
pnpm test

🔑 License

Copyright © 2026 - MIT License. See LICENSE for more information.


This README was generated by markdown-manager 🥲