浅入深出的微前端MicroApp
前言:
本文是由最近做的一个项目有感而发,因为之前做了一些技术栈的统一,为了用ant Design的pro-table,PC统一使用react,但是我们有一些老的项目是vue的,本次新页面较多,老页面的改动较少,除此之外老项目想换菜单,因此我们想借助本次机会用react开发,经过了几番思考,发现本次很适合用微前端来完成本次需求,最终决定用react搭建一个基座(主应用),将原来的vue项目接入到基座,这样我们不仅实现了新页面react开发,而且老项目也能和新项目融合一起。
微前端的概念
什么是微前端?微前端是借鉴了微服务的架构理念,它既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性,相比一整块的前端仓库,微前端架构下的前端仓库倾向于更小更灵活。有一个基座应用(主应用),来管理各个子应用的加载和卸载。所以微前端不是指具体的库,不是指具体的框架,不是指具体的工具,而是一种理想与架构模式。微前端的核心三大原则:独立运行、独立部署、独立开发。
何时使用微前端
(1)一个非常庞大的项目,越来越大,后续难以维护。
(2)在一些大厂,经常会有跨部门和跨团队协作开发项目,这样会导致团队效率降低和沟通成本加大,这时我们可以使用微前端,每个团队或者每个部门单独维护自己的项目,我们只需要一个主项目来把分散的子项目汇集到一起即可。
(3)一个非常老旧的项目,开发效率低,但是一时半会又不能全部重构,这时我们就可以新创建一个新技术新项目的基座,把老项目的页面接入到新项目里面,后面新需求都在新项目里面开发就好,不用再动老项目。
(4)想独立部署每一个单页面应用。
(5)改善初始化加载时间,延迟加载代码。
(6)基于多页的子应用缺乏管理,规范/标准不统一,无法统一控制视觉呈现、共享的功能和依赖。造成重复工作。
如何创建微前端基座
一、微前端框架选型
(1)现有框架
- single-spa是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架。
2.qiankun 是一款基于 single-spa 封装的微前端框架。
- MicroApp 京东出品,一款基于WebComponent的思想,轻量、高效、功能强大的微前端框架。
我们本次项目使用的是umi+react+ts的技术栈,其实比较适合用qiankun,qiankun继承了umi框架,但是这个框架配置起来比较麻烦,其次就是MicroApp 是京东旗下的。
(2)****MicroApp 优势
1、使用起来成本最低,将所有的封装到一个类WebComponent组件中,从而实现在主应用基座中嵌入一行代码即可渲染一个微前端应用。
2、不需要像 single-spa 和 qiankun 一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案。
3、提供了 js沙箱、样式隔离、元素隔离、预加载、数据通信、静态资源补全等一系列完善的功能。
4、没有任何依赖,这赋予它小巧的体积和更高的扩展性。
5、为了保证各个业务之间独立开发、独立部署的能力,micro-app做了诸多兼容,在任何技术框架中都可以正常运行。
(3)****MicroApp 概念图
二、场景演示
以后台管理系统为例
最外层是基座,基座是微前端应用集成的一个重要平台。同时也肩负着管理公共资源、依赖、规范的责任。主要有以下职责:
(1)子应用集成,给子应用提供渲染容器
(2)权限管理
(3)会话管理
(4)路由、菜单管理
(5)主题管理
(6)共享依赖
(7)多语言管理(最重要的一点)等
content里面可以任意放不同技术的子应用,我们只需要开发一个主应用(主应用也可以自由选择语言,目前支持react、vue、vite、angular、next.js、nuxt.js),将一些分散的应用接进来,主应用还可以通过控制权限,让不同的账号看到的菜单不一样,即看到不同系统的页面,通过同一个地址访问到不同的子应用。
三、搭建微前端基座
以react基座为例
1、创建项目
(1)首先确保本地node版本>= 14(推荐用nvm来管理 node 版本,windows 下推荐用nvm-windows)
(2)通过官网提供命令可以快速创建一个基于 UMI 的项目作为主应用也就是我们所谓的基座
(3)安装依赖
npm i @micro-zoe/micro-app --save
package.json文件里面dependencies里面会多一行代码,看到下面代码恭喜你,项目已经具备micro-app接入能力了。
"@micro-zoe/micro-app": "^1.0.0-alpha.7"
(4)在入口引入我们的micro-app
首先在根目录下创建一个global.tsx文件
import microApp from '@micro-zoe/micro-app'
microApp.start()
(5)在主应用引入子应用
a. 分配一个子应用路由
{
path: '/yp',
name: 'yp',
linkHidden: true,
linkDisable: true,
breadcrumbClose: true,
component: '@/pages/yp-app',
}
b. 子应用的文件
在pages文件下创建一个yp-app(子应用的文件)
// name(必传):应用名称 // url(必传):应用地址,会被自动补全为http://localhost:3000/index.html
import React from 'react';
import config from '@/config';
// /** @jsxRuntime classic */
// /** @jsx jsxCustomEvent */
// import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event';
export default (): React.ReactElement => {
// 子应用点击了面包屑的回到首页
const onDispathChild = (e: any) => {
const { isBackHome } = e.detail.data;
if (isBackHome) window.location.href = '/';
};
return (
<>
<micro-app name="yp" url={config?.yp} onDataChange={onDispathChild} />
</>
);
};
说明:onDataChange方法是子应用和主应用的信息通讯方法。micro-app 在 window 下面挂载了一个全局的对象,我们只需要去触发它提供的方法,完成主子之间的通信即可,不管是交互逻辑还是数据传递逻辑,就都通了。
c.主应用成功引入子应用(子应用是VUE项目)
到目前为止如果我们的项目不存在跨域问题,子应用就已成功接入了主应用,此时我们就可以看到如下图:
左侧是主应用,中间模块是子应用,里面包含子应用的整个模块菜单和列表,考虑到菜单统一放到主应用(基座)方便管理,我们需要把子应用的页面的菜单以及一些 不必要的东西删除,然后我们把子项目一些公共样式公共布局等都统一调整下即可,最终我们会得到一个主应用+子应用页面最终页面,恭喜你到这里你就成功接入了第一个子应用,第二个应用。。。。等应用按照同样步骤。
接入完成不代表你子应用里面所有的模块都能用了,此时我们还需要检查导出和导入的接口是获取域名里面的还是单独定义的,如果获取域名里面的前缀,此时你的导入导出不能正常使用,我们需要重新给导入导出单独定义,比如在子应用创建一个单独的host.js文件,引用根据环境区分到处的域名前缀。
2、路由跳转
通过主应用的菜单跳转到对应子应用的路由
//config.ts
let config = {
yp: 'https://xxx.xxx.com:7000/gw',//本地环境子应用的路由前缀
};
const isEnvPro = process.env.NODE_ENV === 'production';
if (isEnvPro) {
config = {
yp: 'https://xxx.xxx.com/gw',//预发环境环境子应用的路由前缀
};
}
export default config;
//以上是config.ts文件的全部-----end
//菜单点击事件里面的内容
history.push('/yp'); //切换到子应用
setTimeout(() => {
microApp.router.push({
name: 'yp',//和子应用的name要保持一致,为了匹配到对应子应用的路由
path: `${config.yp}${item.url}`,
}); //跳转子应用的路由,其中config是上面的配置文件,根据不同的环境取对应环境的子应用,item是当前点击的菜单路径信息
}, 500);
这里解释下为啥要用setTimeout,首先通过history.push('/yp')切换到子应用,防止切换过去之后短时间内找不到子应用的路由,所以加个延迟能够准确的跳转到子应用对应的路由。
3、设置跨域
(1)如果你仅仅本地跨域的话可以给子应用设置,在webpack-dev-server的headers中设置跨域支持:
devServer: {
headers: {
'Access-Control-Allow-Origin': '*',
}
},
这个有相对应的文档,我们根据子应用的语言设置不同的跨域信息。
(2)如果你是接口跨域。
那么你就需要找后端设置允许我们前端跨域的代码了,Java为例:
@Override
public void init(FilterConfig filterConfig) {
this.origins = Lists.newArrayList("http://localhost:8088",
"https://xx.51epei.com",
"https://xx.yunxiu.com",
"https://dev.51epei.com:8088",
"https://xx.51epei.com:7000");
}
这个是基础配置,我们还可以改成同域名下的所有都允许跨域,最好不要设置成'*',这样很不安全。
4、代理配置
如果你遇见主应用本地访问不到子应用本地,访问的一直是预发或者线上,这时候你需要首先考虑你的代理是否配对,比如我的一个子项目,如图所示:
proxy: (() => {
return {
// 本地访问预发
'/avoid': {
target: 'https://pai.51epei.com',
changeOrigin: true,
bypass: (req) => {
if(req.headers.accept.indexOf('html') !== -1 ) {
return '/index'
}
},
}
}
})()
最初本地代理是路由里面包含'/'就代理到预发上,正常单独访问子应用的链接,可以正常访问本地代理预发的接口,但是放到主应用里面就不可以了,最后给代理改成了整个项目公共部分/avoid,解决了此问题,不一定你的项目是因为这个,但是我觉得可以从代理入手查找问题。
5、数据通讯
micro-app提供了一套灵活的数据通信机制,方便基座应用和子应用之间的数据传输。
正常情况下,基座应用和子应用之间的通信是绑定的,基座应用只能向指定的子应用发送数据,子应用只能向基座发送数据,这种方式可以有效的避免数据污染,防止多个子应用之间相互影响。
同时我们也提供了全局通信,方便跨应用之间的数据通信。
子应用获取来自基座应用的数据,以及基座应用向子应用发送数据,基座应用获取来自子应用的数据,全局数据通讯,具体的我这里都不细说了,文档里都有详细介绍,详细参考https://zeroing.jd.com/docs.html#/zh-cn/data
总结
通过上述介绍我们可以知道,采用微前端架构的好处就是,将原本运行已久、没有任何关联的几个应用融合为一个应用,或者将很多个小型单个应用融合为一个完整的应用,可以减少项目之间的耦合,提升项目扩展性。micro-app借鉴了WebComponent的思想,通过CustomElement结合自定义的ShadowDom,将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。并且由于自定义ShadowDom的隔离特性,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案,因此也得到广大程序员的青睐。
虽说微前端已经是一个非常成熟的领域了,我们使用微前端目的就是为了降本提效,但是在现在的这个开源大环境,我们使用哪种框架,或者自己实现微前端都可以,个人觉得应该考虑如果当前的项目接入微服务之后,变得维护成本更高,那就要考虑是否适合微前端了,我们不能为了用而用,微前端并不是适合所有的场景,遇到问题尝试着去考虑多种方案方案解决。
参考资料:micro-app官网: https://zeroing.jd.com/docs.html#/
作者:京东零售 陈艳春
来源:京东云开发者社区 转载请注明来源
浅入深出的微前端MicroApp的更多相关文章
- 浅入深出Vue:工具准备之PostMan安装配置及Mock服务配置
浅入深出Vue之工具准备(二):PostMan安装配置 由于家中有事,文章没顾得上.在此说声抱歉,这是工具准备的最后一章. 接下来就是开始环境搭建了~尽情期待 工欲善其事必先利其器,让我们先做好准备工 ...
- 浅入深出Vue:前言
浅入深出Vue系列文章 之前大部分是在做后端,后来出于某些原因开始接触Vue.深感前端变化之大,各种工具.框架令人眼花缭乱.不过正是这些变化,让前端开发更灵活. 博主在刚开始时,参考官网的各个步骤以及 ...
- 浅入深出Vue:第一个页面
今天正式开始入门篇,也就是实战了~ 首先我们是要做一个博客网站,UI 框架采用江湖传闻中的 ElementUI,今天我们就来利用它确定我们博客网站的基本布局吧. 准备工作 新建一个vue项目(可以参考 ...
- 浅入深出之Java集合框架(上)
Java中的集合框架(上) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...
- 浅入深出之Java集合框架(中)
Java中的集合框架(中) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,如果已经有java基础的小伙伴可以直接跳到<浅入深出之Java集合框架 ...
- 浅入深出之Java集合框架(下)
Java中的集合框架(下) 由于Java中的集合框架的内容比较多,在这里分为三个部分介绍Java的集合框架,内容是从浅到深,哈哈这篇其实也还是基础,惊不惊喜意不意外 ̄▽ ̄ 写文真的好累,懒得写了.. ...
- 浅入深出Vue:环境搭建
浅入深出Vue:环境搭建 工欲善其事必先利其器,该搭建我们的环境了. 安装NPM 所有工具的下载地址都可以在导航篇中找到,这里我们下载的是最新版本的NodeJS Windows安装程序 下载下来后,直 ...
- 浅入深出Vue:工具准备之WebStorm安装配置
浅入深出Vue之工具准备(一):WebStorm安装配置 工欲善其事必先利其器,让我们先做好准备工作吧 导航篇 WebStorm安装配置 所有工具的下载地址都可以在导航篇中找到,这里我们下载的是最新版 ...
- 浅入深出Vue系列
浅入深出Vue导航 导航帖,直接点击标题即可. 文中所有涉及到的资源链接均在最下方列举出来了. 前言 基础篇 浅入深出Vue:工具准备之WebStorm搭建及配置 浅入深出Vue之工具准备(二):Po ...
- 『浅入深出』MySQL 中事务的实现
在关系型数据库中,事务的重要性不言而喻,只要对数据库稍有了解的人都知道事务具有 ACID 四个基本属性,而我们不知道的可能就是数据库是如何实现这四个属性的:在这篇文章中,我们将对事务的实现进行分析,尝 ...
随机推荐
- 基于 Dash Bio 的生物信息学数据可视化
Dash 是用于搭建响应式 Web 应用的 Python 开源库.Dash Bio 是面向生物信息学,且与 Dash 兼容的组件,它可以将生物信息学领域中常见的数据整合到 Dash 应用程序,以实现响 ...
- Nashorn引擎导致metaspace oom
从报错内容很清楚是Metaspace区域oom了 大部分情况下,程序运行中不会出现过多的类加载数量的变动,先导入dump文件检查是否有异常的classLoader或者有异常动态生成的cla ...
- CF1034D Intervals of Intervals
简要题意 给定 \(n\) 个区间组成的序列,定义它的一个连续段的价值为这个段内所有区间的并覆盖的长度.求价值前 \(k\) 大的段的价值和. 数据范围:\(1\le n\le 3\times 10^ ...
- React学习时,自己拟定的一则小案例(table表格组件,含编辑)
某次在Uniapp群看到有人问uniapp如何操作dom元素. 他想对这张表标红的区域,做dom元素获取,因为产品想让红色色块点击时,成为可编辑,渲染1~4月份之间的行程安排. 于是,有小伙伴说让他用 ...
- Profinet转EtherNet/IP网关连接AB PLC的应用案例
西门子S7-1500 PLC(profinet)与AB PLC以太网通讯(EtherNet/IP).本文主要介绍捷米特JM-EIP-PN的Profinet转EtherNet/IP网关,连接西门子S7- ...
- 一份保姆级的Stable Diffusion部署教程,开启你的炼丹之路
市面上有很多可以被用于AI绘画的应用,例如DALL-E.Midjourney.NovelAI等,他们的大部分都依托云端服务器运行,一部分还需要支付会员费用来购买更多出图的额度.在2022年8月,一款叫 ...
- 现代C++(Modern C++)基本用法实践:零、概述&测试项目
序言 习惯上,我们把C++11之前的C++语法特性称之为"传统C++(traditional c++)",而把c++11之后的语法特性称之为现代C++(modern c++).有一 ...
- 如何将Maven项目快速改造成一个java web项目(方式二)
原始的maven项目,使用IDEA打开后,目录结构如下所示 删除pom.xml文件,删除resource目录,将java目录下的代码放到项目根目录下, 将webapp目录放到项目根目录下.如下图所示 ...
- JNI c++ 与 java 通信过程
JNI(Java Native Interface)是Java提供的一种机制,用于在Java和本地C/C++代码之间进行通信.下面是JNI C++与Java通信的一般过程: 1. 编写Java代码:首 ...
- Redis和Mysql保持数据一致性
1.简述 在高并发的场景下,大量的请求直接访问Mysql很容易造成性能问题.所以,我们都会用Redis来做数据的缓存,削减对数据库的请求.但是,Mysql和Redis是两种不同的数据库,如何保证不 ...