happyPack与thread-load
happyPack实现多线程编译
webpack在node中是单线程的,但是在使用webpack编译项目时,loader、plugin需要处理的文件数量很大,webpack单线程处理导致效率低、速度慢,可以使用happyPack来实现多线程工作。
happyPack将不同的loader、plugin工作分配到不同的子线程,在子线程结束完后再推入到主线程中,多线程同时编译,减少编译时间。
基本使用
const path = require('path');
const HappyPack = require('happypack');
module.exports = {
module: {
rules: [
{
test: /.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
exclude: path.resolve(__dirname, 'node_modules'),
},
{
// 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例
test: /.css$/,
use: ExtractTextPlugin.extract({
use: ['happypack/loader?id=css'],
}),
},
]
},
plugins: [
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ['babel-loader?cacheDirectory'],
// ... 其它配置项
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
loaders: ['css-loader'],
}),
new ExtractTextPlugin({
filename: `[name].css`,
}),
],
};
loader配置中,全部交给happyPck/loader处理,其后的 id=babel告诉happyPck/loader选择哪个happyPack实例处理文件
plugin中,options中设置的id和loader中使用的id对应。
实例化happyPack时的其他options
threads代表开启几个子进程去处理这一类型的文件,默认是3个,类型必须是整数。
verbose是否允许HappyPack输出日志,默认是true。
threadPool代表共享进程池,即多个HappyPack实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多,相关代码如下:
const HappyPack = require('happypack')
const os = require('os')
//os nodejs os模块提供了一些基本的系统操作函数
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })
module.exports = {
...
plugins: [
new HappyPack({
id: 'js',
threadPool: happyThreadPool,
loaders: ['babel-loader?cacheDirectory=true']
}),
]
}
基本原理
在整个 Webpack 构建流程中,最耗时的流程可能就是Loader对文件的转换操作了,因为要转换的文件数据巨多,而且这些转换操作都只能一个个挨着处理。 HappyPack的核心原理就是把这部分任务分解到多个进程去并行处理,从而减少了总的构建时间。
所有需要通过Loader处理的文件都先交给了happypack/loader去处理,收集到了这些文件的处理权后HappyPack就好统一分配了。
每通过new HappyPack()实例化一个HappyPack其实就是告诉HappyPack核心调度器如何通过一系列Loader去转换一类文件,并且可以指定如何给这类转换操作分配子进程。
核心调度器的逻辑代码在主进程中,也就是运行着Webpack的进程中,核心调度器会把一个个任务分配给当前空闲的子进程,子进程处理完毕后把结果发送给核心调度器,它们之间的数据交换是通过进程间通信API实现的。
核心调度器收到来自子进程处理完毕的结果后会通知Webpack该文件处理完毕
thread-load替代happyPack
happyPack的作者不维护了,现在使用thread-load
使用thread-load可以实现将不同编译工作放入不同的工作池中运行。
将thread-load放在其他loader的前面即可,那么在它其后的loader就会单独运行在一个工作池中。