WuJie无界微前端使用和问题解决

我正在参加「金石计划5.0」

一、WuJie无界微前端

1.WuJie说明

说明文档:wujie-micro.github.io/doc/guide/

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。

通俗来说,就是在一个web应用中可以独立的运行另一个web应用

微前端有什么使用场景呢?

举例

  • 比如制作一个企业管理平台,把已有的采购系统和财务系统统一接入这个平台;
  • 比如有一个巨大的应用,为了降低开发和维护成本,分拆成多个小应用进行开发和部署,然后用一个平台将这些小应用集成起来;
  • 又比如一个应用使用vue框架开发,其中有一个比较独立的模块,开发者想尝试使用react框架来开发,等模块单独开发部署完,再把这个模块应用接回去

可能有人会有疑问直接使用iframe不就可以做到吗?

采用iframe的方案确实可以做到,而且优点非常明显

优点

  • 非常简单,使用没有任何心智负担
  • web应用隔离的非常完美,无论是jscssdom都完全隔离开来

由于其隔离的太完美导致缺点也非常明显

缺点

  • 路由状态丢失,刷新一下,iframeurl状态就丢失了
  • dom割裂严重,弹窗只能在iframe内部展示,无法覆盖全局
  • web应用之间通信非常困难
  • 每次打开白屏时间太长,对于SPA 应用来说无法接受

WuJie无界的方案,就是为了解决iframe存在的问题,而且还能带来更多的优势,详情可以查看WuJie无界官方指导文档。

2.WuJie快速上手

2.1主应用

1.安装wujie依赖

bash 复制代码
# vue2 框架
npm i wujie-vue2 -S

# vue3 框架
# npm i wujie-vue3 -S

注意:使用vue的框架,是2还是3

2.main.js引入wujie

javascript 复制代码
//引入无界微前端
// vue2
import WujieVue from "wujie-vue2";
// vue3
// import WujieVue from "wujie-vue3";

import lifecycles from "../config/lifecycle";
const { setupApp, preloadApp, bus } = WujieVue;
Vue.use(WujieVue);
const props = {
    jump: (name) => {
        router.push({ name });
    },
};

//设置子应用demo
setupApp({
    name: "demo",
    url: "/demo/home/index",
    exec: true,
    props,
    fetch: function fetch(url, options) {
        //console.log("fetch.url:=",url,options)
        return window.fetch(url, { ...options, credentials: "omit" });
    },
    ...lifecycles,
});

// 预加载
//preloadApp({
//    name: "demo",
//});

注意:setupApp 设置子应用的namepreloadApp 设置的name要一致。

预加载,可以极大的提升子应用首次打开速度

  • 资源的预加载会占用主应用的网络线程池
  • 资源的预执行会阻塞主应用的渲染线程
    一般来说,如果不是很介意打开的首屏时间,这里预加载可以不用加。
  • lifecycle.js
javascript 复制代码
const lifecycles = {
    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),
};
export default lifecycles;

这个是生命周期函数

无界提供一整套的生命周期钩子供开发者调用

如果子应用没有做生命周期的改造,那么 beforeMount、afterMount、beforeUnmount、afterUnmount 这四个生命周期将不会调用

2.2子应用

子应用改造,无界对子应用的侵入非常小,在满足跨域条件下子应用可以不用改造

子应用的资源和接口的请求都在主域名发起,所以会有跨域问题。

所以这里,主应用和子应用,建议使用nginx进行代理,解决跨域的问题。

php 复制代码
//主应用
location /main {
    proxy_set_header Host    $host;
    proxy_pass http://127.0.0.1:8080;
}

//子应用
location /demo {
    proxy_set_header Host    $host;
    proxy_pass http://127.0.0.1:8081;
}
  • 运行模式

无界有三种运行模式:单例模式保活模式重建模式

其中保活模式重建模式子应用无需做任何改造工作,单例模式需要做生命周期改造

改造入口函数:

  • 将子应用路由的创建、实例的创建渲染挂载到window.__WUJIE_MOUNT函数上
  • 将实例的销毁挂载到window.__WUJIE_UNMOUNT
  • 如果子应用的实例化是在异步函数中进行的,在定义完生命周期函数后,请务必主动调用无界的渲染函数 window.__WUJIE.mount()
  • vue2
javascript 复制代码
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
ini 复制代码
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");
}

注意:使用vue的框架,是2还是3

2.3wujie使用

经过上面主应用和子应用的改造之后,就可以再主应用中,使用wujie,将子应用引入到主应用中去。

主应用,有这样的一个vue组件

  • wujieDemo.vue 页面使用WujieVue引用目标项目的页面
xml 复制代码
<template> 
    <WujieVue
            width="100%"
            height="100%"
            name="demo"
            :url="demoUrl"
        />
</template>
​
<script>
 export default {
  data() {
    return {
        demoUrl: '/demo/home/index',
    }
  },
</script>

注意,上面 WujieVue 使用的name要和 setupApp 设置的name,要对应。

3.集成问题处理

3.1 window.parent问题

如果你集成的子应用中,也有用到iframe,那么在iframe中,使用window.parent,这个获取到的,不再是子应用了,这个window.parent将会是主应用

出现这个问题,就是你可能会将一些对象,放入到window里面,那这个时候,需要兼容下这个情况。

例如:

ini 复制代码
window.Demo = {}

//这个时候,需要再加上
window.parent.Demo = window.Demo; //这个的作用,是将Demo这个对象赋值给 "主应用"

这样,在iframe中,使用window.parent.demo,就不会出现null的问题了。

3.2 antdv出现message不显示问题

出现这个问题,是在第一次打开子应用后,关闭后,重新再打开子应用。message消息提示框,无法显示。

出这个问题,是因为子应用,进行了生命周期改造导致。

所以这里,不建议对子应用进行生命周期改造。

...

还有很多问题,不知道怎么解决,也解决不了,最后还是放弃了...

4.写在最后

由于在整合的时候,遇到了不少问题,最后还是放弃了这个方式。

改用回iframe的方式,世界瞬间都清净了。

wujie你强任你强,我放弃了,放手一撑,与世无争


好了,以上就是我个人的实操了。可能有些不对,大家伙,轻点喷!!!

个人理解,可能也不够全面,班门弄斧了。

好了,今天就先到这里了!!!^_^

如果觉得有收获的,帮忙点赞、评论、收藏一下,再走呗!!!

相关推荐
小小竹子3 分钟前
前端vue-实现富文本组件
前端·vue.js·富文本
小白小白从不日白12 分钟前
react hooks--useReducer
前端·javascript·react.js
下雪天的夏风24 分钟前
TS - tsconfig.json 和 tsconfig.node.json 的关系,如何在TS 中使用 JS 不报错
前端·javascript·typescript
青稞儿30 分钟前
面试题高频之token无感刷新(vue3+node.js)
vue.js·node.js
diygwcom36 分钟前
electron-updater实现electron全量版本更新
前端·javascript·electron
Hello-Mr.Wang1 小时前
vue3中开发引导页的方法
开发语言·前端·javascript
程序员凡尘1 小时前
完美解决 Array 方法 (map/filter/reduce) 不按预期工作 的正确解决方法,亲测有效!!!
前端·javascript·vue.js
编程零零七5 小时前
Python数据分析工具(三):pymssql的用法
开发语言·前端·数据库·python·oracle·数据分析·pymssql
(⊙o⊙)~哦7 小时前
JavaScript substring() 方法
前端
无心使然云中漫步7 小时前
GIS OGC之WMTS地图服务,通过Capabilities XML描述文档,获取matrixIds,origin,计算resolutions
前端·javascript