前端微服务无界实践 - 综合 -

当前位置:首页  >  综合  > 正文

前端微服务无界实践

前端微服务无界实践
2023-05-25 18:49:21 来源:博客园
一、前言

随着项目的发展,前端SPA应用的规模不断加大、业务代码耦合、编译慢,导致日常的维护难度日益增加。同时前端技术的发展迅猛,导致功能扩展吃力,重构成本高,稳定性低。因此前端微服务应运而生。

前端微服务优势

1.复杂度可控: 业务模块解耦,避免代码过大,保持较低的复杂度,便于维护与开发效率。


(资料图片仅供参考)

2.独立部署: 模块部署,减少模块影响范围,单个模块发生错误,不影响全局,提升项目稳定性。

3.技术选型灵活: 在同一项目下可以使用市面上所有前端技术栈,也包括未来的前端技术栈。

4.扩展性,提升业务动态扩展的可能,避免资源浪费

微前端服务结构技术对比和选型:
选型静态资源预加载子应用保活iframejs沙箱css沙箱接入成本地址
EMP×××https://github.com/efoxTeam/emp
Qiankun××中低https://qiankun.umijs.org/zh/
无界中低https://wujie-micro.github.io/doc/
micro-app××中低https://zeroing.jd.com/micro-app/

通过对比多种技术对项目的支持情况和项目接入的成本,我们最终选型无界。

二、wujie简单用法(以主应用使用vue框架为例)

主应用是vue框架可直接使用wujie-vue,react框架可直接使用wujie-react,先安装对应的插件哦

主应用改造:
// 引入无界,根据框架不同版本不同,引入不同的版本import { setupApp, bus, preloadApp, startApp } from "wujie-vue2"// 设置子应用默认参数setupApp({    name: "子应用id(唯一值)",    url: "子应用地址",    exec: true,    el: "容器",    sync: true})// 预加载preloadApp({ name: "唯一id"});// 启动子应用startApp({ name: "唯一id"});
子应用改造:1、跨域

子应用如果支持跨域,则不用修改

原因:存在请求子应用资源跨域

方案:因前端应用基本是前后端分离,使用proxy代理。只需配置在子应用配置允许跨域即可

// 本地配置server: {    host: "127.0.0.1", // 本地启动如果主子应用没处在同一个ip下,也存在跨域的问题,需要配置    headers: {        "Access-Control-Allow-Credentials": true,        "Access-Control-Allow-Origin": "*", // 如资源没有携带 cookie,需设置此属性        "Access-Control-Allow-Headers": "X-Requested-With,Content-Type",        "Access-Control-Allow-Methods": "*"    }}// nginx 配置add_header Access-Control-Allow-Credentials true;add_header Access-Control-Allow-Origin "*";add_header Access-Control-Allow-Headers "X-Requested-With,Content-Type";add_header Access-Control-Allow-Methods "*";
2、运行模式选择

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

(1)、保活模式(长存页面)

释义:类似于vue的keep-alive性质(子应用实例和webcomponent不销毁,状态、路由都不丢失,只做热webcomponent的热插拔),子应用不想做生命周期改造,子应用切换又不想有白屏时间,可以采用保活模式。主应用上有多个入口跳转到子应用的不同页面,不能采用保活模式,因为无法改变子应用路由。

配置:只需要在主应用加载子应用的时候,配置参数添加alive:true

效果:预加载+保活模式=页面数据请求和渲染提前完成,实现瞬间打开效果

(2)、单例模式

释义:子应用页面切走,会调用window.__WUJIE_UNMOUNT销毁子应用当前实例。子应用页面如果切换回来,会调用window.__WUJIE_MOUNT渲染子应用新的子应用实例。过程相当于:销毁当前应用实例 => 同步新路由 => 创建新应用实例

配置:只需要在主应用加载子应用的时候,配置参数添加alive:false

改造生命周期

// window.__POWERED_BY_WUJIE__用来判断子应用是否在无界的环境中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");} 

(3)、重建模式

释义:每次页面切换销毁子应用webcomponent+js的iframe。

配置:只需要在主应用加载子应用的时候,配置参数添加alive:false

无生命周期改造

备注:非webpack打包的老项目,子应用切换可能出现白屏,应尽可能使用保活模式降低白屏时间

