真香 - Webpack5 新特性之增量编译

2021-02-05 14:59:11 浏览数 (1)

webpack作为最使用最广泛的前端打包工具,已经成为前端工程化基础设施的一部分。

webpack5正式发布于2020年10月10号,距离上一个大版本Webpack4更新已经是2年前年了,每个大版本的升级都会有相当多的改变和提升,今天咱们就来看看增量编辑和长期缓存。

增量编译(官方称作:优化持久化缓存)

Webpack5之前在构建时,会以配置的 entry 为入口,递归解析模块依赖,构建出一个依赖图(graph),该依赖图记录代码中各个 module 之间的关系。

ps: graph 是什么?图是一种数据结构,类似下面这样


每当有文件内容更新的时候,会重新递归生成依赖图,如果简单粗暴地重建依赖图再编译,会有很大的性能开销。在webpack5中,利用缓存实现增量编译,从而提升构建性能。每当代码变化、模块之间依赖关系改变导致依赖图改变时, Webpack 会读取记录做增量编译。

缓存(内存 / 磁盘两种形式)中的主要内容是 module objects,在编译的时候会将依赖图以二进制或者 json 文件存储在硬盘上。

之前持久缓存的方式

  • 使用 cache-loader 可以将编译结果写入硬盘缓存,Webpack 再次构建时如果文件没有发生变化则会直接拉取缓存。
  • 还有一部分 loader 自带缓存配置,比如 babel-loader,可以配置参数 cacheDirectory 使用缓存,将每次的编译结果写进磁盘(默认在 node_modules/.cache/babel-loader 目录)
  • terser-webpack-plugin 开启缓存

webpack5持久缓存方式

v5 中缓存默认是 memory,你可以修改设置写入硬盘:

代码语言:javascript复制
module.export={
    cache{
       type:'filesystem',  //  'memory' | 'filesystem'
        cacheDirectory: 'node_modules/.cache/webpack', // 默认将缓存存储在 node_modules/.cache/webpack
        // 缓存依赖,当缓存依赖修改时,缓存失效
        buildDependencies:{
         // 将你的配置添加依赖,更改配置时,使得缓存失效
         config: [__filename]
     } 
    }
}

增量编译体验

下面来尝试下这个功能,并同时和webpack4做下对比

为了能够看出对比效果,搞了一堆模块,不过代码量都很少。

配置环境 - webpack4 安装

下面使用yarn 安装,本人习惯用yarn,因为速度够快

代码语言:javascript复制
// webpack4
 yarn add webpack@4 webpack-cli@3 babel-loader @babel/core  @babel/preset-env -D
代码语言:javascript复制
const path=require('path'); 
module.exports={
    mode:"development",
    entry:{
        index:'./src/pages/home/index.js' //入口文件
    },
    output:{
        filename:'[name].js', 
        path:path.resolve(__dirname,'./dist') //指定生成的文件目录
    },
    // 模块
   module:{
    rules:[
      {
        test:/.js$/,
        exclude:/node_modules/,
        use:[
          {
            loader:'babel-loader',
            options:{
              presets:[
                '@babel/preset-env',
              ]
            },
          }
        ]
      },
    ]
  },
}

配置环境 - webpack5 安装

代码语言:javascript复制
// webpack5
 yarn add webpack webpack-cli babel-loader @babel/core  @babel/preset-env -D
代码语言:javascript复制
const path=require('path'); 、
module.exports={
    mode:"development", 、
    entry:{
        index:'./src/pages/home/index.js' 、
    },
    output:{
        filename:'[name].js',、
        path:path.resolve(__dirname,'./dist')、
    },
    cache: {
        type: 'filesystem',//使用文件缓存
        // cacheDirectory 默认路径是 node_modules/.cache/webpack
        cacheDirectory: path.resolve(__dirname, './temp_cache') //本地目录
      },
    // 模块
   module:{
    rules:[
      {
        test:/.js$/,
        exclude:/node_modules/,
        use:[
          {
            loader:'babel-loader',
            options:{
              presets:[
                '@babel/preset-env',
              ]
            },
          }
        ]
      },
    ]
  },
}

配置启动命令

代码语言:javascript复制
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "start": "webpack --config webpack.config.js"
  },

构建结果对比

代码语言:javascript复制
//执行
yarn start
代码语言:javascript复制
首次编译 v5  done in 1.5s 左右  
首次编译 v4  done in 1.05s左    

后续无修改编译:v5 done in 0.6s 左右  
后续无修改编译:v4 done in 0.9s 左右

修改后编译:v5 done in 1.5s 左右  
修改后编译:v4 done in 1.5s 左右  

但v5里多了一个时间 webpack compiled successfully time,这个在v4里默认没有显示

V5 首次编译   webpack compiled successfully in 723 ms
V5 无修改编译 webpack compiled successfully in 100 ms
V5 修改后编译 webpack compiled successfully in 417 ms

但我们应该以 done in time 作为对比

构建产物和日志

v5 缓存文件

v5首次编译

v5 无修改2次编译

直接读取缓存

v5修改后编译

增量编译,只编译修改的模块

v4 首次编译

v4 无修改2次编译

全量编译

v4 修改后编译

全量编译

总结

模块较少,代码量少时,增量编辑的优势并不明显,甚至首次编译的速度还会低于v4的速度,因为v5需要处理缓存。

增量编译中:v5只编译了修改的模块,而v4每次编译都是所有模块重新编译,全量执行。

代码量较少,性能提升不明显,相信在复杂庞大的项目中会有更好的效果,因为增量编译无疑会更节省cpu和内存的使用率,后面试着把老项目升级下,看看最终的一个打包速度能提升多少。

今日一提就到这里,希望对你点帮助。

Webpack V5还有非常多的特性,比如长期缓存、更智能的tree shaking、模块联邦 等,一起来探索吧。

0 人点赞