peng-yin / note

:shipit: This is My GitHub Pages
https://note-seven-rho.vercel.app/
8 stars 0 forks source link

微前端笔记 #74

Open peng-yin opened 2 years ago

peng-yin commented 2 years ago

516032036 519454046

1、名词解释

2、设计背景

微前端架构具备以下几个核心价值:

  1. 技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权

  2. 独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新

  3. 增量升级 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略

  4. 独立运行时 每个微应用之间状态隔离,运行时状态不共享 微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。

  5. 为什么不是iframe , 看这里 Why Not Iframe

4、域名规划

该设计方案需要2类域名配合,  分别为应用域名, 网关域名.   非CDN部署模式下, 网关域名为可选项.  可以与主应用保持一致. 

5、路径结构设计

截图 (2)

6、部署目录设计

└── html/                     # 根文件夹
    |
    ├── app/                # 存放所有微应用的文件夹
    |   ├── vue-hash/         # 存放微应用 vue-hash 的文件夹
    |   ├── vue-history/      # 存放微应用 vue-history 的文件夹
    |   ├── react-hash/       # 存放微应用 react-hash 的文件夹
    |   ├── react-history/    # 存放微应用 react-history 的文件夹
    |   ├── angular-hash/     # 存放微应用 angular-hash 的文件夹
    |   ├── angular-history/  # 存放微应用 angular-history 的文件夹
    ├── index.html            # 主应用的index.html
    ├── css/                  # 主应用的css文件夹
    ├── js/                   # 主应用的js文件夹

6、activeRule详细列表

本设计遵循DDD设计拆分, 与后端相关微服务对齐

3、基本原理

通过图示具体理解一下 qiankun 注册子应用的过程:

image

整个qiankun框架中我们知道了什么东西:

  1. qiankun是如何完善single-spa中留下的巨大缺口-————加载函数,JS沙箱 ,CSS样式隔离。

  2. qiankun如何隔离子应用的js的全局环境————通过沙箱。

  3. 沙箱的隔离原理是什么————在支持proxy中有一个代理对象,子应用优先访问到了代理对象,如果代理对象没有的值再从window中获取。如果不支持proxy,那么通过快照,缓存,复原的形式解决污染问题。

  4. qiankun如何隔离css环境————shadowDOM隔离;

实际开发中遇到的问题

  1. 公用组件依赖复用:项目中避免不了的比如请求库的封装,我可能并不想在子应用中再写一套同样的请求封装代码,可以将公共方法都是放在window上的一个对象里挂载, 对于Typescript项目,基座工程给子工程传的公共方法没有声明文件, 会开发报错怎么办?
// index.js - js部分只需要把window对象里面的方法赋值到开发包里
const baseSDK = window.baseSDK || {};
​
export default {
  report: baseSDK.report || {},
};

// index.d.ts
declare module '@sdk' {
  namespace report {
    function pv(cid: string, data?: Object): any;
    function mc(bid: string, data?: Object): any;
    function mv(bid: string, data?: Object): any;
    function me(bid: string, data?: Object): any;
  }
}
  1. 公共方法的SDK包如何更新?更新时机是什么?

我们把更新的时机放到了子工程本地启动的时候,在启动前利用prestart钩子做一个node的版本检查和自动更新。用户选择是否去更新sdk包,参考代码:

// package.json - 在npm start 时, prestart提示安装最新的包
"scripts": {
    "start": "cross-env NODE_ENV=development DEPLOY_TYPE=development webpack serve --config=./config/webpack.config.js",
    "prestart": "node ./preStart.js",
 }

image

  1. 本地开发热部署失效?

我们把基座工程部署到了一个特有的域名下面,里面去加载子工程,这样避免了启动两个工程开发。但是子工程一开始热更新失效,报错跨域。

1)为什么会跨域?哪里引起的跨域?

首先基座已经配置过对localhost.xx.com的域名跨域,那么问题就出现在热更新资源的问题,webpack-dev-server的热更新其实是node客户端和浏览器之间用ws双工通信去监听文件编译发请求下载薪的hot代码,然后检查发现webpack-dev-server请求的还是localhost这个域名,这个域名和我们配置的localhost.xx.com域名发生了跨域导致热更新失败,然后就去webpack5的文档里找设置webpack-dev-server域名配置方法,最终配置方法如下:

 devServer: {
    host: 'localhost.xx.com',
    firewall: false,
    hot: true,
    client: {
      host: 'localhost.xx.com',
      port: devPort,
      needClientEntry: !IS_REMOTE_DEV,
      needHotEntry: !IS_REMOTE_DEV,
    }
   ...
 }
 // 更新模块重新执行
if(module.hot){
    module.hot.accept()
}
  1. 开发模式

访问主工程域名, 加载本地子工程资源

  1. 路由跳转 在子项目里面跳转到主项目页面时,直接写 或者用 router.push/router.replace 是不行的,原因是这个 router 是子项目的路由,所有的跳转都会基于子项目的 base 。写 链接可以跳转过去,但是会刷新页面,用户体验不好。

解决办法 :在子项目注册时将主项目的路由实例对象传过去,子项目挂载到全局,用父项目的这个 router 跳转就可以了。

  1. 项目通信 qiakun 提供了一个全局的 GlobalState 来共享数据。主项目初始化之后,子项目可以监听到这个数据的变化,也能提交这个数据。

  2. css 污染问题 主项目要想不被子项目的样式污染,项目本身的 id/class 需要特殊一点,不能太简单,被子项目匹配到。类名这需要规范

  3. 其他

1). js 沙箱并不能解决所有的 js 污染,用 onclick 或 addEventListener 给 添加了一个点击事件,js 沙箱并不能消除它的影响,还得靠代码规范

2). qiankun 框架不太好实现 keep-alive 需求,因为解决 css/js 污染的办法就是删除子项目插入的 css 标签和劫持 window 对象,卸载时还原成子项目加载前的样子,这与 keep-alive 相悖: keep-alive 要求保留这些,仅仅是样式上的隐藏。

3). qiankun 将每个子项目的 js/css 文件内容都记录在一个全局变量中,如果子项目过多,或者文件体积很大,可能会导致内存占用过多,导致页面卡顿。

4). qiankun 运行子项目的 js,并不是通过 script 标签插入的,而是通过 eval 函数实现的,eval 函数的安全和性能是有一些争议