三、加载模块(主应用配置)子应用基础信息管理
// subList.js 数据可在配置页面动态配置const subList = [    {        "name":"subVueApp1",        "exec":true,// false只会预加载子应用的资源,true时预执行子应用代码        "alive": true,        "show":true,// 是否引入        "url":{            "pre":"http://xxx1-pre.com",            "gray":"http://xxx1-gray.com",            "prod":"http://xxx1.com"        }    },    {        "name":"subVueApp2",        "exec":false,// false只会预加载子应用的资源,true时预执行子应用代码        "alive": false,        "show":true,// 是否引入        "url":{            "pre":"http://xxx2-pre.com",            "gray":"http://xxx2-gray.com",            "prod":"http://xxx2.com"        }    }]export default subList;
// hostMap.jsimport subList from "./subList" const env = process.env.mode || "pre"// 子应用map结构const subMap = {}const subArr = []// 转换子应用export const hostMap = () => {    subList.forEach(v => {        const {url, ...other} = v        const info = {            ...other,            url: url[env]        }       subMap[v.name] = info       subArr.push(info)    })   return subArr}// 获取子应用配置信息export const getSubMap = name => {    return subMap[name].show ? subMap[name] : {}}
子应用注册预加载和启动
// setupApp.jsimport WujieVue from "wujie-vue2";import {hostMap} from "./hostMap";const { setupApp, preloadApp } = WujieVue const setUpApp = Vue => {    Vue.use(WujieVue)    hostMap().forEach(v => {        setupApp(v)        preloadApp(v.name)    })}export default setUpApp;// main.jsimport Vue from "vue"import setUpApp from"@/microConfig/setupApp"setUpApp(Vue)
配置公共函数

全子应用共享的生命周期函数,可用于执行多个子应用间相同的逻辑操作函数共同处理

// lifecycle.jsconst 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;// subCommon.js// 跳转到主应用指定页面const toJumpMasterApp = (location, query) => {        this.$router.replace(location, query);    const url = new URL(window.location.href);    url.search = query    // 手动的挂载url查询参数    window.history.replaceState(null, "", url.href);}// 跳转到子应用的页面const toJumpSubApp = (appName, query) => {   this.$router.push({path: appName}, query)}export default {    toJumpMasterApp,    toJumpSubApp }// setupApp.jsimport lifecycles from "./lifecycles";import subCommon from "./subCommon";const setUpApp = Vue => {    ....    hostMap().forEach(v => {        setupApp({            ...v,            ...lifecycles,            props: subCommon        })        preloadApp(v.name)    })}
主应用加载子应用页面
// 子应用页面加载// app1.vue<script>import wujieVue from "wujie-vue2";import {getSubMap} from "../../hostMap";const name = "subVueApp1"export default {    data() {       return {          dataProps: [],          subVueApp1Info: getSubMap(name)       }    },    computed: {      appUrl() {        // return getSubMap("subVueApp1").url        return this.subVueApp1Info.url + this.$route.params.path      }    },     watch: {        // 如果子应用是保活模式,可以采用通信的方式告知路由变化        "$route.params.path": {          handler: function () {            wujieVue.bus.$emit("vue-router-change", `/${this.$route.params.path}`);          },          immediate: true,        },      },    methods: {        propsMethod() {}    }}</script>
四、子应用配置

无界的插件体系主要是方便用户在运行时去修改子应用代码从而避免去改动仓库代码

// plugins.jsconst plugins = {  "subVueApp1": [{    htmlLoader:code => {      return code;    },    cssAfterLoaders: [      // 在加载html所有样式之后添加一个外联样式      { src:"https://xxx/xxx.css" },      // 在加载html所有样式之后添加一个内联样式      { content:"img{height: 300px}" }    ],    jsAfterLoaders: [      { src:"http://xxx/xxx.js" },      // 插入一个内联脚本本      { content:`          window.$wujie.bus.$on("routeChange", path => {          console.log(path, window, self, global, location)          })`      },      // 执行一个回调      {        callback(appWindow) {          console.log(appWindow.__WUJIE.id);        }      }    ]  }],  "subVueApp2": [{    htmlLoader: code=> {      return code;    }  }]};export default plugins;
// setupApp.jsimport plugins from "./plugins";const setUpApp = Vue => {    ......    hostMap().forEach(v => {        setupApp({            ...v,            plugins: plugins[element.name]        })        ......    })}
五、数据传输和消息通信数据交互方式

1,通过props进行传

2、通过window进线传达

3,通过事件bus进行传达

props

主应用通过data传参给子应用, 子应用通过methods方法传参给主应用

// 主应用// 子应用const props = window.$wujie?.props; // {data: xxx, methods: xxx}
window

利用子应用运行在主应用的iframe

类似iframe的传参和调用

