前言
接上文,因为公司新项目涉及到多个系统,且系统之间有相互共用的模块与页面,为了降低开发成本,就搭建了这套系统。
本文档涵盖了从环境准备到前端开发,主子项目部署、打包配置,nginx 配置等一系列关键步骤。其中 nginx 相关配置的模块我认为是最重要的模块。需要反复摩擦几次。
在开始下文前,我默认你大概了解了:umi、qiankun、antd、nginx 的使用,并对微前端的架构模式和使用场景有所了解。
不知道?那你还不去看看相关的资料?
项目介绍
目前该项目使用微前端架构方案,一共包含 1 个主项目,4 个子项目。其中 3 个项目为业务层,1 个项目为基建层。
本文配置的子项目可以直接嵌套在主项目中,子项目也可以单独脱离出来单独使用(授权登录的话需要自己做一些额外的配置)。
| 项目名称 | 
说明 | 
| main | 
整套系统的框架,外壳 | 
| app1 | 
a 系统 | 
| app2 | 
b 系统 | 
| app3 | 
c 系统 | 
| app4 | 
公共能力 | 
开发流程
这里介绍一下,各个仓库的起始开发流程和规范。
第一步:初始化开发环境
- 通过 git 把仓库代码 clone 到本地,从对应的版本分支创建一条自己的 feature 分支。
 
- 执行 pnpm i, 等待依赖安装完之后,执行 pnpm run start 进行本地开发。
 
- 注入登录模块,开发环境下可以通过该配置绕过登录授权调试(重要)
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | import slave from '@nicecode/slave';
  export const qiankun = {   
 
 
    async mount() {          slave.init({              jumpUrl: `https://base.nicecode.com/material/login`,     });   }, };
   | 
 
链接上的 会告诉用户跳转到哪个页面去授权登录,但是页面上要有 from 或者是 to 字段。用来授权回跳,理论上跳转的优先级是:属性 to > 属性 from > 链接上的 to > 链接上的 from
一般授权成功跳转回来的链接上会带上 token 字段,例如:
http://j710328466.github.io/nicenote?token=xxxxxxxxxx
第二步:代码推送
- 执行 git add .,暂存所有待推送文件。
 
- 执行 git commit -m “${commitMsg}” commitMsg 可以为当前的修改内容,遵循 commit 提交规范,例如:feat(package): 修改配置包属性
在这个阶段会执行相对应的 lint fix 和 prettier fix,不要跳过! 
- 待 lint 校验通过之后,再执行 git push 提交代码到远程。
 
- 在 gitlab 提交 mr 到对应分支,并且指定相关人员 CR。
 
第三步:触发镜像配置 CI
进入 gitlab 的流水线触发即可,再次打开服务器地址就能看到最新的页面了!
项目配置
微前端架构的好处就是整体是一个可插拔的结构,按需加载引用子项目
4.1 主应用
第一步:在 app.ts 中注册子应用
按需接入相应的应用,这里的 APP_ENV 用来区分本地环境和生产环境的加载路由,可以通过在 umijs 的 define 属性定义,再通过 npm 命令传递,详细可以参考 umijs 手册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | export const qiankun = {   apps: [     {       name: 'app1',       entry:         APP_ENV === 'production'           ? `//${hostname}:30068/app1/`           : '//localhost:30068/',       props: {},       singular: false,       credentials: true,     },     {       name: 'app2',       entry:         APP_ENV === 'production'           ? `//${hostname}:30088/app2/`           : '//localhost:30088/',       singular: false,       credentials: true,     },     {       name: 'app3',       entry:         APP_ENV === 'production'           ? `//${hostname}:30078/app3/`           : '//localhost:30078/',       singular: false,       credentials: true,     },     {       name: 'app4',       entry:         APP_ENV === 'production'           ? `//${hostname}:30098/app4/`           : '//localhost:30098/',       singular: false,       credentials: true,     },   ], };
  | 
 
要注意这里的两个属性:
- singular:子应用是否预加载,最好设置为 false,防止其它子应用卸载的时候,控制台会报错。
 
- credentials:这个设置了的话,请求的子应用就会默认带上 cookie 校验,这样 nginx 配置会略微有些麻烦,不过不打紧。
 
第二步:在主应用中的 umirc.ts 中注册 4 个子应用
这个没啥好说的,就是重置了子应用的路由,映射到所有的微应用。microApp 不要错了,对应注册的子应用名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
   | {   ...   routes: [     {         name: '应用1',         path: '/app1/*',         microApp: 'app1'     },     {         name: '应用2',         path: '/app2/*',         microApp: 'app2'     },     {         name: '应用3',         path: '/app3/*',         microApp: 'app3'     },     {         name: '应用4',         path: '/app4/*',         microApp: 'app4'     }   ]   ... }
  | 
 
4.2 子应用
子应用相对配置简单一点,只需要修改 umijs.ts 文件的一个属性就行:
1 2 3 4 5 6 7
   | {   ...   qiankun: {     slave: {}   }   ... }
  | 
 
项目 nginx 配置
主应用
这里我只贴出重要的部分,具体负载均衡和接口映射啥的,需要和后端协调进行修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | {   ...       server {           listen       30058;
            location / {               if ($request_method = 'OPTIONS') {                   add_header 'Access-Control-Allow-Origin' '$http_origin' always;                   add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';                   add_header 'Access-Control-Allow-Credentials' 'true';                   add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorizationept';                   add_header 'Access-Control-Max-Age' 1728000;                   return 204;               }               add_header 'Access-Control-Allow-Origin' '$http_origin' always;               add_header 'Access-Control-Allow-Credentials' 'true';
                root   /web/main;                   try_files $uri $uri/ /index.html;               index  index.html index.htm;           }
            error_page   500 502 503 504  /50x.html;           location = /50x.html {               root   html;           }       }   ... }
  | 
 
子应用
子应用就是比主应用多了个路由的映射,和 proxy 的设置,其它都差不多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   | {   ...   server {       listen       30078;
        location /app1 {                                 
            if ($request_method = 'OPTIONS') {               add_header 'Access-Control-Allow-Origin' '$http_origin' always;               add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';               add_header 'Access-Control-Allow-Credentials' 'true';               add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorizationept';               add_header 'Access-Control-Max-Age' 1728000;               return 204;           }           add_header 'Access-Control-Allow-Origin' '$http_origin' always;           add_header 'Access-Control-Allow-Credentials' 'true';
            try_files $uri $uri/ /app1/index.html;           alias  /web/app1;           index  index.html index.htm;       }
        error_page   500 502 503 504  /50x.html;       location = /50x.html {           root   html;       }   }   ... }
  | 
 
小结
整个架构从开始环境搭建,开发到部署上线。历时大概 3 个月左右,中间碰到了挺多问题,其中关于 nginx 配置的问题是最多的,基本上就是在恶补还不知道的 nginx 知识。
其次再是相关的公司服务端 CI 部署相关的内容,因为运维方面涉及到 ducker 和 k8s,因为项目的特殊性,也不是用传统的 Jenkins 或者其它 ci 方案,并且是由同一套配置组件化来管理 nginx 配置和部署方案,所以很多时候的项目推进比较麻烦。
简单点说就是,我不是很懂运维那套架构体系,运维说做不了或者没时间…