构建优化
缩小文件搜索范围
优化 loader 配置
通过 test
、include
、exclude
三个配置项,减少 loader 处理的文件
优化 resolve.modules 配置
当安装的第三方模块都放在项目根目录下的 ./node_modules
目录下时,没有必要按照默认的方式去一层层的寻找,可以指明存放第三方模块的绝对路径,以减少寻找。
module.exports = {
resolve: {
// 使用绝对路径指明第三方模块存放的位置,以减少搜索步骤
// 其中 __dirname 表示当前工作目录,也就是项目根目录
modules: [path.resolve(__dirname, 'node_modules')]
},
};
优化 module.noParse 配置
module.noParse
配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。
module.exports = {
module: {
// index.html 中外部链接引入的文件
noParse: [/jquery|lodash/],
},
};
使用 HappyPack
在整个 Webpack 构建流程中,最耗时的流程可能就是 Loader 对文件的转换操作了,因为要转换的文件数据巨多,而且这些转换操作都只能一个个挨着处理。HappyPack 的核心原理就是把这部分任务分解到多个进程去并行处理,从而减少了总的构建时间。
安装依赖
npm i -D happypack
接入配置
const HappyPack = require('happypack');
const os = require('os'); // node 提供的系统操作模块
// 构造出共享进程池,根据我的系统的内核数量 指定线程池个数 也可以其他数量
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length});
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'],
// 使用共享进程池中的子进程去处理任务
threadPool: happyThreadPool,
}),
new HappyPack({
id: 'css',
// 如何处理 .css 文件,用法和 Loader 配置中一样
loaders: ['css-loader'],
// 使用共享进程池中的子进程去处理任务
threadPool: happyThreadPool,
})
],
};
使用 ParallelUglifyPlugin
由于压缩 JavaScript 代码需要先把代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理 AST,导致这个过程计算量巨大,耗时非常多。
当 Webpack 有多个 JavaScript 文件需要输出和压缩时,原本会使用 UglifyJS 去一个个挨着压缩再输出,但是 ParallelUglifyPlugin 则会开启多个子进程,把对多个文件的压缩工作分配给多个子进程去完成,每个子进程其实还是通过 UglifyJS 去压缩代码,但是变成了并行执行。所以 ParallelUglifyPlugin 能更快的完成对多个文件的压缩工作。
npm i -D webpack-parallel-uglify-plugin
const path = require('path');
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
module.exports = {
plugins: [
// 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
new ParallelUglifyPlugin({
// 开启几个子进程去并发的执行压缩。默认是当前运行电脑的 CPU 核数减去 1。workerCount: 4,
// 传递给 UglifyJS 的参数
uglifyJS: {
output: {
// 最紧凑的输出
beautify: false,
// 删除所有的注释
comments: false,
},
compress: {
// 在 UglifyJs 删除没有用到的代码时不输出警告
warnings: false,
// 删除所有的 `console` 语句,可以兼容 ie 浏览器
drop_console: true,
// 内嵌定义了但是只用到一次的变量
collapse_vars: true,
// 提取出出现多次但是没有定义成变量去引用的静态值
reduce_vars: true,
}
},
}),
],
};
输出质量优化
使用 imagemin-webpack-plugin 插件
import ImageminPlugin from 'imagemin-webpack-plugin'
module.exports = {
plugins: [
// Make sure that the plugin is after any plugins that add images
new ImageminPlugin({
disable: process.env.NODE_ENV !== 'production', // Disable during development
test: /\.(gif|png|jpe?g|svg)$/i,
onlyUseIfSmaller: true
})
]
}
chainWebpack
配置
import ImageminWebpackPlugin from 'imagemin-webpack-plugin';
module.exports = {
chainWebpack: config => {config.plugin('imagemin-webpack-plugin')
.use(ImageminWebpackPlugin, [
{
disable: process.env.NODE_ENV !== 'production'
test: /\.(gif|png|jpe?g|svg)$/i,
onlyUseIfSmaller: true
}
]);
}
}
提取公共代码
将所有从 node_modules
的引用打包到一个名字叫 vendor 的 chunk
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};