webpack性能优化-构建速度

2021-10-09 14:17:11 浏览数 (1)

前言

随着项目越来越复杂,可能你们会有同样的感触,上了趟厕所回来,项目还没构建完成。然而测试还一直在催命。或许这时候你就应该去考虑下,如何去优化我们的构建速度。

优化方案

1. 优化babel-loader

babel-loader在执行的时候,可能会产生一些运行期间重复的公共文件,造成代码体积大冗余,同时也会减慢编译效率,因此我们可以通过添加cacheDirectory开启babel缓存。

代码语言:javascript复制
  {
    test: /.m?js$/,
    exclude: /(node_modules)/,
    use: {
      loader: "babel-loader",
      options: {
         cacheDirectory: true
      },
    },
  },
复制代码

2. noParse

该配置项可以让webpack忽略对部分未采用模块化文件的递归解析和处理,该忽略的文件不能包含import,require, define等模块化语句。

代码语言:javascript复制
module.exports = {
  module: {
    noParse: /jquery|xxjs/
  }
}
复制代码

3. happyPack(多进程打包)

由于 JavaScript 是单线程模型,要想发挥多核 CPU 的能力,只能通过多进程去实现,而无法通过多线程实现。happyPack的思想是使用多个子进程去解析和编译JS,css,等,这样就可以并行处理多个子任务,多个子任务完成后,再将结果发到主进程中。

  • 安装
代码语言:javascript复制
$ npm install happypack --save-dev
复制代码
  • 使用

happypack 只是作用在 loader 上,使用多个进程同时对文件进行编译。

1.将常用的 loader 替换为 happypack/loader

代码语言:javascript复制
const HappyPack = require('happypack');

module.exports = {
    ...
    module: {
        rules: [
            test: /.js$/,
            // use: ['babel-loader?cacheDirectory'] 之前是使用这种方式直接使用 loader
            // 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
            use: ['happypack/loader?id=babel'],
            // 排除 node_modules 目录下的文件
            exclude: /node_modules/
        ]
    }
}

复制代码

2.创建 HappyPack 插件

代码语言:javascript复制
const HappyPack = require('happypack');

module.exports = {
    ...
    module: {
        rules: [
            test: /.js$/,
            // use: ['babel-loader?cacheDirectory'] 之前是使用这种方式直接使用 loader
            // 现在用下面的方式替换成 happypack/loader,并使用 id 指定创建的 HappyPack 插件
            use: ['happypack/loader?id=babel'],
            // 排除 node_modules 目录下的文件
            exclude: /node_modules/
        ]
    },
    plugins: [
        ...,
        new HappyPack({
            /*
             * 必须配置 id 标识符,要和 rules 中指定的 id 对应起来
             */
            id: 'babel',
            // 需要使用的 loader,用法和 rules 中 Loader 配置一样
            // 可以直接是字符串,也可以是对象形式
            loaders: ['babel-loader?cacheDirectory']
        })
    ]
}

复制代码

这样 Happypack 的使用就配置完了,运行项目,可以看到控制台打印如下提示:

代码语言:javascript复制
Happy[babel]: Version: 5.0.1. Threads: 3
Happy[babel]: All set; signaling webpack to proceed.
复制代码

说明配置生效了。关于开启多进程,这里要注意下:

  • 项目较大,打包较慢,开启多进程能提高构建速度
  • 项目较小,打包很快,开启多进程会降低速度(进程开销)

如果大家对happypack的使用想更深入些,推荐传送门这篇文章讲的更系统些,建议大家阅读。

4. ParallelUglifyPlugin(多进程压缩js)

webpack默认提供了UglifyJS插件来压缩JS代码,但是它使用的是单线程压缩代码,也就是说多个js文件需要被压缩,它需要一个个文件进行压缩。所以说在正式环境打包压缩代码速度非常慢(因为压缩JS代码需要先把代码解析成用Object抽象表示的AST语法树,再去应用各种规则分析和处理AST,导致这个过程耗时非常大)。使用UglifyJS压缩代码如下:

代码语言:javascript复制
module.exports = {
  plugins: [
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: true,
      compress: {
        warnings: false
      }
    }),
  ]
}
复制代码

ParallelUglifyPlugin插件则会开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成,但是每个子进程还是通过UglifyJS去压缩代码。无非就是变成了并行处理该压缩了,并行处理多个子任务,效率会更加的提高。

  • 安装
代码语言:javascript复制
npm i -D webpack-parallel-uglify-plugin
复制代码
  • 使用
代码语言:javascript复制
// 引入 ParallelUglifyPlugin 插件
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');

module.exports = {
  plugins: [
    // 使用 ParallelUglifyPlugin 并行压缩输出JS代码
    new ParallelUglifyPlugin({
      // 传递给 UglifyJS的参数如下:
      uglifyJS: {
        output: {
          /*
           是否输出可读性较强的代码,即会保留空格和制表符,默认为输出,为了达到更好的压缩效果,
           可以设置为false
          */
          beautify: false,
          /*
           是否保留代码中的注释,默认为保留,为了达到更好的压缩效果,可以设置为false
          */
          comments: false
        },
        compress: {
          /*
           是否删除代码中所有的console语句,默认为不删除,开启后,会删除所有的console语句
          */
          drop_console: true,

          /*
           是否内嵌虽然已经定义了,但是只用到一次的变量,比如将 var x = 1; y = x, 转换成 y = 5, 默认为不
           转换,为了达到更好的压缩效果,可以设置为false
          */
          collapse_vars: true,

          /*
           是否提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx'  转换成
           var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,可以设置为false
          */
          reduce_vars: true
        }
      }
    }),
  ]
}
复制代码

这里同样推荐篇文章传送门

5. IgnorePlugin

IgnorePlugin插件的主要作用是,在打包时可以忽略无用的的内容,减小打包体积。具体使用可以参考官网的例子传送门

6. DllPlugin

  • 作用

把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。

  • 使用

这里可以参考传送门这篇文件,这个大哥讲的比较详细,这里不再赘述。

最后

除了在打包上做优化之外,在平常写代码中,我们也同样应该注意,考虑性能问题,考虑包的体积。避免因为使用某个库的及少的api而去引入一个很大的库。学会使用按需引入,使用懒加载等。

0 人点赞