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

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

  • 初级分析:使用webpack内置的stats
  • 速度分析:使用speed-measure-webpack-plugin
  • 体积分析: 使用webpack-bundle-analyzer 分析体积
  • 性能提升的方法(针对构建速度和体积优化)
    • 使用高版本的 webpack 和 Node.js
    • 多进程、多实例:解析构建
    • 多进程、多实例:并行压缩
      • 方法一: 使用parallel-uglify-plugin插件
      • 方法二:uglifyjs-webpack-plugin开启parallel参数 (webpack4.0以前推荐)
      • 方法三:terser-webpack-plugin 开启parallel参数 (推荐)
    • 进一步分包:预编译资源模块
      • 方法一:使用html-webpack-externals-plugin (例如将react,react-dom基础包通过cdn引入,不打入bundle中)
      • 方法二:使用SplitChunksPlugin
      • 方法三:使用DLLPlugin进行分包,DIIReferencePlugin对mainfest.json引用 (官方内置的插件)
    • 充分利用缓存提升二次构建速度
    • 缩小构建目标
    • 使用Tree Shaking 擦除无用的JavaScript和CSS
      • 关于 tree shaking
      • 擦除无用的CSS
    • 使用动态Polyfill服务
    • 使用webpack进行图片压缩
    • 体积优化策略总结

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

在package.json中使用stats

 "scripts": {
    "stats": "webpack --json > stats.json"
  },
通过npm run stats 即可生产stas.json文件,json文件内容包含了构建的统计信息

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

使用webpack内置的stas分析,颗粒度比较粗,很难发现文件大小、构建速度的问题所在
使用speed-measure-webpack-plugin可以分析每个loader、plugin的耗时所在
webpack4构建速度和体积优化策略_第1张图片

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
  plugins: [new MyPlugin(), new MyOtherPlugin()],
});

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

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

性能提升的方法(针对构建速度和体积优化)

使用高版本的 webpack 和 Node.js

webpack4刚出来时,和webpack3在推特上做了比较,webpack4的构建时间减低了60%-98%

使用webpack4的原因:

  1. V8带来的优化(for of 代替了forEach、Map和set代替了Object、includes代替indexOf)
  2. 默认使用更快的md4 hash算法 去替代 MD5
  3. webpacks AST 可以直接从loader传递给AST, 减少解析时间
  4. 使用字符串方法替代正则表达式

多进程、多实例:解析构建

可选方案:

  1. thread-loader(官方)
  2. parallel-webpack
  3. HappyPack

使用HappyPack去解析资源
原理:每次webpack解析一个模块,HappyPack会将它及它的依赖分配给worker线程中
webpack - HappyLoader - HappyPlguin (创建线程池) - HappyThreadPool - HappyThread[1…N] (各线程会处理各自负责的模块和依赖) - HappyWorkerChannel[1…N] - HappyWorker[1…N] (HappyPack工作流)

使用thread-loader去解析资源
原理:和HappyPack一致,每次webpack解析一个模块,thread-loader会将它及它的依赖分配给worker线程中

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          'thread-loader',
          // your expensive loader (e.g babel-loader)
        ],
      },
    ],
  },
};

如果需要配置three-loader可以通过配置项的形式

use: [
  {
    loader: 'thread-loader',
    // loaders with equal options will share worker pools
    options: {
      // the number of spawned workers, defaults to (number of cpus - 1) or
      // fallback to 1 when require('os').cpus() is undefined
      workers: 2,
 
      // number of jobs a worker processes in parallel
      // defaults to 20
      workerParallelJobs: 50,
 
      // additional node.js arguments
      workerNodeArgs: ['--max-old-space-size=1024'],
 
      // Allow to respawn a dead worker pool
      // respawning slows down the entire compilation
      // and should be set to false for development
      poolRespawn: false,
 
      // timeout for killing the worker processes when idle
      // defaults to 500 (ms)
      // can be set to Infinity for watching builds to keep workers alive
      poolTimeout: 2000,
 
      // number of jobs the poll distributes to the workers
      // defaults to 200
      // decrease of less efficient but more fair distribution
      poolParallelJobs: 50,
 
      // name of the pool
      // can be used to create different pools with elsewise identical options
      name: 'my-pool',
    },
  },
  // your expensive loader (e.g babel-loader)
];

