线上演示地址:wujie-app
源码地址:https://github.com/Jiang-K-J/micro-app?tab=readme-ov-file (如果觉您得有用,请帮忙点个小星星)
主应用:vue2+webpack
子应用:vue3+vite
子应用:react 18 + webpack
无界是微前端框架,有原生版(可在NPM下载),官方同时还针对Vue2、Vue3、React做了不同封装(也可在NPM下载)。封装的意义在于,原生配置较繁琐,而用封装好的版本(如wujie-vue2)操作更简单便捷,下面要讲解基于wujie-vue2封装好的框架开发,实际项目中也多用这种开发方式。
安装
主应用配置
- 准备
首先准备一个vue2的项目,可以是新项目,也可以是已经有过开发的项目,这都不影响wujie微前端框架的使用
- 安装
npm i wujie-vue2 -S
- 引入
// vue2
import WujieVue from "wujie-vue2";const { bus, setupApp, preloadApp, destroyApp } = WujieVue;Vue.use(WujieVue);
- 使用
<WujieVuewidth="100%"height="100%"name="xxx":url="xxx":sync="true":fetch="fetch":props="props":beforeLoad="beforeLoad":beforeMount="beforeMount":afterMount="afterMount":beforeUnmount="beforeUnmount":afterUnmount="afterUnmount"
></WujieVue>
- 属性介绍
更详细的介绍请参考:wujie可用属性的介绍与使用
子应用配置
无界对子应用的侵入非常小,在满足跨域条件下子应用可以不用改造。但是实际开发中,一个成熟的wujie子应用,我们一般需要对它的生命周期进行改造。注意,不同的子应用生命周期改造方式不同,可以参考官方文档,下面我们将讲解对vite构建的vue3子应用进行生命周期改造。
请在你的main.ts文件中加入下方代码
// 你的路由文件
const routes = [{ path: '/', component: About },{ path: '/about', component: About },{ path: '/skip', component: Skip },{ path: '/connect', component: Connect },{ path: '/keepAlive', component: KeepAlive },{ path: '/isolation', component: Isolation }
]declare global {interface Window {// 是否存在无界__POWERED_BY_WUJIE__?: boolean;// 子应用mount函数__WUJIE_MOUNT: () => void;// 子应用unmount函数__WUJIE_UNMOUNT: () => void;// 子应用无界实例__WUJIE: { mount: () => void };}
}if (window.__POWERED_BY_WUJIE__) {let instance: any;window.__WUJIE_MOUNT = () => {const router = createRouter({ history: createWebHistory(), routes });instance = createApp(App)instance.use(router);instance.mount("#app");};window.__WUJIE_UNMOUNT = () => {instance.unmount();};/*由于vite是异步加载,而无界可能采用fiber执行机制所以mount的调用时机无法确认,框架调用时可能vite还没有加载回来,这里采用主动调用防止用没有mount无界mount函数内置标记,不用担心重复mount*/window.__WUJIE.mount()
} else {createApp(App).use(createRouter({ history: createWebHistory(), routes })).mount("#app");
}
基本使用
- Props传参
- 主应用
<template><WujieVuewidth="100%"height="100%"name="about-vue":url="$v3Url":props="{ username: 'JohnDoe', theme: 'dark' }"/>
</template><script>
export default {data() {return {$v3Url: "https://subapp.example.com",};},
};
</script>
- 子应用 :子应用可以通过
window.$wujie.props
获取主应用传递的参数。window.$wujie
这个属性,是wujie自动注入到子应用的windo上的,不需要你做任何操作
const props = window.$wujie?.props;
console.log(props.username); // 输出:JohnDoe
console.log(props.theme); // 输出:dark
- 路由跳转
其实就是主应用通过Props传递一个给子应用,子应用触发主应用的函数实现路由跳转。当然,你也可以将整个路由对象传递给子应用,让子应用实现自定义跳转
- 主应用
<template><!-- 子应用 A --><wujie-vue name="A" url="//hostA.com" :props="{jump}" ></WujieVue>
</template><script>
export default {methods: {jump(location) {this.$router.push(location);}
}
</script>
- 子应用
// 子应用 A 点击跳转处理函数
function handleJump() {window.$wujie?.props.jump({ path: "/pathB" });
}
- 应用通信
Wujie 提供了 bus
作为事件总线,主应用和子应用都可以通过它来发送和接收事件。
- 主应用 :主应用监听和发送事件
<template><WujieVuewidth="100%"height="100%"name="about-vue":url="$v3Url"/><button @click="sendMessageToChild">发送消息到子应用</button>
</template><script>
export default {methods: {sendMessageToChild() {window.$wujie?.bus?.$emit("message-from-main", {msg: "Hello from Main App",});},},mounted() {window.$wujie?.bus?.$on("message-from-child", (data) => {console.log("收到子应用消息:", data);});},
};
</script>
- 子应用 :子应用监听和发送事件
if (window.$wujie?.bus) {// 监听主应用的消息window.$wujie.bus.$on("message-from-main", (data) => {console.log("收到主应用消息:", data);});// 发送消息到主应用window.$wujie.bus.$emit("message-from-child", {msg: "Hello from Child App",});
}
部署
wujie的部署和普通项目部署没有区别,只是子应用需要配置nginx来允许跨域访问
- 主应用nginx配置
location / {index index.html;try_files $uri /index.html;}
- 子应用nginx配置
location / {index index.html;try_files $uri /index.html;# 添加跨域头add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";add_header Access-Control-Allow-Headers "Content-Type, Authorization";if ($request_method = OPTIONS) {add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";add_header Access-Control-Allow-Headers "Content-Type, Authorization";return 204;}}
踩坑总结
- UI组件库样式丢失——增加
patchElementHook
插件
<WujieVuewidth="100%"height="100%"name="xxx":url:props="{ jump }":plugins="[{patchElementHook(element, iframeWindow) {if (element.nodeName === "STYLE") {element.insertAdjacentElement = function (_position, ele) {iframeWindow.document.head.appendChild(ele);};}},}]"></WujieVue>
- el-select 位置偏移以及 el-table tootip 位置偏移的问题
持续更新中