极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。
每天晚上九点 B站讲解前端工程化直播,并解答相关问题。

# 使用 webpack 打包时,如何更好地利用 long term cache

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 81 (opens new window)

查阅了很多前辈的资料,总结大致如下:(最后附上链接) long term cache 即“持久性缓存” Use [chunkhash] to add a content-dependent cache-buster to each file. Use compiler stats to get the file names when requiring resources in HTML. Generate the chunk-manifest JSON and inline it into the HTML page before loading resources. Ensure that the entry point chunk containing the bootstrapping code doesn’t change its hash over time for the same set of dependencies.

1.使用 [chunkhash] 为每个文件增加一个内容相关的缓存清道夫; Separate development and production configs and use [name].js for development and [name].[chunkhash].js in production.

2.使用编译统计在 HTML 中获取资源时取得文件名;html-webpack-plugin (opens new window)

3.生成 JSON 格式的模块清单文件,并在 HTML 页面加载资源之前内联进去; To fix that, we should use chunk-manifest-webpack-plugin (opens new window) which will extract that manifest to a separate JSON file.

4.保证包含启动代码的入口块不会对于同样的依赖生成不同的哈希值;(3.x 以前的版本是使用 CommonsChunkPlugin 来做代码分离的——将公共库(vendor)和应用程序代码分离开来,并创建一个显式的 vendor chunk 以防止它频繁更改。而 webpack 4.x 则是把相关的功能包到了 optimization.splitChunks 中,直接使用该配置就可以实现代码分离。)

代码示例 (opens new window)版本:"webpack": "^1.10.1" 资料来源: webpack 中文文档 (opens new window) Webpack Freestyle 之 Long Term Cache (opens new window) Long-term caching of static assets with Webpack (opens new window) 用 webpack 实现持久化缓存 (opens new window) Webpack 的静态资源持久缓存 (opens new window)

@SageSanyue 目前更推荐使用 contenthash,而不是 chunkhash

# Long Term Cache

使用 webpack 等打包器进行打包时,每个资源都可生成一个带有 hash 的路径。如

  • build/main.071b73.js
  • build/main.94474e.css
  • build/logo.18bac8.png

此处对添加 hash 的资源设置永久缓存,可大幅度提高该网站的缓存能力,从而大幅度提高网站的二次加载性能。

通过在服务器端/网关端对资源设置以下 Response Header,进行强缓存一年时间,称为永久缓存,即 Long Term Cache

Cache-Control: public,max-age=31536000,immutable

而当源文件内容发生变更时,资源的 hash 发生变化,生成新的可永久缓存的资源地址。

因此在实践中,可对打包处理后带有 hash 资源的所有文件设置永久缓存。

如果前端通过 docker/k8s/helm 进行部署,可由团队人员自行在构建 nginx 镜像时进行添加响应头字段。此处可作为前端性能优化的 kpi/okr。

可在浏览器控制台 Network 中查看响应头来验证所属项目是否已成功添加永久缓存。

# 一个问题与更强的永久缓存

假设有两个文件: index.jslib.js,且 index 依赖于 lib,其内容如下。

index.js

// index.js
import("./lib").then((o) => console.log(o));

lib.js

export const a = 3;

由 webpack 等打包器打包后将会生生两个 chunk (为了方便讲解,以下 aaaaaa 为 hash 值)

  • index.aaaaaa.js
  • lib.aaaaaa.js

问: 假设 lib.js 文件内容发生变更,index.js 由于引用了 lib.js,可能包含其文件名,那么它的 hash 是否会发生变动

答: 不一定。打包后的 index.js 中引用 lib 时并不会包含 lib.aaaaaa.js,而是采用 chunkId 的形式,如果 chunkId 是固定的话,则不会发生变更。

// 打包前
import("./lib");

// 打包后,201 为固定的 chunkId (chunkIds = deterministic 时)
__webpack_require__.e(/* import() | lib */ 201);

在 webpack 中,通过 optimization.chunkIds 可设置确定的 chunId,来增强 Long Term Cache 能力。

{
  optimization: {
    chunkIds: 'deterministic'
  }
}

设置该选项且 lib.js 内容发生变更后,打包 chunk 如下,仅仅 lib.js 路径发生了变更。

  • index.aaaaaa.js
  • lib.bbbbbb.js
Last Updated: 11/29/2021, 2:30:53 PM