性能文章>webpack构建速度和体积优化策略>

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

301213

前言

对自己性能优化以及webpack优化进行总结,目前文章对webpack进行了描述,后续会对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的耗时所在 

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

const **p = new SpeedMeasurePlugin();

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

体积分析: 使用webpack-bundle-****yzer 分析体积

const BundleAnalyzerPlugin = require('webpack-bundle-****yzer').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文件对公共基础包、业务基础包进行分包 然后在webpack.config.js通过

webpack.DllReferenctPlugin进行引用 

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

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

  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 **p = new SpeedMeasureWebpackPlugin();
const BundleAnalyzerPlugin = require('webpack-bundle-****yzer').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 = **p.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


作者:左耳咚

点赞收藏
分类:标签:
(งᵒ̌皿ᵒ̌)ง⁼³₌₃
请先登录,查看1条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步
3
1