通过将资源缓存在客户端中,可以避免之后每次都重新下载
浏览器缓存策略和webpack缓存相关配置
第一步:我们一般会将静态资源(JavaScript 、CSS、图片字体文件等) 这些不经常变动的文件寻找更合适的服务器存放,比如放到 CDN 服务器上,并且配置单独的域名,比如百度常用 的 CDN 域名是:x.bdimg.com和x.bdstatic.com域名,这样做的好处是:
- 保证动静分离,将动态页面和静态资源分开部署有利于服务的更好维护;
2. CDN 可以更加接近用户的终端,提供加速服务,详细可以查看 CDN 的原理;
3. 静态资源不会具有动态逻辑,单独的域名可以减少页面请求中的 Cookie 等不必要字段,减少 HTTP 带宽。
将静态资源存放到单独的服务器之后,需要做的是配置合理的 HTTP 缓存相关协议,比如我们使用CacheControl告诉浏览器,当前文件的max-age
Cache-Control: max-age=31536000 //缓存时间为 一年 (31536000=360024365)
第二步:就是要针对发生了变更的静态资源进行重命名,这样静态的文件虽然使用了 CDN 和强缓
存,但是只要内容变化,那么文件的路径(网址)发生了变化,浏览器还是会重新请求下载的:
<!-- 修改前 --> <script src="./index-v1.js"></script>
<!-- 修改后 --> <script src="./index-v2.js"></script>
这个方法可以告诉浏览器去下载 JavaScript 文件,并将它缓存,之后使用的都是它的缓存副本。浏览器只会在文件 名发生改变(或者一年之后缓存失效)时才会请求网络。在使用 Webpack 构建项目的时候,同样可以做到自动更 新,但 Webpack 使用的不是版本号,而是指定哈希值(hash),在之前的文章中不止一次的提到过,Webpack 的 hash 值有三种:
- hash:每次编译 Compilation 对象的 hash,全局一致,跟单次编译有关,跟单个文件无关,不推荐使用
- chunkhash:chunk 的 hash,根据不同的 chunk 及其包含的模块计算出来的 hash,chunk 中包含的任意模块发生 变化,则 chunkhash 发生变化,推荐使用
- contenthash:CSS 文件特有的 hash 值,是根据 CSS 文件内容计算出来的,CSS 发生变化则其值发生变化,推荐 推荐 CSS 导出中使用
我们在 webpack 中使用 chunkhash 实际使用的是 占位符语法
module.exports = {
entry: "./index.js",
output: { filename: "bundle.[chunkhash:8].js" }, // → bundle.8e0d62a3.js }
};
我们 Webpack 打包出来的资源,除了通过 HTML 中使用之外,可能还会需要生成一张包含所有内容的清单文件, 这个文件可以用于类似 Application Cache或 者 PWA方案,这时候我们需要使用 webpack-manifest-plugin 插件。 webpack-manifest-plugin
是一个扩展性极强的插件,它可以帮助你解决服务端逻辑比较复杂的那部分。在打包时, 它会生成一个 JSON 文件,里面包含了原文件名和带哈希文件名的映射。在服务端,通过这个 JSON 就能方便的找到我们真正要执行的文件
// manifest.json
{ "bundle.js": "bundle.8e0d62a03.js" }
将依赖和 Runtime 提取到单独的文件中
Tips:在 Webpack 4.29.6 版本已经修改了模板输出的 Template,即使 entry 修改,实际 Runtime 部分的内 容也不会有变化,所以上面分离 Runtime 的方案适应于低版本的 Webpack。
多页面项目按照路由拆分代码
如果我们的项目是一个由多个路由或页面组成的,但是代码中只有一个单独的 JavaScript 文件(一个单独的入口 chunk),这样会导致不管访问任何页面都会加载整站资源。
此外,如果这个用户经常只 是访问其中的某个页面,但是当我们更改了其它页面的代码,Webpack 将会重新编译,那么整个 bundle 的文件名哈希值就会发生变化,最终导致用户重新下载整个网站的代码,造成不必要的浪费。
这时候合理的做法是将整个项目利用多页面打包方案进行划分,我们将代码按照页面进行拆分,这样用户访问某个
页面的时候,实际下载的只是当前页面的代码,而不是整个网站的代码,浏览器也更好的缓存了这部分代码,当其
他页面代码发生变化的时候,当前代码的哈希值不会失效,自然用户不会重复下载相同的代码了。