webpack全方位由浅到深讲解,做到简历上真正所谓的“熟悉”(系列三)

858 阅读2分钟

webpack构建速度和体积优化策略

初级分析: 使用webpack内置的stats

  • stats: 构建的统计信息
  • pakeage.json 使用stats
方式一:
"scripts": {
    "build:stats": "webpack --env production --json > stats.json"
},
方式二:
// node.js中使用
const prodConfig = require('../../lib/webpack.prod.js');

webpack(prodConfig, (err, stats) => {
    if (err) {
        console.error(err);
        process.exit(2);
    }
    console.log(stats);
});

颗粒度太粗,看不出问题所在

速度分析: 使用 speed-measure-webpack-plugin

  • 分析整个打包总耗时
  • 每个插件和loader的耗时情况
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasureWebpackPlugin();
module.exports = smp.wrap({
    ...
})

image.png

体积分析: 使用webpack-bundle-analyzer

  • 可以分析哪些问题
    • 依赖的第三方模块文件大小
    • 业务里面的组件代码大小
const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
plugins:[
    new BundleAnalyzerPlugin()
]

使用高版本的webpack和Node.js

多进程/多实例构建

  • 使用thread-loader解析资源
{
    test: /\.js$/,
    use: [
        {
            loader: 'thread-loader',
            options: {
                workers: 3
            }
        },
        'babel-loader'
    ]
}

原理: 每次webpack解析一个模块,thread-loader会将它及它的依赖分配给worker线程中

多进程并行压缩代码

使用 terser-webpack-plugin 开启parallel参数

optimization: {
    minimizer: [
         new TerserPlugin({
             parallel: true
         })
     ]
}

分包: 预编译资源模块

思路: 将基础包和业务组件包打成一个文件

方法: 使用DLLPlugin进行分包, DllReferencePlugin对manifest.json引用

// 新建webpack.dll.js
const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: {
        library: [
            'react', 
            'react-dom'
        ]
    },
    output: {
        filename: '[name]_[chunkhash].dll.js',
        path: path.join(__dirname,'build/library'),
        library: '[name]'
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]_[hash]',
            path: path.join(__dirname,'build/library/[name].json'),
        })
    ]
}

// webpack.prod.js
plugins: [
    new webpack.DllReferencePlugin({
        manifest: require('./build/library/library.json')
    })
]

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

  • 缓存思路
    • babel-loader开启缓存
      {
          test: /\.js$/,
          use: [
              'babel-loader?cacheDirectory=true'
          ]
      }
      
    • terser-webpack-plugin开启缓存
      optimization: {
          minimizer: [
              new TerserPlugin({
                  parallel: true,
                  cache: true
              })
          ]
      }
      
    • 使用cache-loader 或者 hard-source-webpack-plugin
      plugins: [
          new HardSourceWebpackPlugin()
      ]
      

缩小构建目标

  • 目的: 尽可能的少构建模块。比如babel-loader不解析node_modules
{
    test: /\.js$/,
    include: path.resolve('src'),
    exclude: 'node_modules',
    use: [
        'babel-loader'
    ]
},
  • 减少文件搜索范围
    • 优化 resolve.modules配置(减少模块搜索层级)
    • 优化 resolve.mainFields配置
    • 优化 resolve.extensions配置
    • 合理使用 alias
    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'],
        mainFiles: ['main']
    }
    

Tree Shaking擦除无用的JavaScript和Css

    1. 擦除无用的JavaScript(见webpack全方位由浅到深讲解,做到简历上真正所谓的“熟悉”(系列一)
    1. 擦除无用的Css
    • 使用 purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用
    const PurgecssWebpackPlugin = require('purgecss-webpack-plugin')
    const PATHS = {
        src: path.join(__dirname, 'src')
    }
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name][contenthash:8].css'
        }),
        new PurgecssWebpackPlugin({
            paths: glob.sync(`${PATHS.src}/**/*`, {nodir: true})
        })
    ]
    

图片压缩

  • 要求:基于 Node 库的imagemin或者tinypng API
  • 使用:配置image-webpack-loader
rules: [{
  test: /\.(gif|png|jpe?g|svg)$/i,
  use: [
    'file-loader',
    {
      loader: 'image-webpack-loader',
      options: {
        mozjpeg: {
          progressive: true,
        },
        // optipng.enabled: false will disable optipng
        optipng: {
          enabled: false,
        },
        pngquant: {
          quality: [0.65, 0.90],
          speed: 4
        },
        gifsicle: {
          interlaced: false,
        },
        // the webp option will enable WEBP
        webp: {
          quality: 75
        }
      }
    },
  ],
}]

动态使用Polyfill

  • 原理: 识别 User Agent, 下发不同的 Polyfill

  • 如何使用动态 Polyfill service

    • polyfill.io 官方提供的服务
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
    
    • 基于官方自建 polyfill服务

最后