Skip to content
🎁
tuvix.js
tuvix.js(聚合包)
一个包,一个导入路径。重新导出 @tuvix.js/core 中的编排器,以及 @tuvix.js/router、@tuvix.js/event-bus、@tuvix.js/loader 和 @tuvix.js/sandbox 的公共 API。

安装 ​

bash
npm install tuvix.js
# or pnpm add tuvix.js

安装 tuvix.js 会同时安装 @tuvix.js/core、@tuvix.js/router、@tuvix.js/event-bus、@tuvix.js/loader 和 @tuvix.js/sandbox。这六个包都提供 ES 模块和 CommonJS 构建,并声明 "sideEffects": false。

何时使用 ​

在同时使用编排器和路由器、事件总线或沙箱的 shell(宿主应用)中安装 tuvix.js。你只需管理一个依赖的版本和一个导入路径,打包工具会去掉你从未导入的导出。

以下情况请改为安装带作用域的包:

  • 微应用只与 shell 通信。单独使用 @tuvix.js/event-bus 就能获得 getGlobalBus(),不会把编排器带进它的 node_modules。
  • 你需要聚合包没有包含的导出,例如 @tuvix.js/loader 的 registerModule 或 emitLifecycle,或 @tuvix.js/router 的 pathToRegex。参见未包含的内容。
  • 你希望 package.json 明确写出一个包依赖 Tuvix.js 的哪些部分。

两者混用是安全的。聚合包重新导出的是相同的模块,所以从 tuvix.js 和从 @tuvix.js/event-bus 导入的 getGlobalBus 返回同一个总线,生命周期辅助函数也共享 window 上的同一个注册表。

快速开始 ​

一个 shell:在 /about 上挂载 about,把链接点击转为路由器导航,并记录应用错误:

ts
import { createOrchestrator, getGlobalBus, interceptLinks, OrchestratorEvent, type AppErrorEvent } from 'tuvix.js';

const orchestrator = createOrchestrator({ router: { routes: [] } });

orchestrator.register({
  name: 'about',
  entry: 'https://cdn.example.com/about/main.js',
  container: '#main',
  activeWhen: '/about',
  props: { who: 'us' },
});

getGlobalBus().on<AppErrorEvent>(OrchestratorEvent.APP_ERROR, ({ name, error, phase }) => {
  console.error(`${name} failed during ${phase}`, error);
});

await orchestrator.start();
interceptLinks({ navigate: (path) => orchestrator.navigateTo(path) });

about 应用,构建到 https://cdn.example.com/about/main.js:

ts
import { defineMicroApp } from 'tuvix.js';

export default defineMicroApp({
  name: 'about',
  mount({ container, props }) {
    container.innerHTML = `<h1>About ${String(props?.who)}</h1>`;
  },
  unmount({ container }) {
    container.replaceChildren();
  },
});

点击 <a href="/about?ref=nav"> 会推入 /about?ref=nav,编排器会把 about 挂载到 #main 中(查询字符串不影响匹配)。

API ​

下面的每个导出都是重新导出。链接的包页面记录了它的签名、选项和边界情况。

来自 @tuvix.js/core ​

文档:@tuvix.js/core。

导出种类作用
createOrchestrator函数创建一个 Orchestrator。
Orchestrator类注册应用,根据 URL 协调应用,跟随路由器(connectRouter),更新 props,销毁。
defineMicroApp函数校验 { name, bootstrap?, mount, unmount, update?, ssr? } 对象,为加载器注册它,并让它发出 tuvix:mounted / tuvix:unmounted / tuvix:error。
OrchestratorEvent枚举编排器在其总线上发出的事件名(tuvix:app:mount、tuvix:app:error 等)。
OrchestratorConfig, MicroAppConfig, MicroAppDefinition类型createOrchestrator、register 和 defineMicroApp 的参数。
AppStatus, AppSandboxOption, RouterSource, RegisteredApp类型应用状态联合类型、sandbox 选项、connectRouter 的参数、应用记录的结构。
AppErrorEvent, AppErrorPhase类型APP_ERROR 的载荷 { name, error, phase } 及其阶段联合类型('load'、'bootstrap'、'mount'、'update'、'unmount')。

来自 @tuvix.js/event-bus ​

文档:@tuvix.js/event-bus。

导出种类作用
EventBus类发布/订阅总线,提供 on、once、emit、off、onAny。
createEventBus函数创建一个新的、独立的 EventBus。
getGlobalBus函数返回存放在 window.__TUVIX_GLOBAL_BUS__ 上的页面级总线。编排器默认使用它。
resetGlobalBus函数销毁页面级总线;下一次调用 getGlobalBus() 会创建新的总线。
IEventBus, EventHandler, WildcardHandler, Unsubscribe, EventBusOptions类型总线接口、处理函数签名、取消订阅函数、构造函数选项。

来自 @tuvix.js/router ​

文档:@tuvix.js/router。

