重构项目,用得上的 Webpack 性能工具

核心流程

Webpack 最最核心的功能,一是使用适当 Loader 将任意类型文件转译成 JavaScript 代码,二是将这些经过 Loader 处理的文件资源合并、打包成向下兼容的产物文件。

为了实现这些功能,Webpack 底层的工作流程大致可以总结为这几个阶段:

  1. 初始化阶段:

    • 初始化参数:从配置文件、配置对象、Shell 参数中读取,与默认配置结合得出最终的参数
    • 创建编译器对象:用上一步得到的参数创建 Compiler 对象
    • 初始化编译环境:包括注入内置插件、注册各种模块工厂、初始化 RuleSet 集合、加载配置的插件等
    • 开始编译:执行 compiler 对象的 run 方法,创建 Compilation 对象
    • 确定入口:根据配置中的entry找出所有的入口文件,调用compilation.addEntry将入口文件转换为dependence对象
  2. 构建阶段:

    • 编译模块:从entry文件开始,调用loader将模块转译为标准 JS 内容,调用 JS 解析器将内容转换为 AST 对象,从中找出该模块依赖的模块,再递归处理这些依赖模块,直到所有入口依赖的文件都经过了本步骤的处理
    • 完成模块编译:模块编译完成后,输出每个模块被编译后的内容以及它们之间的依赖关系图
  3. 封装阶段:

    • 合并:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk
    • 优化:对上述Chunk施加一系列优化操作,包括:tree-shaking、terser、scope-hoistring、压缩、Code Split等
    • 写入文件系统:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

性能分析

有许多被反复实践、行之有效的构建性能优化手段,包括并行编译、缓存、缩小资源搜索范围等等,但在介绍这些具体的优化方法之前,有必要先聊聊:如何收集、分析 Webpack 打包过程的性能数据。

收集数据的方法很简单 ------ Webpack 内置了 stats 接口,专门用于统计模块构建耗时、模块依赖关系等信息,推荐用法:

  1. 添加 profile = true 配置:
java 复制代码
// webpack.config.js
module.exports = {
  // ...
  profile: true
}
  1. 运行编译命令,并添加 --json 参数,参数值为最终生成的统计文件名,如:
ini 复制代码
npx webpack --json=stats.json

上述命令执行完毕后,会在文件夹下生成 stats.json 文件,内容大致如下:

json 复制代码
{
  "hash": "2c0b66247db00e494ab8",
  "version": "5.36.1",
  "time": 81,
  "builtAt": 1620401092814,
  "publicPath": "",
  "outputPath": "/Users/tecvan/learn-webpack/hello-world/dist",
  "assetsByChunkName": { "main": ["index.js"] },
  "assets": [
    // ...
  ],
  "chunks": [
    // ...
  ],
  "modules": [
    // ...
  ],
  "entrypoints": {
    // ...
  },
  "namedChunkGroups": {
    // ...
  },
  "errors": [
    // ...
  ],
  "errorsCount": 0,
  "warnings": [
    // ...
  ],
  "warningsCount": 0,
  "children": [
    // ...
  ]
}

stats 对象收集了 Webpack 运行过程中许多值得关注的信息,包括:

  • modules:本次打包处理的所有模块列表,内容包含模块的大小、所属 chunk、构建原因、依赖模块等,特别是 modules.profile 属性,包含了构建该模块时,解析路径、编译、打包、子模块打包等各个环节所花费的时间,非常有用;

  • chunks:构建过程生成的 chunks 列表,数组内容包含 chunk 名称、大小、包含了哪些模块等;

  • assets:编译后最终输出的产物列表、文件路径、文件大小等;

  • entrypoints:entry 列表,包括动态引入所生产的 entry 项也会包含在这里面;

  • children:子 Compiler 对象的性能数据,例如 extract-css-chunk-plugin 插件内部就会调用 compilation.createChildCompiler 函数创建出子 Compiler 来做 CSS 抽取的工作。 我们可以从这些数据中分析出模块之间的依赖关系、体积占比、编译构建耗时等,Webpack 社区还提供了许多优秀的分析工具,能够将这些数据转换各种风格的可视化图表,帮助我们更高效地找出性能卡点,包括:

  • Webpack Analysis :Webpack 官方提供的,功能比较全面的 stats 可视化工具;

  • Statoscope:主要侧重于模块与模块、模块与 chunk、chunk 与 chunk 等,实体之间的关系分析;

  • Webpack Visualizer:一个简单的模块体积分析工具,真的很简单!

  • Webpack Bundle Analyzer:应该是使用率最高的性能分析工具之一,主要实现以 Tree Map 方式展示各个模块的体积占比;

  • Webpack Dashboard:能够在编译过程实时展示编译进度、模块分布、产物信息等;

  • Unused Webpack Plugin:能够根据 stats 数据反向查找项目中未被使用的文件。

Webpack Analysis

Webpack Analysis 是 webpack 官方提供的可视化分析工具,相比于其它工具,它提供的视图更全,功能更强大,能够通过创建依赖关系图对你的包进行更彻底的检查。

