線上演示地址: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 位置偏移的問題
持續更新中