🚀 Wujie:下一代微前端框架?从入门到精通的终极指南 (Vue3 & React 实战)
微前端 Wujie Vue3 React JavaScript
✨ 前言
官网文档:wujie-micro.github.io/doc/
微前端架构早已不是什么新鲜词,从最早的 iframe 蛮荒时代,到 qiankun 一统江湖,再到后来的 micro-app 等新秀,我们一直在探索更优的解法。我们期望的微前端方案应该是什么样的?
- 接入简单:对子应用的改造越少越好,最好不改。
- 性能卓越:加载速度快,内存占用低,用户体验接近单体应用。
- 隔离完美:JS 沙箱和 CSS 样式隔离必须可靠,杜绝应用间的“爱恨情仇”。
- 功能强大:通信机制完善,应用保活、预加载等高级功能一应俱全。
今天,我们要深入探讨的主角——Wujie (无界) ,就是带着解决这些痛点的使命而来的。它由腾讯前端团队出品,巧妙地结合了 WebComponent 和 iframe 的优点,提供了一种全新的、更优雅的微前端实现思路。
本文将作为一份详尽的 Wujie 使用文档,带你从理念到实战,彻底掌握这个“下一代”微前端框架。
🧐 为什么是 Wujie?核心优势与框架对比
在选择技术方案时,我们首先要问 "Why"。为什么在已经有 qiankun 这样的成熟方案后,我们还要考虑 Wujie?
核心优势 (The Good Parts)
-
极简上手,零改造成本:Wujie 最吸引人的一点就是对子应用的侵入性极低。大部分情况下,子应用无需做任何改造,不需要暴露特定的生命周期,也不需要修改打包配置,像普通应用一样开发部署即可。这极大地降低了老项目迁移和新项目接入的成本。
-
极致性能与完美体验:
- 预加载:Wujie 可以在用户访问前,提前静默加载子应用的资源(js, css),当用户真正切换时,能够实现秒开效果。
- 应用保活:基于
WebComponent的disconnectedCallback特性,Wujie 可以轻松实现应用状态的保留。切换回之前的应用时,所有数据、状态、DOM 都完好如初,体验远超 qiankun 的快照方案。 - 多应用同时激活:可以同时激活多个子应用,并通过
display: none控制显隐,实现类似keep-alive的效果。
-
天生隔离,坚不可摧:
- CSS 隔离:Wujie 利用
WebComponent+Shadow DOM实现了完美的样式隔离。主应用和子应用、子应用和子应用之间的样式完全互不干扰,无需任何babel插件或css scope方案。 - JS 隔离:Wujie 创新性地利用一个独立的
iframe作为 JS 沙箱。子应用的js在iframe内运行,window、document等全局变量天然隔离,但DOM又被巧妙地“劫持”并渲染到主应用的WebComponent中。这种方式比Proxy实现的沙箱更彻底、更安全,且性能更优。
- CSS 隔离:Wujie 利用
🆚 主流微前端框架横评
为了更直观地展示 Wujie 的优势,我们将其与目前最主流的 qiankun 和 micro-app 进行对比。
| 特性 / 框架 | Wujie (无界) | qiankun | micro-app |
|---|---|---|---|
| 核心原理 | WebComponent + iframe 沙箱 | Proxy 沙箱 + import-html-entry | WebComponent + Proxy 沙箱 |
| JS 隔离 | ✅ 天然隔离 (iframe) | ✅ Proxy 代理,有逃逸风险 | ✅ Proxy 代理,有逃逸风险 |
| CSS 隔离 | ✅ 天然隔离 (Shadow DOM) | ⚠️ 需 Scoped CSS 或 PostCSS | ✅ Shadow DOM |
| 接入成本 | ⭐ 极低,基本无需改造 | ⚠️ 较高,需改入口、打包配置 | ⭐ 较低,需简单修改入口文件 |
| 性能损耗 | ✅ 较低 | ⚠️ 中等,Proxy 劫持较多 | ⚠️ 中等,Proxy 劫持较多 |
| 应用保活 | ✅ 原生支持,状态完整保留 | ⚠️ 实验性方案,基于快照 | ✅ 原生支持 |
| 预加载 | ✅ 原生支持 | ✅ 原生支持 | ✅ 原生支持 |
| 社区生态 | 🚀 发展中 | ⭐ 非常成熟 | 👍 良好 |
结论:如果你追求最低的接入成本、最彻底的隔离和最接近原生的应用保活体验,Wujie 无疑是当前最值得尝试的方案。
🛠️ Wujie 实战演练:从 0 到 1 集成
光说不练假把式,接下来我们手把手带你将 Wujie 集成到 Vue 3 和 React 项目中。
准备工作
- 主应用:可以是 Vue 3 或 React。
- 子应用:可以是任何技术栈(Vue 2/3, React, Angular, 甚至静态页面),能够独立运行即可。
1. Vue 3 主应用集成
步骤 1: 安装依赖
在你的 Vue 3 主应用项目中安装 Wujie。
Bash
npm install wujie-vue3 --save
步骤 2: 注册插件
在 main.js 中引入并注册 Wujie。这是配置全局能力的地方,例如预加载。
JavaScript
// main.js
import { createApp } from 'vue'
import WujieVue from 'wujie-vue3'
import App from './App.vue'
const app = createApp(App)
app.use(WujieVue)
app.mount('#app')
// 在合适的时机执行预加载
// WujieVue.preload({ name: "vue3-app", url: "http://localhost:8081/" })
步骤 3: 在组件中使用
在需要嵌入子应用的组件中,使用 <WujieVue> 组件。
代码段
<template>
<div class="micro-app-container">
<WujieVue
width="100%"
height="100%"
:name="appName"
:url="appUrl"
:sync="true"
:props="passProps"
></WujieVue>
</div>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
// 子应用配置
const microApps = {
'vue3-app': 'http://localhost:8081/',
'react-app': 'http://localhost:8082/',
};
// 动态决定加载哪个子应用
const appName = computed(() => route.meta.appName);
const appUrl = computed(() => microApps[appName.value]);
// 传递给子应用的 props
const passProps = reactive({
message: 'Hello from main app!',
// ... 其他数据或方法
});
</script>
步骤 4: 配置子应用 (几乎不用动!)
对于 Vue 3 子应用,为了确保在微前端环境下也能正常卸载,我们需要在 main.js 中做一点小小的适配。
JavaScript
// 子应用: main.js
import { createApp } from 'vue'
import App from './App.vue'
let instance;
function render(props) {
instance = createApp(App)
instance.mount(props?.container ? props.container.querySelector('#app') : '#app')
}
// wujie 会注入一个 `window.__WUJIE_UNMOUNT` 方法
if (window.__POWERED_BY_WUJIE__) {
window.__WUJIE.mount = (props) => {
console.log("Wujie mount", props);
render(props);
};
window.__WUJIE.unmount = () => {
console.log("Wujie unmount");
instance.unmount();
};
} else {
// 独立运行时
render();
}
看到了吗? 子应用的改造就是这么简单!它甚至保留了独立运行的能力。
2. React 主应用集成
步骤 1: 安装依赖
Bash
npm install wujie-react --save
步骤 2: 在组件中使用
Wujie for React 同样提供了一个组件 <WujieReact>。
JavaScript
// components/MicroApp.js
import React, { useState, useMemo } from 'react';
import { useLocation } from 'react-router-dom';
import WujieReact from 'wujie-react';
const microApps = {
'vue3-app': 'http://localhost:8081/',
'react-app': 'http://localhost:8082/',
};
export default function MicroApp() {
const location = useLocation();
// 假设你的路由信息中包含了 appName
const appName = useMemo(() => location.state?.appName, [location]);
const appUrl = useMemo(() => microApps[appName], [appName]);
const props = {
message: 'Hello from React main app!',
};
if (!appUrl) return <div>Invalid App</div>;
return (
<div style={{ width: '100%', height: '100%' }}>
<WujieReact
width="100%"
height="100%"
name={appName}
url={appUrl}
sync={true}
props={props}
></WujieReact>
</div>
);
}
步骤 3: React 子应用改造
与 Vue 子应用类似,适配 React 子应用。
JavaScript
// 子应用: index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
let root;
function render(props) {
const { container } = props;
root = ReactDOM.createRoot(container ? container.querySelector('#root') : document.querySelector('#root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
}
if (window.__POWERED_BY_WUJIE__) {
window.__WUJIE.mount = (props) => {
render(props);
};
window.__WUJIE.unmount = () => {
root.unmount();
};
} else {
render({});
}
⚙️ 核心配置与高级用法
掌握了基础集成,我们再来看看 Wujie 那些强大的配置和高级功能。
1. <WujieVue> / <WujieReact> 核心 Props
name: 子应用的唯一标识,必填。用于缓存和通信。url: 子应用的 HTML 入口地址,必填。sync: 是否将路由同步到主应用。设为true后,子应用的路由变化会反映在主应用的 URL 参数上,便于刷新和分享。props: 传递给子应用的数据和方法。alive: 是否开启应用保活。设为true后,切换走再切回来,应用状态会保留。exec: 是否立即执行脚本。配合alive和预加载,可以实现应用预执行,达到秒开效果。plugins: 插件系统,可以拦截和处理js、css等资源。beforeLoad,beforeMount,afterMount,beforeUnmount,afterUnmount: 完整的生命周期钩子。
2. 应用间通信 (Communication)
Wujie 提供了三种主流的通信方式:
a. props 属性注入 (父 -> 子)
这是最简单直接的方式,主应用通过 props 属性将数据和方法传递给子应用。
代码段
<WujieVue :props="{ data: 'some data', callMain: handleCall }"></WujieVue>
子应用通过 window.$wujie.props 来获取。
JavaScript
// 子应用
const props = window.$wujie?.props;
console.log(props.data); // 'some data'
props.callMain('message from child');
b. EventBus 事件总线 (推荐)
Wujie 内置了一个全局的事件总线 $bus,用于任意应用间的通信,实现解耦。
JavaScript
// A 应用 (主或子)
window.$wujie?.bus.$emit('some-event', { id: 1, content: '...' });
JavaScript
// B 应用 (主或子)
window.$wujie?.bus.$on('some-event', (payload) => {
console.log('Received:', payload);
});
// 记得在组件卸载时取消监听
// window.$wujie?.bus.$off('some-event', myListener);
c. window.parent (子 -> 父)
子应用可以通过 window.parent 访问主应用的 window,从而调用主应用挂载在 window 上的方法或变量。
注意:这是一种强耦合的方式,仅在特殊场景下推荐使用。
3. 子应用预加载 (Preload)
为了极致的用户体验,预加载必不可少。在主应用合适的位置(例如,App.vue 的 onMounted 中),调用 preload 方法。
JavaScript
import WujieVue from 'wujie-vue3';
// 登录成功后或首页加载完成后
WujieVue.preload({
name: "react-app", // 预加载 react-app
url: "http://localhost:8082/",
exec: true // [可选] 提前执行脚本,内存换时间
});
当用户点击导航切换到 react-app 时,由于资源已经加载甚至执行完毕,页面将瞬间呈现。
⚠️ 最佳实践与注意事项
- Public Path:确保子应用的
webpack等打包工具配置了正确的publicPath,以应对不同的部署环境。通常建议配置为相对路径publicPath: '/'。 - 路由模式:主子应用都推荐使用
History模式路由。Wujie 对Hash模式的支持不如History模式完美。对于子应用,需要设置好路由的base路径。 - 弹窗与全局组件:子应用的
Modal、Dialog、Message等全局组件,由于 Wujie 的Shadow DOM隔离,默认会被限制在子应用容器内。为了让它们能够全局展示,需要将这些组件teleport(瞬移) 到主应用的body下。Wujie 提供了document.body的代理,子应用可以直接teleport到document.body。 - 字体文件跨域:如果子应用的字体文件与主应用不在同域,可能会有跨域问题。需要在字体文件服务器上配置正确的
CORS策略。
🏁 总结
Wujie 微前端框架通过其 WebComponent + iframe 的独特架构,成功地解决了传统微前端方案中的诸多痛点。它在接入成本、隔离机制和性能体验三个核心维度上都表现出了卓越的竞争力。
- 对于新项目,Wujie 提供了一个高起点、高性能的微前端解决方案。
- 对于希望进行微前端改造的老项目,Wujie 极低的改造成本使其成为一个极具吸引力的选择。
当然,Wujie 作为一个相对年轻的框架,其社区生态和周边工具与 qiankun 相比还有一定差距。但在核心能力上,它已经证明了自己是一款设计精良、功能强大的现代微前端框架。
如果你正在进行微前端的技术选型,我强烈建议你将 Wujie 放入考察列表,亲自体验一下它带来的 “无界” 开发之旅。
希望这篇详尽的文档能对你有所帮助!如果你有任何问题,欢迎在评论区留言讨论。