微前端-乾坤

Posted 赏花赏景赏时光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微前端-乾坤相关的知识,希望对你有一定的参考价值。

本文将按照下面的顺序逐一讲解:

1)什么是微前端以及为什么使用微前端

2)乾坤框架介绍

3)基于乾坤框架实例

4)开发过程中遇到的问题

一、什么是微前端

微前端的核心思想就是将按照不同功能或不同维度拆分的独立子应用,通过主应用来加载这些子应用,达到子项目可以独立开发、独立部署、不受技术栈影响效果。

二、乾坤框架介绍

下面的地址是乾坤文档地址,详细介绍了微前端的概念、乾坤的核心设计思想介绍https://qiankun.umijs.org/zh/guide

三、乾坤框架实例

说明:例子基于三个独立项目,项目都采用了vue框架

1、创建项目

由于是基于项目改造,所以项目已经创建好了,这里就不赘述创建项目的过程了

2、主应用配置

主应用不限技术栈,只需要提供一个容器 DOM,然后注册微应用并 start 即可 

1)主应用安装乾坤包

npm i qiankun -S

2)修改App.vue文件,添加微应用挂载节点

3)注册微应用,并启动

首先,配置一些全局变量,用于区分开发环境、测试环境、生产环境的微应用的入口

VUE_APP_UPKEEP_STATIC_HOST是微应用A的域名;VUE_APP_SUB_APP_UPKEEP_PATH是微应用A的路径;

VUE_APP_BRAND_STATIC_HOST是微应用B的域名;VUE_APP_SUB_APP_BRAND_PATH是微应用B的路径。

这里之所以将资源加载的路径写的这么具体,是因为我们的项目都是部署在同一台机器上,只不过是访问路径有些区别,为了防止微应用资源加载错误,所以才写的那么具体。

开发环境配置的一些变量:

测试环境配置的一些变量:

生产环境配置的一些变量:

由于生产环境会区分灰度环境,所以通过变量process.env.IS_GRAY来区分路径。 

 然后,配置微应用的注册信息、将微应用的注册和启动封装成模块

将微应用的注册信息封装成模块,micros/subApps.js

 引进微应用注册信息,将微应用的注册和启动封装成模块,micros/index.js

 

接着,修改入口文件index.js

注意:一定要先挂载主应用之后,才能注册和启动微应用,否则不会触发微应用的加载,即先执行了mountApp之后,在执行startMicroApp

 ThirdMicroPush和ThirdMicroReplace方法用于微应用间跳转,实质是调用了history.pushState和history.replaceState方法,改变浏览器的地址,如果改变后的地址匹配上之前的激活规则activeRule的值,则激活相应的微应用,示例如下:

ThirdMicroReplace('/umc-mall/upkeep/index.html#/home?processNo=tuhu')

4)在webpack.dev.js的devServer属性添加跨域的配置

由于主应用和微应用间的端口号不一样,会存在跨域问题,所以需要配置可跨域信息

至此,主应用的配置已经修改完成,下面说下微应用的改造,微应用不需要额外安装任何其他依赖即可接入 qiankun 主应用。

3、微应用A改造

微应用A的入口文件导出相应的生命周期钩子

微应用需要在自己的入口 js (通常就是你配置的 webpack 的 entry js,这里是根目录下的src/modules/index.js) 导出 bootstrapmountunmount 三个生命周期钩子,以供主应用在适当的时机调用,同时兼容微应用独立运行

修改的代码在下面两张图内:

 

配置微应用A的打包信息

 修改webpack.conf.js文件的output配置

如果项目中有用dll 打包输出一些资源,则需要对dll的配置信息进行修改,并且重新打包,如果没有的话,至此子应用的配置就已经修改完成了。

由于我们的项目有用到dll打包输出的资源,所以还需要修改webpack.dll.js

 在output对象上添加属性libraryTarget: window

 然后需要重新打包dll

注意,确保项目中引进的是新打的dll文件,否则会出现一些异常问题

其他的微应用配置同上。至此,主应用和微应用的改造已经完成,不出问题的话,项目就可以跑起来了

四、开发过程遇到的问题

1、Cannot read property 'range' of null

 在src/modules/views/home/index.vue文件中的methods对象下有如下方法,将该方法注释掉,控制台就不报错了

 按照webpack官方文档描述,是支持动态路径引进相应文件的,但是这里却报错了,而别的项目也有使用动态引进文件,却没有报错。看下控制台的报错信息,是从eslint-loader抛出来的,于是对比了一下关于eslint包的版本,发现正常跑起来项目安装的babel-eslint版本是7.2.3,而报错项目安装的版本是10.0.3。于是将babel-eslint版本改成7.2.3,重启项目就正常了。

原因:安装babel-eslint版本不对,导致解析动态引进文件语法错误

解决方法:安装7.2.3版本的babel-eslint

2、根目录下的模板文件的ejs语法在浏览器下未被正常解析

效果如下:

原因:html-loader和html-webpack-plugin有冲突。如果用html-loader处理了.html类型文件,会把html模板编译成js模块的字符串,html-webpack-plugin解析时候发现文件已经被编译了,就会直接跳过对其编译

图1:

图2: 

解决方法:将图2的配置去掉 

3、Utils is not defined

场景:微应用项目都是用统一的cli命令初始化项目的,统一会在window对象下挂载Utils属性。在本地开发过程能正常访问到Utils对象,但是在线上环境,就抛Utils is not defined。

