Wujie:下一代微前端框架?从入门到精通的终极指南 (Vue3 & React 实战)

347 阅读9分钟

🚀 Wujie:下一代微前端框架?从入门到精通的终极指南 (Vue3 & React 实战)

微前端 Wujie Vue3 React JavaScript

✨ 前言

官网文档:wujie-micro.github.io/doc/

微前端架构早已不是什么新鲜词,从最早的 iframe 蛮荒时代,到 qiankun 一统江湖,再到后来的 micro-app 等新秀,我们一直在探索更优的解法。我们期望的微前端方案应该是什么样的?

  • 接入简单:对子应用的改造越少越好,最好不改。
  • 性能卓越:加载速度快,内存占用低,用户体验接近单体应用。
  • 隔离完美:JS 沙箱和 CSS 样式隔离必须可靠,杜绝应用间的“爱恨情仇”。
  • 功能强大:通信机制完善,应用保活、预加载等高级功能一应俱全。

今天,我们要深入探讨的主角——Wujie (无界) ,就是带着解决这些痛点的使命而来的。它由腾讯前端团队出品,巧妙地结合了 WebComponentiframe 的优点,提供了一种全新的、更优雅的微前端实现思路。

本文将作为一份详尽的 Wujie 使用文档,带你从理念到实战,彻底掌握这个“下一代”微前端框架。


🧐 为什么是 Wujie?核心优势与框架对比

在选择技术方案时,我们首先要问 "Why"。为什么在已经有 qiankun 这样的成熟方案后,我们还要考虑 Wujie?

核心优势 (The Good Parts)

  1. 极简上手,零改造成本:Wujie 最吸引人的一点就是对子应用的侵入性极低。大部分情况下,子应用无需做任何改造,不需要暴露特定的生命周期,也不需要修改打包配置,像普通应用一样开发部署即可。这极大地降低了老项目迁移和新项目接入的成本。

  2. 极致性能与完美体验

    • 预加载:Wujie 可以在用户访问前,提前静默加载子应用的资源(js, css),当用户真正切换时,能够实现秒开效果。
    • 应用保活:基于 WebComponentdisconnectedCallback 特性,Wujie 可以轻松实现应用状态的保留。切换回之前的应用时,所有数据、状态、DOM 都完好如初,体验远超 qiankun 的快照方案。
    • 多应用同时激活:可以同时激活多个子应用,并通过 display: none 控制显隐,实现类似 keep-alive 的效果。
  3. 天生隔离,坚不可摧

    • CSS 隔离:Wujie 利用 WebComponent + Shadow DOM 实现了完美的样式隔离。主应用和子应用、子应用和子应用之间的样式完全互不干扰,无需任何 babel 插件或 css scope 方案。
    • JS 隔离:Wujie 创新性地利用一个独立的 iframe 作为 JS 沙箱。子应用的 jsiframe 内运行,windowdocument 等全局变量天然隔离,但 DOM 又被巧妙地“劫持”并渲染到主应用的 WebComponent 中。这种方式比 Proxy 实现的沙箱更彻底、更安全,且性能更优。

🆚 主流微前端框架横评

为了更直观地展示 Wujie 的优势,我们将其与目前最主流的 qiankunmicro-app 进行对比。

特性 / 框架Wujie (无界)qiankunmicro-app
核心原理WebComponent + iframe 沙箱Proxy 沙箱 + import-html-entryWebComponent + 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: 插件系统,可以拦截和处理 jscss 等资源。
  • 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.vueonMounted 中),调用 preload 方法。

JavaScript

import WujieVue from 'wujie-vue3';

// 登录成功后或首页加载完成后
WujieVue.preload({
  name: "react-app", // 预加载 react-app
  url: "http://localhost:8082/",
  exec: true // [可选] 提前执行脚本,内存换时间
});

当用户点击导航切换到 react-app 时,由于资源已经加载甚至执行完毕,页面将瞬间呈现。


⚠️ 最佳实践与注意事项

  1. Public Path:确保子应用的 webpack 等打包工具配置了正确的 publicPath,以应对不同的部署环境。通常建议配置为相对路径 publicPath: '/'
  2. 路由模式:主子应用都推荐使用 History 模式路由。Wujie 对 Hash 模式的支持不如 History 模式完美。对于子应用,需要设置好路由的 base 路径。
  3. 弹窗与全局组件:子应用的 ModalDialogMessage 等全局组件,由于 Wujie 的 Shadow DOM 隔离,默认会被限制在子应用容器内。为了让它们能够全局展示,需要将这些组件 teleport (瞬移) 到主应用的 body 下。Wujie 提供了 document.body 的代理,子应用可以直接 teleportdocument.body
  4. 字体文件跨域:如果子应用的字体文件与主应用不在同域,可能会有跨域问题。需要在字体文件服务器上配置正确的 CORS 策略。

🏁 总结

Wujie 微前端框架通过其 WebComponent + iframe 的独特架构,成功地解决了传统微前端方案中的诸多痛点。它在接入成本隔离机制性能体验三个核心维度上都表现出了卓越的竞争力。

  • 对于新项目,Wujie 提供了一个高起点、高性能的微前端解决方案。
  • 对于希望进行微前端改造的老项目,Wujie 极低的改造成本使其成为一个极具吸引力的选择。

当然,Wujie 作为一个相对年轻的框架,其社区生态和周边工具与 qiankun 相比还有一定差距。但在核心能力上,它已经证明了自己是一款设计精良、功能强大的现代微前端框架。

如果你正在进行微前端的技术选型,我强烈建议你将 Wujie 放入考察列表,亲自体验一下它带来的 “无界” 开发之旅。

希望这篇详尽的文档能对你有所帮助!如果你有任何问题,欢迎在评论区留言讨论。