使用上只需要将上一节 webpack --json=stats.json 命令生成的 stats.json 文件导入页面,就可以看到一些关键统计信息

Statoscope

Statoscope 也是一个非常强大的可视化分析工具,主要提供如下功能:

  • 完整的依赖关系视图,涵盖 modules/chunks/assets/entrypoints/packages 维度;
  • entrypoints/chunks/packages/module 体积分析;
  • 重复包检测;
  • 多份 stats 数据对比;
  • 等等。

有两种用法,一是将 stats 数据导入到 Statoscope 在线页面;二是使用 @statoscope/webpack-plugin 插件,用法:

  1. 安装依赖:
sql 复制代码
yarn add -D @statoscope/webpack-plugin
  1. 注册插件:
ini 复制代码
const StatoscopeWebpackPlugin = require('@statoscope/webpack-plugin').default;

module.exports = {
  ...
  plugins: [new StatoscopeWebpackPlugin()],
};

之后,运行 npx webpack 命令,编译结束后默认打开分析视图,

Webpack Bundle Analyzer

Webpack-bundle-analyzer 是一个非常有名的性能分析插件,只需要一些简单配置就可以在 Webpack 构建结束后生成 Tree Map 形态的模块分布统计图,用户可以通过对比 Tree Map 内容推断各模块的体积占比,是否包含重复模块、不必要的模块等,用法:

  1. 安装模块依赖:
csharp 复制代码
yarn add -D webpack-bundle-analyzer
  1. 添加插件:
ini 复制代码
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
  .BundleAnalyzerPlugin;

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

Webpack Visualizer

Webpack Visualizer 是一个在线分析工具,可用于检测、可视化 Webpack 产物的构成模块。有两种用法,一是将 stats.json 文件上传到在线 页面;二是使用 webpack-visualizer-plugin 生成统计页面,用法:

  1. 安装依赖:
csharp 复制代码
yarn add ---D webpack-visualizer-plugin
  1. 添加插件:
java 复制代码
// webpack.config.js
const VisualizerPlugin = require('webpack-visualizer-plugin');

module.exports = {
  // ...
  plugins: [
    new Visualizer({
      filename: './stats.html'
    })
  ],
}
//...

Webpack Dashboard

webpack-dashboard 是一个命令行可视化工具,能够在编译过程中实时展示编译进度、模块分布、产物信息等,用法:

  1. 安装依赖:
csharp 复制代码
yarn add -D webpack-dashboard
  1. 注册插件:
ini 复制代码
const DashboardPlugin = require("webpack-dashboard/plugin");

module.exports = {
  // ...
  plugins: [new DashboardPlugin()],
};
  1. 注意了,需要用 webpack-dashboard 命令启动编译:
bash 复制代码
# 打包
npx webpack-dashboard -- webpack
# Dev Server
npx webpack-dashboard -- webpack-dev-server
# 运行 Node 程序
npx webpack-dashboard -- node index.js

Speed Measure Plugin

SpeedMeasureWebpackPlugin 插件能够统计出各个 Loader、插件的处理耗时,开发者可以根据这些数据分析出哪些类型的文件处理更耗时间,用法:

  1. 安装依赖:
csharp 复制代码
yarn add -D speed-measure-webpack-plugin
  1. 修改配置:
ini 复制代码
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");

const smp = new SpeedMeasurePlugin();

const config = {
  entry: "./src/index.ts",
  // ...
};

// 注意,这里是用 `smp.wrap` 函数包裹住 Webpack 配置
module.exports = smp.wrap(config);

之后运行打包命令如 npx webpack 即可。

UnusedWebpackPlugin

最后分享 UnusedWebpackPlugin 插件,它能够根据 webpack 统计信息,反向查找出工程项目里哪些文件没有被用到,我日常在各种项目重构工作中都会用到,非常实用。用法也比较简单:

csharp 复制代码
const UnusedWebpackPlugin = require("unused-webpack-plugin");

module.exports = {
  // ...
  plugins: [
    new UnusedWebpackPlugin({
      directories: [path.join(__dirname, "src")],
      root: path.join(__dirname, "../"),
    }),
  ],
};

示例中,directories 用于指定需要分析的文件目录;root 用于指定根路径,与输出有关。配置插件后,webpack 每次运行完毕都会输出 directories 目录中,有哪些文件没有被用到。

相关推荐
咖啡の猫1 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲3 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5814 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路4 小时前
GeoTools 读取影像元数据
前端
ssshooter4 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
Jerry5 小时前
Jetpack Compose 中的状态
前端
dae bal6 小时前
关于RSA和AES加密
前端·vue.js
柳杉6 小时前
使用three.js搭建3d隧道监测-2
前端·javascript·数据可视化
lynn8570_blog6 小时前
低端设备加载webp ANR
前端·算法
LKAI.6 小时前
传统方式部署(RuoYi-Cloud)微服务
java·linux·前端·后端·微服务·node.js·ruoyi