导出种类作用
Router类把路径映射到应用名的 history 或 hash 路由器。
createRouter函数创建一个 Router。
matchPath函数用模式匹配路径(支持 :param、/*,忽略查询字符串和 hash)。activeWhen 字符串使用它。
matchRoute函数返回 RouteConfig[] 中第一个完整匹配路径的路由,附带 params 和 query。
normalizePath函数添加开头的斜杠并去掉结尾的斜杠。
interceptLinks函数把同源链接点击转为 navigate(path) 调用,可选按意图预取。
resolveLink函数返回事件发生所在 HTML 链接的 { anchor, url, path },浏览器应当处理该链接时返回 null。
IRouter, RouterConfig, RouterMode, RouteConfig, MatchedRoute类型路由器接口、选项和路由结构。
NavigationEvent, NavigationGuard, RouteChangeHandler类型导航载荷、守卫和监听器的签名。
PathMatch, MatchPathOptions, InterceptLinksOptions, ResolvedLink, ResolveLinkOptions类型matchPath 的结果和选项,interceptLinks 的选项,resolveLink 的结果和选项。

来自 @tuvix.js/loader ​

文档:@tuvix.js/loader。

导出种类作用
ModuleLoader类加载入口(URL、脚本/样式配置或加载器函数),支持超时、重试和缓存。
createLoader函数创建一个 ModuleLoader。
whenMounted函数在应用发出 mounted 生命周期事件时 resolve。
onLifecycle函数监听 tuvix:mounted、tuvix:unmounted 或 tuvix:error DOM 事件。
isMounted函数根据生命周期事件,只要应用的任一容器处于挂载状态就返回 true。
Entry, EntryConfig, MicroAppModule, MountContext, UnmountContext, UpdateContext类型入口格式,以及微应用要实现的生命周期契约。
LoaderOptions, LoadResult, LoadStatus, PrefetchStrategy类型加载器选项和结果。
LifecycleType, LifecycleDetail, LifecycleEvent类型生命周期事件名、载荷和 DOM 事件类型。
ts
import { onLifecycle, whenMounted } from 'tuvix.js';

const off = onLifecycle('error', ({ name, error }) => console.error(name, error));

const { container, hydrated } = await whenMounted('footer', { signal: AbortSignal.timeout(5000) });
console.log(container.id, hydrated);
off();

来自 @tuvix.js/sandbox ​

文档:@tuvix.js/sandbox。

导出种类作用
CssSandbox类把容器移入 shadow root,并在其中加载样式表。编排器在 sandbox: true 时使用它。
JsSandbox类代理 window,让脚本写入的全局变量不进入真实的 window。
Sandbox类用一对 activate / deactivate 统一控制 CssSandbox 和 JsSandbox。
createSandbox函数创建一个 Sandbox。
SandboxOptions, ISandbox, ICssSandbox, IJsSandbox类型各沙箱的选项和接口。
AdoptStylesOptions, AdoptedStyles类型CssSandbox.adoptStyles 的参数和返回值。

未包含的内容 ​

聚合包没有包含以下内容。请安装提供它们的包。

你需要安装
registerModule, unregisterModule, getRegisteredModule, emitLifecycle, hasServerMarkup, normalizeEntry, loadScript, loadStyle, removeScript, removeStyle, prefetchResource,以及类型 EntryLoader, EntryLoaderContext, MicroAppBus, ScriptType, CacheEntry, ResourceOptions, LoadScriptOptions, LoadStyleOptions, PrefetchOptions@tuvix.js/loader
pathToRegex, parseQuery, isPathActive@tuvix.js/router
React、Vue、Svelte 或 Angular 微应用@tuvix.js/react, @tuvix.js/vue, @tuvix.js/svelte, @tuvix.js/angular
服务端组合@tuvix.js/server
Module Federation 远程模块@tuvix.js/module-federation
Vite 构建中的 island 资源@tuvix.js/vite
DevTools 面板@tuvix.js/devtools
项目脚手架create-tuvix-app

边界情况 ​

  • tuvix.js 只有一个入口点。tuvix.js/core 或 tuvix.js/router 这类子路径导入无法解析;请从 tuvix.js 或带作用域的包导入。
  • 聚合包把依赖固定到同一个发布版本。在 tuvix.js 旁边安装另一个版本的带作用域包,会得到该包的两个副本。getGlobalBus() 和生命周期注册表仍然通过 window 共享状态,但跨副本的 instanceof Orchestrator 或 instanceof EventBus 检查会失败。
  • whenMounted、onLifecycle 和 isMounted 响应 tuvix:* DOM 事件。来自 defineMicroApp 和框架适配器的模块会发出这些事件;手写的模块除非调用 @tuvix.js/loader 的 emitLifecycle,否则不会发出任何事件。针对文档之外的容器的事件会在 document 上派发。
  • resetGlobalBus() 会销毁正在运行的编排器持有的总线。编排器会继续持有这个已销毁的总线,因此它的事件不再到达下一次 getGlobalBus() 的订阅者。请在测试之间、orchestrator.destroy() 之后调用它。
  • @tuvix.js/core 和 @tuvix.js/router 中的行为变更和破坏性变更在这里同样适用。参见从 0.4 迁移。

它不做什么 ​

  • 它不添加任何自己的代码。每个导出都来自五个带作用域的包之一。
  • 它不包含框架适配器、server 包、Module Federation、Vite 或 DevTools。
  • 它不为每个包提供子路径入口。