// 主应用获取子应用的全局变量数据window.document.querySelector("iframe[name=子应用id]").contentWindow.xxx;//子应用获取主应用的全局变量数据window.parent.xxx;
eventBus

去中心化的通信方案,方便。类似于组件间的通信

主应用

// 使用 wujie-vueimport WujieVue from"wujie-vue";const{ bus }= WujieVue;// 主应用监听事件bus.$on("事件名字",function(arg1,arg2, ...){});// 主应用发送事件bus.$emit("事件名字", arg1, arg2,...);// 主应用取消事件监听bus.$off("事件名字",function(arg1,arg2, ...){});

子应用

// 子应用监听事件window.$wujie?.bus.$on("事件名字",function(arg1,arg2, ...){});// 子应用发送事件window.$wujie?.bus.$emit("事件名字", arg1, arg2,...);// 子应用取消事件监听window.$wujie?.bus.$off("事件名字",function(arg1,arg2, ...){});
规范主子应用传递规则

规则:子应用名+事件名

主应用向子应用传参

// 主应用传参bus.$emit("matser", options) // 主应用向所有子应用传参bus.$emit("vite:getOptions", options) // 主应用向指定子应用传参//子应用监听主应用事件window?.$wujie?.bus.$on("master", (options) => {  console.log(options)});//子应用监听主应用特定通知子应用事件window?.$wujie?.bus.$on("vite:getOptions", (options) => {  console.log(options)});
六、路由

以 vue 主应用为例,子应用 A 的 name 为 A, 主应用 A 页面的路径为/pathA,子应用 B 的 name 为 B,主应用 B 页面的路径为/pathB为例

主应用统一props传入跳转函数

jump (location) {  this.$router.push(location);}
1、主应用history路由子应用 B 为非保活应用

1、子应用A 只能跳转到子应用 B 的主应用的默认路由

function handleJump(){   window.$wujie?.props.jump({ path:"/pathB"});}

2、子应用A 只能跳转到子应用B 应用的指定路由(非默认路由)

// 子应用A点击跳转处理函数, 子应用B需开启路由同步function handleJump(){    window.$wujie?.props.jump({ path:"/pathB", query:{ B:"/test"}});}
子应用 B 为保活应用

子应用A 只能跳转到子应用 B 的主应用的路由

可写入主应用的插件中,主应用插件根据不同的应用,引入不同方法

// 子应用 A 点击跳转处理函数function handleJump() {  window.$wujie?.bus.$emit("routeChange", "/test");}// 子应用 B 监听并跳转window.$wujie?.bus.$on("routeChange", (path) => this.$router.push({ path }));
2、主应用hash路由子应用 B 为非保活应用

1、子应用A 只能跳转到子应用 B 的主应用的默认路由

同子应用B为非保活应用,子应用A跳转到子应用 B 的主应用的默认路由

2、子应用A 只能跳转到子应用B 应用的指定路由(非默认路由)

