# wujie-test **Repository Path**: gitee654764771/wujie-test ## Basic Information - **Project Name**: wujie-test - **Description**: 基于wujie实现的前端微应用架构。 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: https://bidding-m.gitee.io/wujie-test/main/ - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2024-09-27 - **Last Updated**: 2024-09-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # wujie-test ## 介绍 基于wujie实现的前端微应用架构。 ## 安装教程 ```shell yarn ``` ## 使用说明 ### 一、主应用 #### 1、wujie方式 + 安装依赖包 ```shell yarn add wujie ``` + main.js ```javascript import {bus, setupApp, preloadApp, startApp, destroyApp} from "wujie"; import hostMap from "./hostMap"; // wujie 子路由注册 import credentialsFetch from "./fetch"; import lifecycles from "./lifecycle"; // wujie lifecycle import plugins from "./plugin"; // wujie plugin // 在子应用模块路由激活时将路由同步给主应用,主应用跳转对应路由高亮菜单栏 bus.$on("sub-route-change", (name, path) => { const mainName = `${name}-sub`; const mainPath = `/${name}-sub{path}`; const currentName = router.currentRoute.name; const currentPath = router.currentRoute.path; if (mainName === currentName && mainPath !== currentPath) { router.push({path: mainPath}); } }); // 是否降级处理 const degrade = window.localStorage.getItem("degrade") === "true" || !window.Proxy || !window.CustomElementRegistry; // 传递给子应用的props const props = { jump: (name) => { router.push({name}); }, }; /** * 配置应用,主要是设置默认配置 * preloadApp、startApp的配置会基于这个配置做覆盖 */ setupApp({ name: "mapbox", url: hostMap("//localhost:10030/mapbox-test/"), exec: true, props, // fetch: credentialsFetch, degrade, ...lifecycles, }); setupApp({ name: "maptalks", url: hostMap("//localhost:10040/maptalks-test/"), exec: true, alive: true, // 保活模式 props, // fetch: credentialsFetch, degrade, ...lifecycles, }); // 预加载设置 if (window.localStorage.getItem("preload") !== "false") { preloadApp({ name: "mapbox", }); if (window.Proxy) { preloadApp({ name: "maptalks", }); } } // 启动子应用 startApp({name: "mapbox"}); ``` + hostMap.js ```javascript const map = { "//localhost:10030/mapbox-test/": "https://bidding-m.gitee.io/mapbox-test/", "//localhost:10040/maptalks-test/": "https://bidding-m.gitee.io/maptalks-test-next/", "//localhost:8080/": "//localhost:8080/", }; export default function hostMap(host) { if (process.env.NODE_ENV === "production") return map[host]; return host; } ``` + fetch.js ```javascript // 携带登录态credentials必须为include export default function fetch(url, options) { return window.fetch(url, {...options, credentials: "omit"}); } ``` + lifecycle.js ```javascript export default { beforeLoad: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeLoad 生命周期`), beforeMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeMount 生命周期`), afterMount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterMount 生命周期`), beforeUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} beforeUnmount 生命周期`), afterUnmount: (appWindow) => console.log(`${appWindow.__WUJIE.id} afterUnmount 生命周期`), activated: (appWindow) => console.log(`${appWindow.__WUJIE.id} activated 生命周期`), deactivated: (appWindow) => console.log(`${appWindow.__WUJIE.id} deactivated 生命周期`), loadError: (url, e) => console.log(`${url} 加载失败`, e), }; ``` + plugin.js ```javascript export default [ { htmlLoader: (code) => { console.log("html-loader"); return code; }, jsBeforeLoaders: [ { callback(appWindow) { console.log("js-before-loader-callback", appWindow.__WUJIE.id); }, }, ], jsLoader: (code, url) => { console.log("js-loader", url); return code; }, jsAfterLoaders: [ { callback(appWindow) { console.log("js-after-loader-callback", appWindow.__WUJIE.id); }, }, ], cssBeforeLoaders: [ //在加载html所有的样式之前添加一个外联样式 {src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/HDaBURp7.css"}, //在加载html所有的样式之前添加一个内联样式 {content: "img{width: 300px}"}, ], cssLoader: (code, url) => { console.log("css-loader", url, code.slice(0, 50) + "..."); return code; }, cssAfterLoaders: [ //在加载html所有样式之后添加一个外联样式 {src: "https://vfiles.gtimg.cn/wuji_dashboard/xy/test_wuji_damy/FQsK8IN6.css"}, //在加载html所有样式之后添加一个内联样式 {content: "img{height: 300px}"}, ], }, ]; ``` #### 2、组件方式(wujie-vue2、wujie-vue3) + 安装依赖包 ```shell yarn add wujie-vue2 ``` + main.js ```javascript // 引入wujie import WujieVue from "wujie-vue2"; Vue.use(WujieVue) ``` + 路由注册跳转 ```vue ``` ### 二、子应用 > 子应用在满足跨域条件下可以不用改造 #### 1、前提 ```javascript module.exports = { outputDir: `../dist/${packageName}`, publicPath: process.env.VUE_APP_BASE_URL, configureWebpack: { resolve: { alias: { "src": "@", } }, output: { library: `${packageName}-[name]`, libraryTarget: 'umd', // 把微应用打包成 umd 库格式 }, }, devServer: { headers: { 'Access-Control-Allow-Origin': '*', // 主应用获取子应用时跨域响应头 "Access-Control-Allow-Headers": "*", "Access-Control-Allow-Methods": "*", }, } } ``` #### 2、[运行模式](https://wujie-micro.github.io/doc/guide/mode.html) > 三种运行模式:单例模式、保活模式、重建模式 > 其中保活模式、重建模式子应用无需做任何改造工作 > 单例模式需要做生命周期改造 + vue2 ```javascript // main.js if (window.__POWERED_BY_WUJIE__) { let instance; window.__WUJIE_MOUNT = () => { const router = new VueRouter({routes}); instance = new Vue({router, render: (h) => h(App)}).$mount("#app"); }; window.__WUJIE_UNMOUNT = () => { instance.$destroy(); }; } else { new Vue({router: new VueRouter({routes}), render: (h) => h(App)}).$mount("#app"); } ``` + vue3 ```javascript // main.js if (window.__POWERED_BY_WUJIE__) { let instance; window.__WUJIE_MOUNT = () => { const router = createRouter({history: createWebHistory(), routes}); instance = createApp(App); instance.use(router); instance.mount("#app"); }; window.__WUJIE_UNMOUNT = () => { instance.unmount(); }; } else { createApp(App).use(createRouter({history: createWebHistory(), routes})).mount("#app"); } ``` + vite ```typescript // main.ts 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"); } ``` ### 三、[应用间通信](https://wujie-micro.github.io/doc/guide/communication.html) #### 1、props + 主应用通过 props 属性注入的方法 > 主应用通过 props 注入 jump(跳转页面)方法,子应用通过 $wujie.props.jump(xxx) 来使用 #### 2、 window.parent + 通过 window.parent 方法拿到主应用的全局方法 > 子应用调用 window.parent.alert 来调用主应用的 alert方法 #### 3、bus + 通过 bus 方法发送去中心化的事件 > 主应用 bus.$on("click", (msg) => window.alert(msg)) 监听子应用的 click 事件 > 子应用点击按钮 $wujie.bus.$emit('click', 'vue2') 发送 click 事件