多进程、多实例:并行压缩

方法一: 使用parallel-uglify-plugin插件

方法二:uglifyjs-webpack-plugin开启parallel参数 (webpack4.0以前推荐)

方法三:terser-webpack-plugin 开启parallel参数 (推荐)

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        parallel: true, // parallel默认值是当前电脑环境CPU数量的2倍减1
      }),
    ],
  },
};

如果你使用的是 webpack v5 或以上版本,你不需要安装这个插件。webpack v5 自带最新的 terser-webpack-plugin。如果使用 webpack v4,则必须安装 terser-webpack-plugin v4 的版本

进一步分包:预编译资源模块

方法一:使用html-webpack-externals-plugin (例如将react,react-dom基础包通过cdn引入,不打入bundle中)

方法二:使用SplitChunksPlugin

方法三:使用DLLPlugin进行分包,DIIReferencePlugin对mainfest.json引用 (官方内置的插件)

一般先创建webpack.dll.js文件对公共基础包、业务基础包进行分包
webpack4构建速度和体积优化策略_第2张图片
然后在webpack.config.js通过webpack.DllReferenctPlugin进行引用
webpack4构建速度和体积优化策略_第3张图片

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

目的:提升二次构建速度
缓存思路:

  1. babel-loader 开启缓存
  2. terser-webpack-plugin开启缓存
  3. 使用 cache-loader 或者 hard-source-webpack-plugin

缩小构建目标

目的:尽可能的少构建模块
比如babel-loader不解析node_modules

减少文件搜索范围

  1. 优化resolve.modules 配置 (减少模块搜索层级)
  2. 优化resolve.mainFields配置
  3. 优化resolve.extensions配置
  4. 合理使用alias (自己标记一下,还是不错的这个alias)

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

关于 tree shaking

概念: 1个模块可能有多个方法,只要其中的某个方法使用到了,则整个文件都会被打到bundle里面去,tree shaking就是只把用到的方法打入bundle,没用到的方法会在uglify阶段被擦除掉。

使用:webpack默认支持,在.babelrc里面设置modules:false即可
production mode 的情况下默认开启

要求:必须是ES6语法,CJS的方法不支持

擦除无用的CSS

使用purgecss-webpack-plugin和mini-css-extract-plugin配合使用

const path = require('path');
const glob = require('glob')
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasureWebpackPlugin();
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const TerserPlugin = require("terser-webpack-plugin");
const webpack = require('webpack');
const PurgeCSSPlugin = require('purgecss-webpack-plugin')


const PATHS = {
    src: path.join(__dirname)
}

module.exports = smp.wrap({
    // 开发者工具 不需要开发调试
    devtool: false,
    // 开发模式 不进行代码压缩
    mode: 'development',
    // 入口文件
    entry: './index.js',
    output: {
      // 输出文件名称
      filename: 'bundle.js',
      // 输出文件路径
      path: path.join(__dirname, './'),
    },
    module: {
        rules: [
            {
                // 正则匹配后缀名为 .css 的文件
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader'],
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin(),
        new PurgeCSSPlugin({
            paths: glob.sync(`${PATHS.src}/*`,  { nodir: true }),  // 只支持绝对路径
        }),
    ],
});
 

使用动态Polyfill服务

使用webpack进行图片压缩

使用image-webpack-loader飞机票

体积优化策略总结

  1. scope Hoisting
  2. Tree-shaking
  3. 公共资源分离
  4. 图片压缩
  5. 动态polyfill

你可能感兴趣的:(webpack,javascript)