# 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 事件