构建优化
缩小文件搜索范围
优化 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' } } } }};