重构项目,用得上的 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 目录中,有哪些文件没有被用到。

相关推荐
Lysun00120 分钟前
vue2的$el.querySelector在vue3中怎么写
前端·javascript·vue.js
jerry-8939 分钟前
Centos类型服务器等保测评整/etc/pam.d/system-auth
java·前端·github
小爬菜1 小时前
Django学习笔记(启动项目)-03
前端·笔记·python·学习·django
想要打 Acm 的小周同学呀1 小时前
前端Vue2项目使用md编辑器
前端·编辑器·vue2·markdown 语法
计算机-秋大田1 小时前
基于SSM的家庭记账本小程序设计与实现(LW+源码+讲解)
java·前端·后端·微信小程序·小程序·课程设计
海的预约2 小时前
VUE之路由Props、replace、编程式路由导航、重定向
前端·vue.js·智能路由器
西柚与蓝莓2 小时前
报错:{‘csrf_token‘: [‘The CSRF token is missing.‘]}
前端·flask
德迅云安全-小钱4 小时前
跨站脚本攻击(XSS)原理及防护方案
前端·网络·xss
ss2734 小时前
【2025小年源码免费送】
前端·后端
Amy_cx4 小时前
npm install安装缓慢或卡住不动
前端·npm·node.js