Galan小屋

welcome my blog

Vuejs项目的Webpack2构建优化

By galan99

发表于 2018-07-03

优化webpack构建速度,总的来说有几个思路:

  • 优化本身项目结构,模块的引入、拆分、共用
  • 优化结构路径、让webpack接管的文件能够快速定位
  • 优化uglify编译速度
  • 优化webpack本身编译速度

开启webpack的cache

打开webpack.base.conf.js,在module.exports里加上cache: true:

module.exports = {
  cache: true,
  // ... 其他配置
}

换用happypack多进程构建

webpack的构建毕竟还是单进程的。采用happypack可以改为多进程构建。而对于小文件而言,happypack效果并不明显。而对于babel-loader编译的庞大的js文件群来说,则是一大利器。

首先安装:npm install happypack –save-dev或者yarn add happypack

然后修改webpack.base.conf.js的配置如下:

const os = require('os');
const HappyPack  = require('happypack');
const happThreadPool = HappyPack.ThreadPool({size: os.cpus().length}); // 采用多进程,进程数由CPU核数决定

module: {
  rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            js: 'happypack/loader?id=js' // 将loader换成happypack
          }
        }
      },
      {
        test: /\.js$/,
        loader: ['happypack/loader?id=js'], // 将loader换成happypack
        include: [resolve('src')], // src是项目开发的目录
        exclude: [path.resolve('../../node_modules')] // 不需要编译node_modules下的js 
      },
      // ... 其他loader
  ]
},
plugins: [
    new HappyPack({
      id: 'js',
      loaders: ['babel-loader?cacheDirectory=true'],
      threadPool: happThreadPool
    }),
    new webpack.optimize.CommonsChunkPlugin('common.js'),
]

css-loader换成0.14.5版本

可以查看这个issue,说是该版本之上的版本会拖慢webpack的构建速度。我自己实验了之后确实能快几秒钟。

增强代码代码压缩工具

Webpack 默认提供的 UglifyJS 插件,由于采用单线程压缩,速度颇慢 ;推荐采用 webpack-parallel-uglify-plugin 插件,她可以并行运行 UglifyJS 插件,更加充分而合理的使用 CPU 资源,这可以大大减少的构建时间;当然,该插件应用于生产环境而非开发环境,其做法如下

首先安装:npm install webpack-parallel-uglify-plugin –save

找到webpack.prod.conf.js(由于开发模式不需要进行uglify压缩),将原本的:

const UglifyJsparallelPlugin = require('webpack-uglify-parallel');
const os = require('os');

plugins: [
  //使用 HashedModuleIdsPlugin 解决 hash 频繁变动的问题,webpack的持久化缓存方案
  new webpack.HashedModuleIdsPlugin(),

  //js旧的压缩
  // new webpack.optimize.UglifyJsPlugin({
  //   compress: {
  //     warnings: false
  //   },
  //   sourceMap: true
  // }),
  new ParallelUglifyPlugin({
    cacheDir: '.cache/',
    uglifyJS:{
      output: {
        comments: false
      },
      compress: {
        warnings: false
      }
    }
  }),
]

当然也有其他同类型的插件,比如:webpack-uglify-parallel,但根据自己实践效果来看,并没有webpack-parallel-uglify-plugin表现的那么卓越,需要额外说明的是,webpack-parallel-uglify-plugin 插件的运用,会相对 UglifyJsPlugin 打出的包,看起来略大那么一丢丢(其实可以忽略不计);如果在你使用时也是如此,那么在打包速度跟包体积之间,你应该有自己的抉择。

使用DllPlugin和DllReferencePlugin预编译

这个也是一个大杀器。将一些全局都要用到的依赖抽离出来,预编译一遍,然后引入项目中,作为依赖项。而webpack在正式编译的时候就可以放过他们了。能够很明显地提升webpack的构建速度。dll资源能够有效的解决资源循环依赖的问题。能够大大减少项目里重复依赖的问题。

在webpack.base.conf.js所在的文件夹里建立一个webpack.dll.conf.js,我们将一些常用的依赖打包成dll。

首先配置一下DllPlugin的资源列表。

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    vendor: ['vue/dist/vue.esm.js','vue-router','axios','vuex'] // 需要打包起来的依赖
  },
  output: {
    path: path.join(__dirname, '../../public/js'), // 输出的路径
    filename: '[name].dll.js', // 输出的文件,将会根据entry命名为vendor.dll.js
    library: '[name]_library' // 暴露出的全局变量名
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '../../public/js/', '[name]-mainfest.json'), // 描述依赖对应关系的json文件
      name: '[name]_library', 
      context: __dirname // 执行的上下文环境,对之后DllReferencePlugin有用
    }),
    new webpack.optimize.UglifyJsPlugin({ // uglifjs压缩
      compress: {
        warnings: false
      }
    })
  ]
}

为了方便之后构建,可以在package.json里加上这么一句scripts

scripts: {
  //... 其他scripts
  "build:dll": "webpack --config ./webpack/build/webpack.dll.conf.js" // 填写你项目中webpack.dll.conf.js的路径
}

然后执行一下npm run build:dll,就可以在输出的目录里输出一个vendor.dll.js和vendor-mainfest.json两个文件。

之后打开webpack.base.conf.js。在plugins一项里加上DllReferencePlugin。这个plugin是用于引入上一层里生成的json的。

module.exports = {
  //... 其他配置
  
  plugins: [
    // ... 其他插件
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('../../public/js/vendor-mainfest.json') // 指向这个json
    })
  ]
}

最后,在项目输出的index.html里,最先引入这个js:

<script type="text/javascript" src="public/js/vendor.dll.js"></script>

这样,webpack将不会再解析dll里的资源了。构建速度将会有质的提高。


结语:除了上面的DllPlugin这个没用,其他都用上了,之前的打包时间也从120s变成了60s,开发阶段时编译也提升很大,效果还是挺好的。