Orion's Studio.

前端通用依赖库缓存方案

2023/01/02

背景

看到这篇文章 https://mp.weixin.qq.com/s/0q0E3fIxdii5e-AgjXskdA 发现活动这边基本上也是重复代码率很高,例如 React, React-DOM, encrypt-fetch 这几个包能占到每次活动 js 的 80%文件体积。

将这份代码放到通用库中,从缓存或者离线包中获取,这样每次上线就可以打包非常小体积的代码上线。

静态部署相关

部署 id = 项目 id + 环境 id

形如 xxxx/appcore-react16.js 的 CDN 地址,其中 5fc64a46358dbb5df667b1d0 是项目 id 大家都知道,但是后面的 5fcee95c3d3224c86b199944 其实是环境地址,同一个环境也是不会变的。

一开始我以为这个是版本 id,每次发包都会改变,但实际上不会。而且这个普通的包和离线包都是如此,离线包后缀会带 _0,这也是预留字段,目前也是不会变的。

期间还踩了个坑:webpack 5 + webpack cli 4.2.0 在跑 webpack –env.id xxx 的时候就会报错 Unknown argument: –env,仿佛不支持 –env.id 这种写法,于是降级到 webpack 4 + webpack cli 3 跑通(还把 wepback 5 下的 target: [‘web’, ‘es5’] 写法改回了 target: ‘web’ 终于发布成功)。

离线包的 url

顺带说下,走离线包的 url 测试环境是 mpcdn.xxx、线上环境是 s7/s8.xxx,且目录一定要是 public 下。

客户端存储

另外客户端离线包用来保存区分的是时候也不是只按照项目 id 存的,而是按照项目 id+环境 id 的完整形式存的。所以同一环境的离线包就算更新了,对应的 cdn 地址也不会变。

离线包相关

CDN 与强缓存

强缓存的优先级要高于离线包,CDN 文件都是走的强缓存,也就是说离线包只能优化第一次访问的速度,从第二次开始都是走的强缓存。

客户端支持

目前感觉走缓存的体验效果良好,同时把通用库做成离线包,增加了第一次体验质量。

使用

1.通过 webpack 插件引入脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const HtmlWebpackTagsPlugin = require('html-webpack-tags-plugin');
module.exports = {
plugins: [
new HtmlWebpackTagsPlugin({
usePublicPath: false,
append: false,
scripts: [
{
path:
'xxxx/appcore-react16.js?v=0'
}
]
})
]
};

注 1:千万不要用 async,加载时会报错,可以用 defer

注 2:直接用 script 标签用离线包可能在替换时出现问题,建议用 webpack 插件的方式引入

2.在 webpack 中配置:

1
2
3
4
5
6
7
{
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'prop-types': 'PropTypes',
}
}

之后就能正常使用啦,import ‘react’ 的时候就相当于从 window.React 中获取。

版本

目前根据 React 版本分为两个 cdn 地址:

React 16:xxxx/appcore-react16.js?v=0

React 17:xxxx/appcore-react17.js?v=0

这边带v=0是为了方便之后强制更新版本, 因为重新部署不会使得离线包升级

打包内容

React 16 之后依赖集合类型 Map、Set 和 requestAnimationFrame,为了支持老设备使用了全局的 polyfill。

polyfill

React 在低版本手机可能有兼容性问题,要主动打 polyfill。

1
2
3
import 'core-js/es/map';
import 'core-js/es/set';
import 'raf/polyfill';
CATALOG
  1. 1. 背景
  2. 2. 静态部署相关
    1. 2.1. 部署 id = 项目 id + 环境 id
    2. 2.2. 离线包的 url
    3. 2.3. 客户端存储
  3. 3. 离线包相关
    1. 3.1. CDN 与强缓存
    2. 3.2. 客户端支持
  4. 4. 使用
    1. 4.1. 1.通过 webpack 插件引入脚本:
    2. 4.2. 2.在 webpack 中配置:
  5. 5. 版本
  6. 6. 打包内容
  7. 7. polyfill