Vuejs项目 Webpack2构建优化

转载自:https://molunerfinn.com/Webpack-Optimize/#%E5%BC%80%E5%90%AFbabel-loader%E7%9A%84cache

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

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

有些是在开发的时候代码层面上的,有些则是需要在webpack配置层面上的。对于开发层面上来说,按需引入是很重要的一点。通常为了方便我们可以直接引入一个echarts,但是实际上并不需要echarts的所有功能。而按需引入则能最大程度上让

总得来说作用最大的有这几个:

  • 开启webpack的cache
  • 开启babel-loader的cache
  • 指定modules以及配置项目相关的alias
  • 配置loaderincludeexclude
  • CommonsChunkPlugin提取公用模块
  • 使用DllPluginDllReferencePlugin预编译
  • 换用happypack多进程构建
  • css-loader换成0.14.5版本。
  • 换用webpack-uglify-parallel并行压缩代码

以下的配置都是基于vue-cliwebpack模板进行的优化。

开启webpack的cache

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

1
2
3
4
module.exports = {
  cache: true,
  // ... 其他配置
}

开启babel-loader的cache

开启了cache的babel-loader,在下次编译的时候,遇到不变的部分可以直接拿取cache里的内容,能够较为明显地提高构建速度。在loader选项里只需要对babel-loader开启cacheDirectory=true即可。

1
2
3
4
5
6
7
8
9
10
// ... 其他配置
module: {
  rules: [
    {
      test: /\.js$/,
      loader: ['babel-loader?cacheDirectory=true']
    },
    // ... 其他loader
  ]
}

配置modules以及配置项目相关的alias

这个部分的配置实际上都是对webpack接管的文件路径的一些配置。通过这些配置,webpack可以不必自己遍历去搜索模块等,而可以通过我们定义的路径,快速定位。尤其是node_modules的位置,这个位置可以通过modules选项配置,节省webpack去查找的时间。

alias是别名。通过编写alias,既能让webpack查找文件定位更快,在开发的时候,也能少些很多相对路径的../..,在引入模块的时候很方便。

同样是打开webpack.base.conf.js,在module.exportsresolve属性里配置modulesalias。其中vue-cli会自动配置一些默认的alias

1
2
3
4
5
6
7
8
9
resolve: {
  //... 其他配置
  modules: [path.resolve(__dirname, '../../node_modules')], // node_modules文件夹所在的位置取决于跟webpack.base.conf.js相对的路径
  alias: {
    //... 其他配置
    api: path.resolve(__dirname, '../../server/api') // api文件所在的位置取决于跟webpack.base.conf.js相对的路径,在项目中会自动转换跟项目文件的相对路径
    //... 其他配置
  }
}

如果配置了如上的alias,那么我们在项目里,要引用比如api.js这个模块,可以直接这样做了:

1
2
import * as api from 'api' // 'api'是个alias,webpack会直接去找`server/api`

而不用手动去根据项目文件和api所在路径的相对位置去书写import的路径了。

配置loaderincludeexclude

loaderincludeexclude也就是需要loader接管编译的文件和不需要loader接管编译的文件。

这里我们举babel-loader为例。通常情况下,我们不需要loader去编译node_modules下的js文件,而我们只需要编译我们项目目录下的js就行了。这样可以通过配置这两个选项,能够最小范围的限制babel-loader需要编译的内容,能够有效提升构建速度。

同样打开webpack.base.conf.js,在rulesbabel-loader那块加上includeexclude

1
2
3
4
5
6
7
8
9
10
11
12
// ... 其他配置
module: {
  rules: [
    {
      test: /\.js$/,
      loader: ['babel-loader?cacheDirectory=true'],
      include: [resolve('src')], // src是项目开发的目录
      exclude: [path.resolve('../../node_modules')] // 不需要编译node_modules下的js 
    },
    // ... 其他loader
  ]
}

使用CommonsChunkPlugin提取公用模块

我们经常会有这种场景:在a.vue组件里引入了a.js或者比如c.vue,在b.vue组件里也引入了a.js或者c.vue。这样,打包了之后将会把引入的模块重复打包。而CommonsChuncksPlugin就是把这样重复打包的模块给抽取出来单独打包的插件。这个能够显著降低最后打包的体积,也能提升一些打包速度。

webpack.base.conf.js里的plugins可以加上这段:

1
2
3
4
5
6
7
8
9
10
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    async: 'shared-module',
    minChunks: (module, count) => (
      count >= 2    // 当一个模块被重复引用2次或以上的时候单独打包起来。 
    )
  }),

  //...
]

使用DllPluginDllReferencePlugin预编译

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

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

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

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

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
  //... 其他配置
  
  plugins: [
    // ... 其他插件
    new webpack.DllReferencePlugin({
      context: __dirname,
      manifest: require('../../public/js/vendor-mainfest.json') // 指向这个json
    })
  ]
}

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

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

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

换用happypack多进程构建

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
const os = require('os');
const HappyPack  = require('happypack');
const happThreadPool = HappyPack.ThreadPool({size: os.cpus().length}); // 采用多进程,进程数由CPU核数决定

//...
module.exports = {
  plugins: [
    // ...
    new HappyPack({
      id: 'js',
      cache: true,
      loaders: ['babel-loader?cacheDirectory=true'],
      threadPool: happThreadPool
    })
  ],
  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 
      },
      //...
    ]
  }
}

提速还是比较明显的。

css-loader换成0.14.5版本

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

换用webpack-uglify-parallel并行压缩代码

webpack自带的uglifyjs插件效果确实不错。只不过由于受限于单线程,所以压缩速度不够高。换成webpack-uglify-parallel这个插件之后能够有效减少压缩的时间。

首先安装:npm install webpack-uglify-parallel --save-dev 或者 yarn add webpack-uglify-parallel

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

1
2
3
4
5
6
7
8
9
plugins: [
  new webpack.optimize.UglifyJsPlugin({
    compress: {
      warnings: false
    },
    sourceMap: true
  })
  // ... 其他配置
]

替换为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const UglifyJsparallelPlugin = require('webpack-uglify-parallel');
const os = require('os');

// ... 其他配置
plugins: []
new UglifyJsparallelPlugin({
  workers: os.cpus().length,
  mangle: true,
  compressor: {
    warnings: false,
    drop_console: true,
    drop_debugger: true
  }
})

猜你喜欢

转载自blog.csdn.net/qq_31687021/article/details/89543411