🧑💻 寫在開頭
點贊 + 收藏 === 學會🤣🤣🤣
官方文件
接入vue2
專案和vue3
專案
對應路由模式分別是hash
和history
主應用
主應用是基於vue3開發的一個入口網站,僅有登入以及門戶列表。
基於路由配置方式
透過將微應用關聯到一些 url 規則的方式,實現當瀏覽器 url 發生變化時,自動載入相應的微應用的功能。
-
安裝
qiankun
npm i qiankun -S # 或者 yarn add qiankun
-
在主應用中註冊微應用以及對應配置
新建
qiankun
資料夾,包含一個config.js
和index.js
-
config
下面存放微應用的配置資訊,程式碼如下:
// qiankun/config.js // 這裡用函式的方式,方便初始化的時候可以設定一些預設引數傳進來,例如token等, // 用於下發給微應用 export const getQiankunConfig = (props = {}) => { return { subApps: [ { name: "xxx-wms", // 子應用名稱,建議跟package.json一致 entry: "//192.168.1.40:8990/", // 子應用入口,本地環境下指定埠 container: "#sub-container", // 掛載子應用的dom activeRule: "/xxx/wms", // 路由匹配規則 props // 主應用與子應用通訊傳值 }, { name: "xxx-report", // 子應用名稱,跟package.json一致 entry: "//192.168.1.40:9527/#/", // 子應用入口,本地環境下指定埠 container: "#sub-container", // 掛載子應用的dom activeRule: "/xxx/report", // 路由匹配規則 props // 主應用與子應用通訊傳值 }, ] }; };
index
放初始化函式以及一些其他需要配置和操作
// qiankun/index.js import { registerMicroApps } from "qiankun"; import { getQiankunConfig } from "./configs"; import { getToken } from "@/plugins/cache"; import useUserStore from "@/store/modules/user"; // 設定初始需要傳遞的值 export const getState = () => { const { userInfo } = useUserStore(); const state = { token: getToken(), accessUser: { loginName: userInfo.userName || "", realName: userInfo.userDisplayName || "" } }; return state; }; const { subApps } = getConfig(getState()); // 暴露註冊函式,裡面對應存放生命週期的鉤子,可以做需要的處理 export function registerApps() { try { registerMicroApps(subApps, { beforeLoad: [ app => { console.log("before load", app); } ], beforeMount: [ app => { console.log("before mount", app); } ], afterUnmount: [ app => { console.log("before unmount", app); } ] }); } catch (err) { console.log(err); } }
新增容器,以及在路由表上增加對應路徑的配置
官方原話:當微應用資訊註冊完之後,一旦瀏覽器的
url
發生變化,便會自動觸發qiankun
的匹配邏輯,所有activeRule
規則匹配上的微應用就會被插入到指定的container
中,同時依次呼叫微應用暴露出的生命週期鉤子。
- 新建
subContainer
元件,程式碼如下:
// subContainer.vue <template> <div id="sub-container"></div> </template> <script setup> import { start } from "qiankun"; import { registerApps } from "@/qiankun"; onMounted(()=>{ if (!window.qiankunStarted) { window.qiankunStarted = true; registerApps(); start({ prefetch: false, // 是否開啟預載入, 預設為 true // sandbox: { // strictStyleIsolation: true // 開啟嚴格的樣式隔離模式 // experimentalStyleIsolation: true // 樣式隔離 // } }); } }) </script>
- 路由表配置如下:
// router/xxx.js export const routes = [ // ... { // history模式需要通配所有路由, // 注意:此處xxx需要匹配上面的微前端配置裡的activeRule欄位 path: "/xxx/:pathMatch(.*)*", name: "xxxxx", meta: {}, component: () => import("@/views/subContainer") }, ]
微應用
-
vue3 + vite
,路由模式為history
-
新建
qiankun
相關配置檔案- 安裝
vite-plugin-qiankun
外掛(qiankun
目前沒有支援vite
的文件)
npm i vite-plugin-qiankun -D
- 在
vite.config.js
中配置外掛
- 安裝
// vite.config.js import qiankun from "vite-plugin-qiankun"; export default defineConfig() => { const { VITE_POWERED_BY_QIANKUN, VITE_PUBLIC_PATH } = env; return { base: VITE_PUBLIC_PATH, // 絕對路徑,線上會有跨域問題 plugins: [ // VITE_POWERED_BY_QIANKUN qiankun的路徑字首 qiankun(VITE_POWERED_BY_QIANKUN, { useDevMode: true }) ] } }
- 匯出對應的生命週期鉤子,以及初始化方式
// qiankun.js import { renderWithQiankun, qiankunWindow } from "vite-plugin-qiankun/dist/helper"; export const render = (app, container) => { app.mount(container ? container.querySelector("#app") : "#app"); }; export const initQianKun = (app) => { renderWithQiankun({ mount(props) { const { container } = props; render(app, container); }, bootstrap() { console.log("bootstrap"); }, unmount() { app.unmount(); } }); }; // 初始化,判斷是否在子應用的環境中 export const init = (app) => { qiankunWindow.__POWERED_BY_QIANKUN__ ? initQianKun(app) : render(app); };
- 路由設定,如果是
qiankun
子應用的環境,增加對應的字首
// router/index.js import { createWebHistory, createRouter } from "vue-router"; const VITE_POWERED_BY_QIANKUN = import.meta.env.VITE_POWERED_BY_QIANKUN; const router = createRouter({ history: createWebHistory( qiankunWindow.__POWERED_BY_QIANKUN__ ? `/xxx/${VITE_POWERED_BY_QIANKUN}/` : "/" ), routes: constantRoutes, scrollBehavior(to, from, savedPosition) { if (savedPosition) { return savedPosition; } return { top: 0 }; } }); export default router;
- 初始化應用
// main.js import { createApp } from "vue"; import { init } from "@/qiankun.js"; import App from "./App"; if (window.__POWERED_BY_QIANKUN__) { // eslint-disable-next-line no-undef __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; } const app = createApp(App); init(app);
vue2 + webpack
,路由模式為 hash
-
新建
qiankun
相關配置檔案- 配置
webpack
- 配置
// vue.config.js const { name } = require('./package'); module.exports = { // 開發跨域配置 devServer: { headers: { 'Access-Control-Allow-Origin': '*', }, }, configureWebpack: { output: { library: `${name}-[name]`, libraryTarget: 'umd', // 把微應用打包成 umd 庫格式 jsonpFunction: `webpackJsonp_${name}`, // webpack 5 需要把 jsonpFunction 替換成 chunkLoadingGlobal }, }, };
- 匯出對應的生命週期鉤子,以及初始化方式
// qiankun.js import App from './App' import router from './router' import store from './store' import { setToken, setAccessUser, } from "@/utils/auth"; let instance = null export function render(props = {}) { const { container } = props instance = new Vue({ router, store, render: h => h(App) }).$mount(container ? container.querySelector('#app') : '#app') } export async function bootstrap(props) { console.log('[vue] vue app bootstraped', props) } export async function mount(props, ...args) { console.log('[vue] props from main framework', props, args); setData(props) props.onGlobalStateChange((state, prev) => { // state: 變更後的狀態; prev 變更前的狀態 console.log("🚀 ~ props.onGlobalStateChange ~ state:", state) setData(state) }); render(props) } export async function unmount() { instance.$destroy() instance.$el.innerHTML = '' instance = null } // 拿到主應用傳過來的資料進行處理 function setData(state){ if(state['token']){ setToken(state.token) } if(state['accessUser']) { setAccessUser(state.accessUser) } } export default render
-
路由配置
// router/index.js import Router from 'vue-router' export const constantRouterMap = [ ... ] export default new Router({ scrollBehavior: () => ({ y: 0 }), base: window.__POWERED_BY_QIANKUN__ ? '/xxx/report/' : '/', routes: constantRouterMap })
- 初始化應用
import render from "./qiankun"; // 匯出所有的鉤子 export * from "./qiankun"; if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__; }else { // 獨立執行時 render(); }
總結
- 部署上線需要注意資源路徑的問題
- 不同伺服器下的專案需要處理跨域問題
qiankun
還有手動載入微應用的方式,暫時還沒有用到,可檢視官方文件
本文轉載於:https://juejin.cn/post/7395387245313163327
如果對您有所幫助,歡迎您點個關注,我會定時更新技術文件,大家一起討論學習,一起進步。