解决思路:之前微应用项目没有配置微应用信息前,作为独立H5项目,线上和本地都可以访问到window.Utils对象。在配置微应用之后,本地可以访问到Utils对象,但是线上访问不到。应该是和修改了webpack配置有关。然后对比了一下修改webpack前后的配置信息,唯一的区别就是:重新打包了dll后,本地开发时候引的是本地dll文件,即重新打的dll文件,而线上引的是cdn地址dll文件,问题就出在这里。

dll文件引进如下:

开发环境的dll引进放在inc-footer-dev.html中

线上环境的dll引进放在inc-footer.html中

 根目录下的模板文件index.html

原因:修改了dll打包配置,线上用的不是最新打包出来的dll文件

因为我们修改了dll的配置文件的output内容,即添加了libraryTarget: 'window',本地引用的是重新打包后的dll文件,打包出来的全局变量是挂载在window上,肯定是没有问题,而线上引用的是修改dll配置文件之前打包出来的文件,没有配置libraryTarget,默认是var声明的变量

解决方法:线上环境引用的dll文件改成项目打包出来的dll文件,修改inc-footer.html:

 4、微应用A的window.Utils被微应用B的window.Utils覆盖

场景:一起有三个项目:主应用、微应用A、微应用B,微应用A和微应用B都是用同一个脚手架搭的项目,会默认在全局window上添加变量Utils。

问题:现在从链接上直接跳到主应用,在主应用上调接口判断要激活哪个微应用。假如主应用调接口后判断要激活微应用A,这时候Utils对象是微应用A设置的;当在微应用A的某个页面,点击某个按钮时候会激活微应用B,跳转到微应用B的某个页面,这时候Utils对象是微应用B设置的;当从B在回到A上时,Utils对象还是B设置的值。

解决方法:将微应用A和B的Utils对象重新命名,避免重名导致覆盖想象

注意:当调用start方法时,设置sandbox:false,即当关闭沙箱功能时候,检查在主应用和微应用在window对象上挂载的属性是否有重名,避免重名想象

5、主应用线上编译部署时候,抛错:BigInt is not defined

错误信息如下:webpack-cli/bin/cli.js文件抛出来的错误,然后想到项目用的是webpack5的版本,会不会是线上编译的webpack版本不对,然后将线上编译的webpack 的版本打印出来,版本是5.55.0,发现没错。

接着想到webpack5版本对node版本有要求,Webpack 5 对 Node.js 的版本要求至少是 10.13.0 (LTS)会不会是线上编译的node版本不符合要求。接着打印出线上node版本,发现node版本是8.3.0。问题就出在这了。

解决方法:在编译脚本里面,指定node的版本:NODE_VERSION=10.15.3

 6、接口请求时候,网关报错

在我们的项目里面,会加载一个网关包,用于对请求数据的加密。在线上访问主应用时,主应用调接口是正常的,但是主应用激活微应用后,微应用中调接口,报如下错误:

问题:请求头中的字段:X-PA-SIGN-V和X-PA-SIGN-ALG的值不对

主应用会去初始化网关信息,微应用在乾坤容器环境内的话不会重新初始化网关信息,但是主应用调接口时候请求头的X-PA-SIGN=v3和X-PA-SIGN-ALG=1,接口请求正常,微应用接口却报值不对的问题。

主应用代码如下:

微应用代码如下:

主应用没有报网关问题,微应用却报了,两者关于网关信息唯一不同的地方就是引进的包名不一致,于是将微应用的网关包名改成和主应用一致,接口就正常了

问题原因:两个项目的网关包不一样

解决方法:项目的网关包改成一致就可以了

7、运行主项目时候,报错:

index.1b2c201fea272d41a704.js:39190 Uncaught QiankunError: application 'umcmallupkeep' died in status NOT_MOUNTED: [qiankun]: Target container with #childContainer not existed after umcmallupkeep mounted!

 大致意思是,用于挂载微项目的容器节点childContainer不存在。

 

先来看下子项目的注册信息,指定的容器节点名是否为childContainer:下图中的container:'#childContainer',值没有配置错误

 接着看下主应用的挂载组件App.vue内容:

微应用挂载组件App.vue内容:

 法相主应用和微应用的挂载节点的id都是app, 在看下报错图片渲染出来的DOM只有微应用的DOM结构,主应用的DOM节点都没有发现。怀疑是挂载DOM节点的id命名冲突导致的。

将主应用的挂载id由app改成main,项目就不报错了。

正常显示效果如下:

 报错原因:主应用和微应用的DOM节点id命名冲突了

解决方法:修改成不一样的就可以了

8、控制台报跨域问题 ,微应用资源获取失败

Access to fetch at 'https://xxx.com.cn/vender/1.0.0/encrypt.min.js' from origin 'http://localhost:5910' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. Uncaught TypeError: application 'umcmallupkeep' died in status LOADING_SOURCE_CODE: Failed to fetch

 报died in status LOADING_SOURCE_CODE: Failed to fetch错误,一般是微应用还没有改造完成导致的。但是我们的项目已经改造完成了,还是报该错误。在看控制台有一个跨域的错误,会不会是该报错导致的呢?

于是将该文件的引用改成项目中的文件地址,果然就不报错了。

报错原因:当主应用发生跨域报错时,会block调微应用的加载和执行

解决方法:解决掉跨域报错问题

注意:如果测试环境有调生产环境资源,也会报跨域问题,导致微应用加载失败

以上是关于微前端-乾坤的主要内容,如果未能解决你的问题,请参考以下文章

微前端-乾坤

微前端-乾坤

微前端实战-乾坤

微前端实战-乾坤

10分钟弄懂微应用框架——乾坤,真香!

乾坤基础教程