缓存是现在计算机领域最常见的优化手段,作为一个前端见的最多的就是浏览器缓存;
测试人员:线上项目更新怎么没效果呀?
开发人员:缓存清了没呀?
这一节带来的则是
webpack5
的缓存。
Webpack5 中的持久化缓存
webpack5
的持久化缓存能够将首次构建的过程和结果数据进行持久化缓存到本地的文件系统中,下次构建则可以跳过这些构建步骤,使用缓存的数据,以此来达到高速构建的目的,详情参见:webpack5
的持久化缓存
开启webpack5
中的缓存也很简单,只需要配置cache
属性值为true
就可以了,webpack5
在默认情况下,cache
属性值在开发环境中为true
,等同于cache: { type: 'memory' }
,而在生产环境下则是被禁用。
对于持久化缓存,则需要指定cache.type
的属性值为filesystem
,开启这个配置之后,默认会在node_modules
下创建一个.cache
的目录,用来存放生成的缓存文件。
const path = require('path'); module.exports = { mode: 'production', cache: { type: 'filesystem' }, entry: './src/main.js', output: { path: path.resolve(__dirname, './dist'), filename: "[name].js", }, }
执行
npx webpack
命令之后会在node_modules
下生成.cache
目录
webpack5
同时还给cache
属性添加了很多其他的配置选项:
cache.type
:缓存类型,支持'memory' | 'filesystem'
,需要设置为filesystem
才能开启持久缓存。cache.cacheDirectory
:缓存文件路径,默认为node_modules/.cache/webpack
。cache.buildDependencies
:额外的依赖文件,当这些文件内容发生变化时,缓存会完全失效而执行完整的编译构建。cache.managedPaths
:受控目录,Webpack 构建时会跳过新旧代码哈希值与时间戳的对比,直接使用缓存副本,默认值为['./node_modules']
。cache.profile
:是否输出缓存处理过程的详细日志,默认为false
。cache.maxAge
:缓存失效时间,默认值为5184000000
。
上述的完整配置情况如下:
module.exports = { cache: { type: 'filesystem', // 可选值 memory | filesystem cacheDirectory: './.cache/webpack', // 缓存文件生成的地址 buildDependencies: { // 那些文件发现改变就让缓存失效,一般为 webpack 的配置文件 config: [ './webpack.config.js' ] }, managedPaths: ['./node_modules', './libs'], // 受控目录,指的就是那些目录文件会生成缓存 profile: true, // 是否输出缓存处理过程的详细日志,默认为 false maxAge: 1000 * 60 * 60 * 24, // 缓存失效时间,默认值为 5184000000 } }
缓存原理
在课程中的演示中,使用了threejs
作为演示,优化构建效果提高了50倍,这里我没有将threejs
的代码down下来验证,我验证的是上面的配置确实是生效了,构建速度提升很明显。
为什么加了个缓存速度可以提升这么高呢?这就要充webpack
的构建流程开始说起。
webpack
构建项目会经历3个阶段:
- 初始化
- 初始化就是读取你的配置,加载对应的
loader
和插件
- 构建阶段
- 从入口
entry
的文件位置开始读取文件 - 调用
loader
对文件进行转译 - 调用 acorn 生成 AST 结构
- 分析 AST,确定模块依赖列表
- 遍历模块依赖列表,对每一个依赖模块重新执行上述流程,直到生成完整的模块依赖图 —— ModuleGraph 对象
- 生成阶段
- 遍历模块依赖图,对每一个模块执行:
- 代码转译,如
import
转换为require
调用; - 分析运行时依赖。
- 合并模块代码与运行时代码,生成 chunk;
- 执行产物优化操作,如 Tree-shaking;
- 将最终结果写出到产物文件。
在这三个阶段中,会存在很多CPU
密集的操作。
首先说构建阶段,遇到一个文件,需要解析就需要调用对应的loader
进行转译,转译完成还需要分析文件结构生成AST
,然后还要对AST
进行分析,解析出依赖列表,完了之后还要对依赖模块再进行一遍这样的操作。
生成阶段也差不多,也要分析AST
,然后生成最终产物。
在这个步骤中,其实大多数依赖文件是没有发生修改的,因为你总不能没事就去修改node_modules
下的第三方库的代码吧,而且做优化会将这些第三方库的代码生成一个个单独的chunk
,这些chunk
也是单独的,其实不需要再重新生成了。
缓存就是将这两步的操作状态记录下来,并存储在对应的缓存文件中,在下次构建开始时,尝试读入并恢复这些对象的状态,从而跳过执行 Loader 链、解析 AST、解析依赖等耗时操作,提升编译性能。
总结
webpack5
的缓存使用起来很简单,而且效果提升也很明显,抱歉我不会画图,讲原理的时候只能用干巴巴的文字,课程中有图,但是我不能摽窃。
课程中还讲到了webpack4
的缓存和一些loader
的缓存,我都学webpack5
了,就不记录别的了。