本周接到一个优化项目打包速度的任务,开始我是一脸懵逼的,之前未曾做过类似的任务,而且对webpack配置也不是太精通。头疼之际,google了网上大神的意见,并以身试毒,这里面有很多坑,现总结一下我用到的优化方式
优化后对比
我们先看看优化之前的打包时间:62.74s
优化之后的打包时间:18.24
优化方法
配置include
和 exclude
- 使用 include 精确指定要处理的目录,这可以减少不必要的遍历,从而减少性能损失。
- 使用 exclude 对已明确知道的,不需要处理的目录,予以排除,从而进一步提升性能
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig,
include: [resolve('src'), resolve('node_modules/vue-easytable/libs')],
exclude: /node_modules\/(?!(autotrack|dom-utils))|vendor\.dll\.js/
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src')],
exclude: /node_modules/
},
css-loader使用0.15.0以下的版本
个版本以上的速度会慢许多,不过在我的项目中还没看到明显变化
使用 HappyPack
运行在 Node.js 之上的 Webpack 是单线程模型的,也就是说 Webpack 需要处理的任务需要一件件挨着做,不能多个事情一起做。
那能不能让 Webpack 同一时刻处理多个任务,发挥多核 CPU 电脑的威力,以提升构建速度呢?
HappyPack 就能让 Webpack 做到这点,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
// 接入happypack
const HappyPack = require('happypack')
const os = require('os')
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
var vueLoaderConfig = require('./vue-loader.conf')
module.exports = {
module: {
rules: [{
test: /\.css$/,
loader: 'happypack/loader?id=css'
}, {
test: /\.less$/,
loader: 'happypack/loader?id=less'
},
{
test: /\.vue$/,
loader: 'happypack/loader?id=vue'
},
{
test: /\.js$/,
loader: 'happypack/loader?id=js',
include: [resolve('src'), resolve('test')]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'happypack/loader?id=font'
}
]
},
plugins: [
new HappyPack({
id: 'css',
loaders: [{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
minimize: true,
sourceMap: true
}
}
],
threadPool: happyThreadPool,
verbose: false
}),
new HappyPack({
id: 'less',
loaders: [{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
minimize: true,
sourceMap: true
}
}, {
loader: require.resolve('less-loader'),
}
],
threadPool: happyThreadPool,
verbose: false
}),
new HappyPack({
id: 'vue',
loaders: [{
loader: 'vue-loader',
options: vueLoaderConfig
}],
threadPool: happyThreadPool,
verbose: false
}),
new HappyPack({
id: 'js',
loaders: [{
loader: 'babel-loader?cacheDirectory=true'
}],
threadPool: happyThreadPool,
verbose: false
}),
new HappyPack({
// 用id来标识 happypack处理那里类文件
id: 'font',
// 如何处理 用法和loader 的配置一样
loaders: [{
loader: 'url-loader?cacheDirectory=true',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}],
//共享进程池
threadPool: happyThreadPool,
// 允许 HappyPack 输出日志
verbose: false
}),
],
};
以上代码有两点重要的修改:
- 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。
- 在 Plugin 配置中,新增了两个 HappyPack 实例分别用于告诉 happypack/loader 去如何处理 .js 和 .css 文件。选项中的 id 属性的值和上面 querystring 中的 ?id=babel 相对应,选项中的 loaders 属性和 Loader 配置中一样。
它对file-loader和url-loader支持不好,所以这两个loader就不需要换成happypack了