主应用jump(location,query){     // 跳转到主应用B页面    this.$router.push(location);     const url=new URL(window.location.href);    url.search=query    // 手动的挂载url查询参数    window.history.replaceState(null,"",url.href);}// 子应用 B 开启路由同步能力// 子应用Afunction handleJump() {  window.$wujie?.props.jump({ path: "/pathB" } , `?B=${window.encodeURIComponent("/test")}`});}
子应用 B 为保活应用

同子应用B为保活应用,子应用A跳转到子应用 B 路由

// bus.js// 在 xxx-sub 路由下子应用将激活路由同步给主应用,主应用跳转对应路由高亮菜单栏  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 });      }  });
七、部署

前端单页面的部署,不管怎么自动化,工具怎么变. 都是把打包好的静态文件,放到服务器的正确位置下。所以支持项目的独立部署和混合部署。

作者:京东物流 张燕燕 刘海鼎

内容来源:京东云开发者社区

标签:

(责任编辑:news01)
人类与自然界中的动物都存在生殖隔离?如果是,意味着什么?

人类与自然界中的动物都存在生殖隔离?如果是,意味着什么?

人类是一种高度进化的生物,和其他生物之间存在着各种隔离,其中生殖隔离是其中之一。生殖隔离是指不同种群
05-23 12:28:53
《洛奇英雄传》烈日下的清凉 夏日时装今日上新 全球播报

《洛奇英雄传》烈日下的清凉 夏日时装今日上新 全球播报

在5月23日维护后至6月20日维护前,《洛奇英雄传》中的“2023女神的馈赠V”限时上架,英雄们可从中获得时尚
05-23 12:00:57
今年1至4月 贵阳住房公积金缴存额48.01亿元 全球速看

今年1至4月 贵阳住房公积金缴存额48.01亿元 全球速看

央广网贵阳5月23日消息(记者任振国)近日,贵阳市住房公积金中心公布今年1至4月统计报告,报告显示,今年1
05-23 11:14:35
珠峰再次发现“史前海怪”! 环球新消息

珠峰再次发现“史前海怪”! 环球新消息

第二次青藏高原综合科学考察的科考人员近日在珠穆朗玛峰地区发现新的喜马拉雅鱼龙化石。
05-23 10:24:17
热推荐:《中国藏族文化艺术彩绘大观》:巨幅长卷 一眼千年

热推荐:《中国藏族文化艺术彩绘大观》:巨幅长卷 一眼千年

《中国藏族文化艺术彩绘大观》:巨幅长卷一眼千年---“没错,右上角的汉式建筑代指长安,这幅唐卡生动展...
05-23 09:54:07
热搜第一!空乘歧视非英语旅客?国泰航空就旅客不愉快经历道歉:严肃调查处理 环球信息

热搜第一!空乘歧视非英语旅客?国泰航空就旅客不愉快经历道歉:严肃调查处理 环球信息

今日(5月23日),国泰航空致歉的话题冲上热搜第一,引发网友关注。近日,有网友在网络平台举报国泰航空空
05-23 09:17:31
安徽启动县域生物多样性本底调查 力争“十四五”末摸清“家底”

安徽启动县域生物多样性本底调查 力争“十四五”末摸清“家底”

人民网合肥5月22日电(记者陈浩)“启动全省县域生物多样性本地调查、观测和评估工作,力争‘十四五’末...
05-23 08:48:02
比尔盖茨被曝婚内出轨俄年轻女牌手,还因婚外情遭爱泼斯坦要挟?

比尔盖茨被曝婚内出轨俄年轻女牌手,还因婚外情遭爱泼斯坦要挟?

【环球时报特约记者刘皓然】美国微软公司创始人比尔·盖茨再次被爆曾婚内出轨,出轨对象是一名当时仅20...
05-23 08:00:11
最新快讯!前四月新增各类品牌首店三百七十五家 上海做强首发经济释放消费活力

最新快讯!前四月新增各类品牌首店三百七十五家 上海做强首发经济释放消费活力

作为上海第四届“五五购物节”最受关注的标杆活动,“上海全球新品首发季”近日在静安区“海上第一名园...
05-23 06:14:35
世界微笑日发朋友圈说说_世界微笑日朋友圈文案

世界微笑日发朋友圈说说_世界微笑日朋友圈文案

世界微笑日发朋友圈说说,世界微笑日朋友圈文案很多人还不知道,现在让我们一起来看看吧!1、在世界微笑日
05-23 05:00:17
制度范文集锦--职工奖惩条例

制度范文集锦--职工奖惩条例

职工奖惩条例为维护公司劳动纪律和各项制度,保障公司工作的正常进行,激励职工的敬业精神,特制定本条例。
05-23 02:08:44
重庆首批地方法人银行碳减排支持工具落地

重庆首批地方法人银行碳减排支持工具落地

华龙网–新重庆客户端讯(林红)5月22日,人民银行重庆营业管理部宣布已发放首批地方法人银行碳减排支持工
05-22 23:10:33
我国科考队再次发现史前“海上霸主”化石,比恐龙还早……-世界独家

我国科考队再次发现史前“海上霸主”化石,比恐龙还早……-世界独家

再次发现!珠峰地区发现新的喜马拉雅鱼龙化石
05-22 22:10:32
。。。。。。好家伙,这三个人名字真熟悉![叹气]... 天天微资讯

。。。。。。好家伙,这三个人名字真熟悉![叹气]... 天天微资讯

。。。。。。好家伙,这三个人名字真熟悉![叹气]本赛季英超联赛,射门次数超过60次的球员里,转化率最差的
05-22 21:27:25
天天播报:炖排骨要焯水吗(炖排骨要焯水吗怎么处理最好)

天天播报:炖排骨要焯水吗(炖排骨要焯水吗怎么处理最好)

炖排骨需要焯水。排骨经过焯水后,可以有效去除排骨里面的血水和杂质,这样会使得做出来的排骨肉更鲜香,汤
05-22 20:31:57
外交部亚洲司司长刘劲松同韩方举行外交磋商

外交部亚洲司司长刘劲松同韩方举行外交磋商

2023年5月22日,外交部亚洲司司长刘劲松在首尔同韩国外交部东北亚局局长崔容准举行外交磋商,就中方核心关
05-22 19:56:30
叶公好龙寓意_告诉了我们什么道理

叶公好龙寓意_告诉了我们什么道理

欢迎观看本篇文章,小柴来为大家解答以上问题。叶公好龙寓意,告诉了我们什么道理很多人还不知道,现在让我
05-22 19:08:29
川观科考队㉕丨国际生物多样性日走进“植物王国” 这些濒危植物也太美了!|今日精选

川观科考队㉕丨国际生物多样性日走进“植物王国” 这些濒危植物也太美了!|今日精选

本期川观科考队来到海拔约800米的峨眉山生物站。
05-22 18:13:24
速递!日本民众:七国集团强推规则 破坏地区稳定

速递!日本民众:七国集团强推规则 破坏地区稳定

七国集团峰会闭幕当天,不少民众在日本首都东京街头自发组织集会,抗议七国集团只代表少数发达国家利益,无
05-22 17:57:34
快手一季度总营收增长19.7%至252.2亿元 上市后首次实现集团整体盈利

快手一季度总营收增长19.7%至252.2亿元 上市后首次实现集团整体盈利

转自:上海证券报上证报中国证券网讯(记者罗茂林)5月22日,快手发布2023年第一季度业绩,总营收同比增长1
05-22 17:21:19
火山活动致墨西哥两座机场暂时关闭

火山活动致墨西哥两座机场暂时关闭

因受到波波卡特佩特火山活动影响,墨西哥两座机场20日暂时关闭。墨西哥城国际机场社交媒体官方账号当天发布
05-22 16:49:38
8路硬盘录像机多少钱 最新的8路硬盘录像机报价大全 天天热讯

8路硬盘录像机多少钱 最新的8路硬盘录像机报价大全 天天热讯

在我们的日常生活中,数码产品的普及率是相当的高了。各式的数码产品在我们的生活中都充当着重要的角色,这
05-22 16:19:14
乐华因合同纠纷被冻结2390万元财产 究竟到底发生了什么?

乐华因合同纠纷被冻结2390万元财产 究竟到底发生了什么?

今天,乐华娱乐被处罚的消息沸沸扬扬,虽然没有详情披露其中的原因,但网友的猜测也八九不离十,毕竟从处罚
05-22 15:35:00
全球微速讯:顺丰向左,极兔向右,红海鏖战再起

全球微速讯:顺丰向左,极兔向右,红海鏖战再起

天下大势,合久必分、分久必合,快递行业亦是如此。5月12日,顺丰突然宣布同极兔速递签署协议,将旗下子公
05-22 14:57:33
环球资讯:闫瑞祥:上周五黄金如期上涨,今日暂时关注延续

环球资讯:闫瑞祥:上周五黄金如期上涨,今日暂时关注延续

【黄金】黄金方面上周五市场整体呈现上涨的状态当日价格最高于198407位置最低下跌至195387位置晚间收盘于19
05-22 14:19:07
全球热点评!@成都,一起比个“心”吧!

全球热点评!@成都,一起比个“心”吧!

如果用花花,让五月的昆明和成都为爱注解,不是娇艳的玫瑰,也不是纯洁的百合,而是那一簇簇、一团团的蓝花
05-22 13:47:58
全球播报:现代纸的种类有哪些_纸的种类有哪些

全球播报:现代纸的种类有哪些_纸的种类有哪些

1、纸的品种很多,分类方法也不一致。2、习惯分类方法有3种。3、①按生产方式分为手工纸和机制纸。4、
05-22 12:16:06
【天天速看料】小米Civi 3官宣5月25日发布、号称“新潮流手机的黎明”

【天天速看料】小米Civi 3官宣5月25日发布、号称“新潮流手机的黎明”

5月22日消息,今天小米官方宣布即将于5月25日正式发布小米Civi3新机,该款手机号称“新潮流手机的黎明”...
05-22 11:33:01
廖茂富 | 冷冻电镜在新科研领域的拓荒人|时讯

廖茂富 | 冷冻电镜在新科研领域的拓荒人|时讯

如果说人体是一台精密的仪器,那么疾病就是出现的故障。人类追求健康,却摆脱不了疾病的存在。以前,古人认
05-22 11:11:35
g70高速是哪条高速公路_g70高速_当前关注

g70高速是哪条高速公路_g70高速_当前关注

1、G70福银高速甘肃141 530凤翔路口(甘陕界)1864 000沿川子(甘宁界)2005 530约311
05-22 10:38:25

为您推荐

精彩推送