webpack如何优化?

1,019 阅读2分钟

速度分析

使用speed-measure-webpack-plugin,可以看到loader和插件的执行耗时。

const SpeedMeasureWebpackPlugin=require('speed-measure-webpack-plugin');
const smp=new SpeedMeasureWebpackPlugin();
const webpackConfig=smp.warp{(
...
)}

体积分析

使用webpack-bundle-analyzer,构建完成后会在8888端口展示大小。

const {BundleAnalyzerPlugin}=require('webpack-bundle-analyzer');
module.exports={
plugins:[
   new BundleAnalyzerPlugin()
  ]
}

多进程、多实例构建

可选方案:

  • thread-loader
  • happyPack(不维护了,不支持ES6) 原理:每次webpack解析一个模块,将它及它的依赖分配给worker线程中
module.exports={
 module: {
   rules: [
            {
                test: /.js$/,
                include:path.resolve('src'),
                use: [
                    {
                      loader: 'thread-loader',
                       options: {
                          workers:3
                        }
                    },
                    'babel-loader?cacheDirectory=true'
                ]
            },
         ]
}

多进程并行压缩代码

可选方案:

  • parallel-uglify-plugin
  • uglifyjs-webpack-plugin 开启parallel(不支持ES6)
  • terser-webpack-plugin 开启parallel
const TerserPlugin=require('terser-webpack-plugin');
module.exports={
   optimization: {
        minimizer:[
            new TerserPlugin({
                parallel:4 //默认cup*2-1
            })
        ]
}

充分利用缓存提升二次构建速度

缓存思路:

  • babel-loader开启缓存
  • terser-webpack-plugin开启缓存
  • 使用cache-loader 或者hard-source-webpack-plugin
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports={
 module: {
   rules: [
            {
                test: /.js$/,
                include:path.resolve('src'),
                use: [
                    'babel-loader?cacheDirectory=true'
                    ]
            },
      ]
   },
  plugins:[
       new HardSourceWebpackPlugin()
    ],
  optimization: {
        minimizer:[
            new TerserPlugin({
                cache: true
            })
        ]
  }
}

缩小构建目标

目的:尽可能的少构建模块 减少文件搜索范围:


module.exports={
  resolve:{
    alias:{
        'react':path.resolve(__dirname,'./node_modules/react/umd/react.production.min.js'),
        'react-dom':path.resolve(__dirname,'./node_modules/react-dom/umd/react-dom.production.min.js'),
    },
    extensions:['.js'],
    mainFields:['main']
}
}

使用Tree Shaking擦除无用的JavaScript和CSS

  • 概念:一个模块可能有多个方法,只要其中某个方法使用到了,则整个文件都会被打包到bundle里面。tree shaking就是只把用到的放到打包到bundle,没用的方法会在uglify阶段被擦除掉。
  • 原理:利用ES6模块的特点:只作为模块顶层的语句出现。import的模块名只能是字符串常量。improt binding是immutable的。
  • 使用:webpack默认支持,.babelrc里设置modules:false即可。production mode的情况下默认开启。
  • 要求:必须是ES6的语法,commonJS的方式不支持 使用purgecss-webpack-plugin搭配mini-css-extract-plugin擦除无用的css
const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const PurgecssPlugin = require('purgecss-webpack-plugin');
const PATHS = {
    src: path.join(__dirname, 'src')
};
module.exports={
 module: {
   rules: [
            {
                test: /.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },
      ]
   },
 plugins:[
      new MiniCssExtractPlugin({
            filename: '[name]_[hash:8].css'
        }),
      new PurgecssPlugin({
            paths: glob.sync(`${PATHS.src}/**/*`,  { nodir: true }),
       }),
  ]
}

图片压缩

使用image-webpack-loader

const {BundleAnalyzerPlugin}=require('webpack-bundle-analyzer');
module.exports={
  moudle:{
    rules:[
    {
                test: /.(png|jpg|gif|jpeg)$/,
                use: [
                    {
                        loader: "file-loader",
                        options: {
                            name: '[name]_[hash:8].[ext]'
                        }
                    },
                    {
                        loader: 'image-webpack-loader',
                        options: {
                            mozjpeg: {
                                progressive: true,
                                quality: 65
                            },
                            optipng: {
                                enabled: false,
                            },
                            pngquant: {
                                quality: '65-90',
                                speed: 4
                            },
                            gifsicle: {
                                interlaced: false,
                            },
                            webp: {
                                quality: 75
                            }
                        }
                    }
                ]
            },
    ]
  }
}