1
头图

背景

公司各团队管理自己的项目,分别有卖家中心、管理中心、商城、h5、...等项目。项目多达40+个。需要统一规划配置项目对应的路由、构建后静态资源存放地址。

前端页面请求过程

浏览器输入url请求页面,经过路由服务,根据路由配置去拉取OSS上相应的index.html

image.png

前端项目CI/CD、请求页面到渲染,都会根据路由服务中的路由配置,结构如下:

[
   {
      "gitRepo": "cassfrontend/seller-merchant-react", // 项目仓库地址
      "cdnRoot": "/www/seller/merchant", // 构建后项目CDN存放目录
      "url": ["/seller/merchant"] // 浏览器请求的url
   },
   {
      "gitRepo": "cassfrontend/seller-test-react",
      "cdnRoot": "/www/seller/test",
      "url": ["/any/path", "/alias/path"]
   }
]

为什么路由服务在返回index.html之前需要改写PUBLIC_PATH呢?

因为生产构建时设置静态资源引用路径是'./',相对于当前路径获取静态资源,而实际情况请求页面地址有配置pathname,比如上图访问页面https://ec-test.casstime.com/seller/merchant/,但是页面资源不是存放在/seller/merchant目录,而是存放在构建后的目录 /seller/merchant/prod/。访问域名也会不一样,资源是在指定的bucket下,访问域名应该是桶配置的CDN链接https://mstatic.cassmall.com。因此,需要动态改写PUBLIC_PATH,向OSS请求静态资源。

webpack支持动态PUBLIC_PATH,在项目主入口文件index.ts中引入import './public-path';

// public-path.ts

declare var __webpack_public_path__: string;

__webpack_public_path__ = (window as any).__PUBLIC_PATH as string;

export default __webpack_public_path__;

路由服务返回index.html,向其中注入script脚本设置window.__PUBLIC_PATH = "xxx"

<!-- index.html 处理前 -->
<script src="/js/main.54b2835a.chunk.js"></script>

<!-- index.html 处理后 -->
<script>
window.__PUBLIC_PATH = "https://mstatic.cassmall.com/admin/merchant/prod/"
</script>
<script src="https://mstatic.cassmall.com/admin/merchant/prod/js/main.54b2835a.chunk.js"></script>

页面加载具体流程

前端页面请求过程.png

部署及回滚方案

1、发布前端项目时,采用非覆盖式发布。每次构建后,入口文件index.html 按版本号复制一份。CDN目录结构如下:

/seller/merchant/prod
   css
   js/
       main.fade23.js
       main.aeb3ef.js
   index.html
   index-v2.0.0.html
   index-v1.0.0.html

2、每个项目可以配置唯一的目录(cdnRoot),不同环境的静态文件部署到cdnRoot对应的子目录中。

环境目录
灾备环境${cdnRoot}/backup/
演示环境${cdnRoot}/demo/
生产环境${cdnRoot}/prod/
测试环境${cdnRoot}/test/

3、构建/发布示意图如下:

image.png

4、需要回滚到指定版本时,只需要将对应版本的html重命名为 index.html 即可快速回滚,回滚示意图如下:

image.png

解决了哪些问题

  • 路由服务业务逻辑简单,但区分 admin、seller,需要为每个项目单独编写路由,配置复杂。
  • 部署目录不规范,项目多后不好管理
  • 不同环境的公共路径(publicPath)不一致,导致在不同的环境需要单独构建。有可能存在测试环境和线上环境代码不一致的问题。
  • 构建和发布在同一个流水线,存在外部环境影响构建结果的风险。
  • 当回滚静态资源时,需要重新构建。

Q&A

  • 为什么忽略路由缓存

    内网获取OSS页面非常快(10ms内),而且页面请求量不会特别高(单页应用,应用内【项目内】切换页面不会刷新),没必要做太复杂的缓存,缓存只作为容错的补救措施。

  • 为什么不再构建时触发更新

    这种操作加大CI复杂度,发布的同时更新路由配置关系(Redis),系统变得复杂。路由服务希望像一般反向代理一样,文件变化了,就给前端返回变化后的文件。文件本身的变化可以通过 HTTP 304 机制优化。


记得要微笑
1.9k 声望4.5k 粉丝

知不足而奋进,望远山而前行,卯足劲,不减热爱。