线上演示地址: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);
- 使用
<WujieVue
width="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>
<WujieVue
width="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>
<WujieVue
width="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
插件
<WujieVue
width="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 位置偏移的问题
持续更新中