前言
使用vue
、react
、angular
等技术开发过程中,我们都会遇到以下问题:
-
首屏加载慢(这个单页面原因引起的, 如果真的很在乎,可以考虑服务端渲染)
-
每一次更新都需要清除浏览器缓存才能看到效果(经常被测试吐槽)
这两个问题可以从很多方面进行优化,今天我就从前端页面部署阶段来优化一下这两个问题。PS:以下内容都基于vue-cli3+
。
前端页面文件缓存方案
从vue-cli3
打包说起
路由使用按需加载后,打包生成的文件,每一个路由页面都对应一个js
和css
文件,入口main.js
及其依赖则打包成了app.js
和app.css
,公共依赖都放到了chunk-vendors.js
。
vue-cli3
打包后的dist/js
文件夹:
可以看到,打包生成的js/css/img
等文件的文件名都带有hash
值,当源文件内容改变时,重新打包后对应的文件hash
值也会改变。举个栗子,我们修改了about.vue
中js
的内容,重新打包时about.js
的hash
值会改变,以及依赖about.vue
的文件app.js
的hash
值也会改变,而其他没有修改的文件,打包后的hash
值都不会改变。
我们知道,文件名带hash
是为了消除缓存带来的影响的,但是所有文件都不缓存肯定不是一个很好的解决方案。
vue-cli3
打包生成的文件名带hash
值的作用
为了缓存的最优体验
我们先来简单回顾下http
缓存的知识(参考MDN:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Caching_FAQ):
-
HTTP1.0
是通过Expires
(文件过期时间)和Last-Modified
(最近修改时间)来告诉浏览器进行缓存的,这两个字段都是UTC
时间(绝对时间)。Expires
过期控制不稳定,因为浏览器端可以随意修改本地时间,导致缓存使用不精准。而且Last-Modified
过期时间只能精确到秒。 -
HTTP1.1
通过Cache-Contorl
和Etag
(版本号)进行缓存控制。浏览器先检查Cache-Control
,如果有,则以Cache-Control
为准,忽略Expires
。如果没有Cache-Control
,则以Expires
为准。
Cache-Control
除了可以设置 max-age
(相对过期时间,以秒为单位)以外,还可以设置如下几种常用值:
-
public
,资源允许被中间服务器缓存。浏览器请求服务器时,如果缓存时间没到,中间服务器直接返回给浏览器内容,而不必请求源服务器。 -
private
,资源不允许被中间代理服务器缓存。浏览器请求服务器时,中间服务器都要把浏览器的请求透传给服务器。 -
no-cache
,不管本地副本是否过期,每次访问资源,浏览器都要向服务器询问,如果文件没变化,服务器只告诉浏览器继续使用缓存(304)。 -
no-store
,浏览器和中间代理服务器都不能缓存资源。每次访问资源,浏览器都必须请求服务器,并且,服务器不去检查文件是否变化,而是直接返回完整的资源。 -
must-revalidate
,本地副本过期前,可以使用本地副本;本地副本一旦过期,必须去源服务器进行有效性校验。 -
proxy-revalidate
,要求代理服务器针对缓存资源向源服务器进行确认。 -
s-maxage
:缓存服务器对资源缓存的最大时间。
现在99%的浏览器都是HTTP1.1
及以上版本,我们配置缓存就使用Cache-Contorl
和Etag
配合就好了。
那么问题来了,检查文件是否最新不是用etag
吗,为什么文件名还需要有hash
值?
(1)如果文件名不带hash
值,文件版本得用etag
来标记,浏览器需要先去检查下是否过期&#