本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!
前言
前一段时间,小编在学习完 Vite
之后,写了一篇关于 Webpack
和 Vite
在开发体验上对比的文章 - 为什么有人说 vite 快,有人却说 vite 慢?。文章发布以后,反响非常好,有很多小伙伴在评论区积极发表自己的看法,而小编也从这些评论中又 get 到了不一样的收获,非常 👍。
在这些评论中,有一些非常有趣。比如,部分小伙伴也提到了使用 Vite
时遇到了首屏较慢的问题,有小伙伴回复说是不是因为浏览器禁用了缓存功能,导致 Vite
的缓存策略没有生效,从而使得首屏性能受到影响。
针对这一点,小编要先说明一下,之前说的 Vite
首屏性能差,是指 dev server
首次启动以后首次访问应用。在这种情况下,即使没有禁用缓存,首屏还是有点慢。不过在此之后,再次刷新页面时,首屏性能就好很多了。
那小伙伴们可能就有疑惑了,不管是首次访问应用还是二次访问应用,明明在 network
中看到静态资源不是走强缓存就是协商缓存,为什么会有不同的效果呢?这是怎么一回事呢?꒰╬•᷅д•᷄╬꒱
哈哈,其实这个问题的答案非常简单。接下来,小编将会本文中做详细说明,相信小伙伴们看完以后肯定会恍然大悟的。
本文的目录结构如下:
没有起作用的协商缓存
为什么标题是没有起作用的协商缓存呢?
在回答这个问题之前,小编先给大家简单介绍一下 Vite
开发模式下的缓存策略。在 Vite
中,静态资源分为两类:预构建内容和业务代码。其中,预构建内容通常是由项目中的第三库生成的,采用强缓存策略,业务代码则采用协商缓存策略。
举个 🌰:
图中 chunk-xxx
格式的内容就是预构建内容,响应头中通过 cache-control
字段中的 max-age = 3153600
, 指明该文件采用强缓存策略。在请求时,可以通过修改请求的版本号 v=xxxx
来规避强缓存。
App.tsx
,业务代码,采用协商缓存策略。
了解完这个以后,小编就通过 2
个 gif
动图来给大家演示一下为什么说协商缓存没有起作用。
首先是dev server
启动后首次访问应用的 gif
动图。
在这个 gif
动图中,大家可以看到请求静态资源时,会走强缓存和协商缓存。仔细看这些请求,我们会发现在请求 less
类型的文件时,尽管走了协商缓存,但依旧要消耗很长的时间,导致首屏性能受到影响。
接下来,小编再给大家看一个二次访问应用的 gif
动图。
这次,首屏性能要好很多。打开 network
, 我们发现请求 less
类型的文件,只用到了十几毫秒,比之前的 2s
多要好太多了。
那这是为什么呢?明明返回的状态码都是 304
,为什么会是两种效果呢?这里面是有什么说法吗?
答案其实很简单,那就是两次判断 304
的逻辑不一样。
我们知道,协商缓存,通常需要在发起请求时,在请求头中添加 If-None-Match
字段,携带请求文件对应的 ETag
信息。当 dev server
收到请求时,会将请求头的 ETag
和请求文件的 ETag
信息做对比,如果没有变化,返回 304
通知浏览器使用本地缓存,反之则返回新的文件内容。
在获取请求文件的 ETag
信息这一块儿,Vite
有自己的一套处理逻辑。
在 dev server
内部,有一个缓存对象 - moduleGraph
, 用来缓存请求过的文件内容和对应的 ETag
信息。
当 dev server
启动以后,这个对象是空的。此时如果浏览器发起业务代码请求,dev server
需要根据请求,将请求 url
解析为文件的本地路径(resolve
)、读取文件内容(load
)、对文件内容做转换(transform
- 如 less
转换为 css
)、计算 ETag
,并缓存到 moduleGraph
中。 此时,如果请求中 If-None-Match
字段中携带的 ETag
信息和新计算的 ETag
信息一致,server
端会将状态码设置为 304
,不返回转换以后的内容。
当浏览器再次请求相同文件时,dev server
会根据请求路径直接从缓存中去读取文件内容和 ETag
信息,然后和请求中 If-None-Match
字段中携带的 ETag
信息做比较。如果一致,server
端直接将状态码设置为 304
,通知浏览器使用本地缓存。
了解了这些,那么首次访问应用时协商缓存为什么没有起作用就好理解了。因为这个时候,dev server
内部的缓存为空,所有的请求都需要经历 resolve
、load
、transform
的过程,导致响应耗时较久。
哈哈,是不是很简单呢,😂。
结束语
到这里,关于 Vite
开发模式下的缓存策略就介绍完了。
最后,我们做一个简单的总结:
-
开发模式下,请求预加载文件采用强缓存策略,请求业务文件采用协商缓存策略。
-
首次访问应用请求业务文件时,尽管会命中协商缓存,但
sever
端依旧会进行resolve
、load
、transform
操作,导致响应需要消耗一定的时间。 -
二次访问应用,强缓存和协商缓存同时起作用,性能很好。
其实,关于结论中提到的第二点,我们还是有办法进行优化的,比如说采取 Webpack5
的缓存策略,在 dev server
关闭之前将 moduleGraph
缓存到本地,等到再次启动时读取本地缓存。这一点,小编将会在后面单独写一篇文章来介绍,感兴趣的小伙伴们可以保持关注哦,😄。