webpack5 优化构建速度

下面会以这些方面来说明如何 优化构建速度

  1. 优化babel-loader
    • 使用includeexclude来缩小查找范围
    • 使用cacheDirectory来设置缓存
  2. 避免引入无用的模块:webpack.IgnorePlugin
  3. 避免重复打包:module.noParse
  4. 开启多进程打包:happypack
  5. 多进程压缩jswebpack-parallel-uglify-plugin
  6. 自动更新和热更新(仅适合开发环境):watch(devServer自动开启)、HotModuleReplacementPlugin

优化babel-loader

在遇到浏览器不识别的es6代码时,我们往往借助babel-loader去解译成ES5, 当有多个模块引用时,这个解析时间是比较长的,所以可以采用以下方式来减少解析的时间:

  1. 开启缓存,在第2次编译时,直接使用缓存,不用重新编译,缓存一般只适用于开发环境
  2. 使用includeexclude适当缩小loader的适用范围,让其更快找到要解析的文件,开发和生产环境皆适用
  module: {
    rules: [
      {
        test: /\.js$/,
        use: ['babel-loader?cacheDirectory'], // 1. 开启缓存
        include: srcPath, // 2. 缩小适用范围(使用include或exclude)
        exclude: /node_modules/
        }
    ]
  }

IgnorePlugin 避免引入无用的模块

IgnorePlugin可以用来忽略某些库中我们不需要引入的部分,比如moment包中的多国语言包,下面以moment库为例来说明如何使用

  1. 安装: npm i momnet -D
  2. index.js入口文件中,引入moment,可以看到它的体积很大,有290K,压缩后也要72k(计算包大小,可安装vscodeimport cost插件查看)
    moment包大小
// index.js
import moment from 'moment'
console.log(moment.each);
moment.locale('zh-cn');  // 设置为中文
const date = moment().format('LL');   // 2021年6月29日
console.log(date);

moment库会默认引入所有语言的代码,所以会导致代码很大,在实际开发中,其实我们一般只需要中文,或者中英两个语言的代码,这时就可以使用IgnorePlugin来优化,避免引入其他无用语言的代码

  1. 在不设置IgnorePlugin时,index打包大小295k

    image.png

  2. 设置IgnorePlugin

// webpack.prod.js或webpack.common.js都可以
const webpack = require('webpack')
const prodConfig = {
  plugins: [
    // webpack4写法
    // new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)

    // webpack5写法
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,   // 忽略content设置的库中的某个文件夹
      contextRegExp: /moment$/, // 要被忽略某部分内容的库
    })
  ]
}
  1. 因为忽略了moment的所有语言包,所以在index.js中要手动引入想要的语言包(这点比较麻烦,但相较性能来说值得做),比如中文
import moment from 'moment'
// 动态引入中文语言包
import 'moment/locale/zh-cn'
console.log(moment.each);
moment.locale('zh-cn');  // 设置语言为中文
const date = moment().format('LL');   // 2021年6月29日
console.log(date);
  1. 此时再打包,可以看到index打包后的体积变为64k,小了230k,所以性能是提升了很多的
    使用IgnorePlugin的moment包

noParse

noParse是用来过滤不需要解析的模块,比如jquery,lodash之类的,这些库一般不会再引入其它库,所以不需要webpack去解析其依赖,也不用打包,只是直接引用即可
noParsemodule的一个配置:

module: {
  noParse: /jquery|lodash/,
}

IgnorePluginnoParse的区别:

  • IgnorePlugin是不引入指定库的部分内容,会减少打包的体积
  • noParse是只引入库,但不对其进行webpack解析依赖和构建,包的体积不会减少,但打包速度会提升
  • 两者都可以在开发和生产环境中使用

happyPack 多进程打包

因为js是单线程的,如果引用的模块很多,且模块间引用的层级很深,那么webpack在递归解析依赖时,速度就会很慢。而使用happyPack可以开启多进程打包,会提高构建速度
它在开发或者生产环境都可以使用,不过对于小项目,使用这个优化空间不大,且开启进程可能消耗性能会更多;在大项目时,才会有较多的优化空间

  • 安装:npm i happypack -D
  • 配置:
// wepback.common.js 或webpack.prod.js 
const HappyPack = require('happypack')
// 将原来babel的配置改下,改为使用happypack多进程打包
module: {
    rules: [
      {
        test: /\.js$/,
        // use: ['babel-loader?cacheDirectory'],
        // 改为使用 happypack打包
        use: ['happypack/loader?id=babel'], // 这个id是自定义命名的,要跟插件中id对应 
        include: srcPath
      }
  ]
},
plugins: [
  new HappyPack({
      id: 'babel', // 唯一标识符
      // 使用的loader配置改写到happypack的配置项中
      use: ['babel-loader']
    })
  ]

parallelUglifyPlugin 多进程压缩js

适用生产环境

  • 安装:npm i webpack-parallel-uglify-plugin -D
  • 配置:
// webpack.prod.js
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')

plugins: [
  new ParallelUglifyPlugin({
      // 压缩js的一些配置
      uglifyJS: {
        output: {
          beautify: false,  // 不需要格式化,以最紧凑的方式输出
          comments: false // 删除注释
        },
        warnings: false, // 删除未使用一些代码时引起的警告
        compress: {
          drop_console: true, // 删除所有console.log
          // 是否内嵌虽定义,但只使用了一次的变量
          // 比如var x = 2, y = 10, z = x + y 变成 z = 12
          collapse_vars: true,
          // 提出多次出现但没定义的变量,将其变成静态值;
          // 比如x = 'xx', y = 'xx' 变成 var a = 'xx', x = a, y = a 
          reduce_vars: true 
        }
      }
    })
  ]

多进程使用总结:

  • 项目大时,打包较慢时,我们才考虑开启多进程来提高速度
  • 项目较小时,本身打包就比较快,没必要开启多进程,因为进程开启、销毁、通信,本身就有一定的性能消耗,在项目小时,有可能使用多进程反而会降低打包速度

自动刷新

在开发环境下,一般配置了devServer会默认开启自动刷新页面的功能,即watch: true,不需要我们手动再配置

// webpack.dev.js
// watch: true, //相当于默认开启watch
devServer: {
    port: 8080,
    // 设置代理
    proxy: {
      // 将本地 /api2/xxx 代理到 localhost:6666/xxx,通常用这个,/api2仅作为代理转发的标识
      '/api2': {
          target: 'http://localhost:3000',
          changeOrigin: true,
          pathRewrite: {
              '/api2': ''
          }
      },
      hot: true, // 热重载
      open: true
    }
  },

热更新

  • 自动刷新
    是指在修改模块内存时,浏览器会自动刷新页面来更新视图内容,是整个页面刷新,速度较慢;刷新页面还会导致临时状态丢失(比如表单内容)
  • 热更新
    是在不刷新页面的情况下,使新代码生效,整个网面不会刷新,状态也不会丢失

热更新配置:

// webpack.dev.js
const webpack = require('webpack')
module.exports = {
  target: 'web',
  plugins: [
    new webpack.HotModuleReplacementPlugin({})
  ]
}

你可能感兴趣的:(webpack5 优化构建速度)