HappyPack通过并行转换文件使得初始webpack构建更快。这句话可不是我说的,是npm官网中happypack的readme的开场白。
我在前几天的《vue项目打包优化之webpack-parallel-uglify-plugin》一文中提到过happypack,我说它有些鸡肋,为什么这么说呢,如果项目较小,可能打包时间优化的并不是太好,甚至可能还会延长打包时间。不过在公司项目中我再使用webpack-parallel-uglify-plugin之后项目打包时间大概在3分钟左右,在此基础上使用happypack优化之后,时间缩短了将近一分钟。
现在我将happypack配置做个记录和说明,以自己的demo为例。项目是用vuecli脚手架搭建。
首先我们先了解一下happypack的一些参数
id: String
用唯一的标识符 id。加载程序使用它来知道它应该与哪个插件进行通.loaders: Array
用法和 webpack Loader 配置中一样.threads: Number
代表开启几个子进程去处理这一类型的文件。默认为:3
verbose: Boolean
启用此选项可将状态消息从HappyPack记录到STDOUT,默认是 true。threadPool: HappyThreadPool
代表共享进程池,即多个 HappyPack 实例都使用同一个共享进程池中的子进程去处理任务,以防止资源占用过多。默认为:null
verboseWhenProfiling: Boolean
如果您希望HappyPack即使在webpack --profile
运行时仍能生成其输出,请启用此选项。默认为:false
debug: Boolean
启用此选项可将诊断消息从HappyPack记录到STDOUT。用于故障排除。默认false
。
接下来是demo中的配置
第一步,安装happypack
npm i happypack -D
//"happypack": "^5.0.1",demo中happypack版本
//"webpack": "^3.6.0",demo中webpack版本
第二步,配置happypack
1、修改webpack.base.conf.js文件
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
提示:由于HappyPack 对file-loader、url-loader 支持的不友好,所以没修改相应loader使用。
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath },
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'happypack/loader?id=vueLoader',
},
{
test: /\.js$/,
loader: 'happypack/loader?id=babelLoader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
},
plugins:[
new HappyPack({
//用id来标识 happypack处理那里类文件
id: 'vueLoader',
//如何处理 用法和loader 的配置一样
loaders: [
{
loader:'vue-loader',
options: vueLoaderConfig
}
],
//共享进程池
threadPool: happyThreadPool,
//允许 HappyPack 输出日志
verbose: true,
}),
new HappyPack({
//用id来标识 happypack处理那里类文件
id: 'babelLoader',
//如何处理 用法和loader 的配置一样
loaders: [
{
loader:'babel-loader',
}
],
//共享进程池
threadPool: happyThreadPool,
//允许 HappyPack 输出日志
verbose: true,
})
]}
2、修改utils.js文件
const HappyPack = require('happypack');
const os = require('os');
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
提示:由于HappyPack 对less-loader、sass-loader、stylus-loader支持的不友好,所以没修改相应loader使用。
exports.styleLoaders = function (options) {
const output = []
const plugins = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
if(extension!='less'&&extension!='sass'&&extension!='scss'&&extension!='stylus'&&extension!='styl'){
output.push({
test: new RegExp('\\.' + extension + '$'),
use: [`happypack/loader?id=${extension}Loader`]
})
plugins.push(
new HappyPack({
//用id来标识 happypack处理那里类文件
id: `${extension}Loader`,
//如何处理 用法和loader 的配置一样
loaders: loader,
//共享进程池
threadPool: happyThreadPool,
//允许 HappyPack 输出日志
verbose: true,
})
)
}else{
output.push({
test: new RegExp('\\.' + extension + '$'),
use: loader
})
}
}
return {output,plugins}
}
由于更改了css的规则,所以需要修改相关引用处的配置
3、修改webpack.dev.conf.js文件
const styleLoaders= utils.styleLoaders({ sourceMap: config.dev.cssSourceMap,
usePostCSS: true
})
const devWebpackConfig = merge(baseWebpackConfig, {plugins:styleLoaders.plugins},{
module: {
rules: styleLoaders.output
},
// cheap-module-eval-source-map is faster for development
devtool: config.dev.devtool,
...
})
4、修改webpack.prod.conf.js文件
const styleLoaders= utils.styleLoaders({
sourceMap: config.build.productionSourceMap,
extract: true,
usePostCSS: true
})
const webpackConfig = merge(baseWebpackConfig, {plugins:styleLoaders.plugins},{
module: {
rules: styleLoaders.output
},
devtool: config.build.productionSourceMap ? config.build.devtool : false,
...
})
TIME!