使用 webpack 设置性能预算

Milica Mihajlija
Milica Mihajlija

Webpack 会合并所有导入的文件,并将其打包到一个或多个输出文件(称为 bundle)中。打包很方便,但随着应用规模的扩大, 您的软件包也会随之变大。您需要监控软件包大小,以确保它们不会变得过大,从而影响应用的加载时间。Webpack 支持根据资源大小设置性能预算,并且可以为您监控 bundle 大小。

为了展示其工作原理,我们来看一个计算距离新年还有多少天的应用。 它使用 React 和 moment.js 构建。 (就像现实世界中的应用越来越依赖框架和库一样。😉)

一款计算距离元旦还有多少天的应用

测量

此 Codelab 已包含与 webpack 捆绑的应用。

  1. 点击 Remix to Edit(混剪以编辑)使项目可编辑。
  2. 点击终端(注意:如果未显示“终端”按钮,您可能需要使用“全屏”选项)。
  3. 如需获取采用颜色编码的资源及其大小列表,请在控制台中输入 webpack。
webpack

主 bundle 以黄色突出显示,因为它大于 244 KiB (250 KB)。

Webpack 输出显示软件包大小为 323 KiB
Webpack 警告您 JS 软件包过大 ⚠️

这些警告在生产模式下默认处于启用状态,并且对于资源和入口点(页面初始加载期间使用的所有资源的组合),默认阈值均为 244 KiB(未压缩)。

Webpack 警告:素材资源超出了建议的大小上限
Webpack 警告您 JS 软件包过大 ⚠️

Webpack 不仅会向您发出警告,还会就如何缩减 bundle 大小向您提供建议。如需详细了解推荐的技术,请参阅网站开发基础。

Webpack 性能优化建议
Webpack 性能优化建议 💁

设置自定义性能预算

适当的性能预算取决于项目的性质。 最好自行研究。 一个经验法则是,提供小于 170 KB 的压缩/缩减大小的关键路径资源。

对于这个简单的演示,请尝试更加保守,并将预算设置为 100 KB (97.7 KiB)。在 webpack.config.js 中添加以下代码:

module.exports = {
  //...
  performance: {
    maxAssetSize: 100000,
    maxEntrypointSize: 100000,
    hints: "warning"
  }
};

新的性能预算以字节为单位设置:

  • 单个素材资源 100000 字节 (maxAssetSize)
  • 入口点为 100000 字节 (maxEntrypointSize)

在这种情况下,只有一个 bundle,它同时也是入口点。

hints 的可能值包括:

  1. warning(默认):显示黄色警告消息,但 build 会通过。最好在开发环境中使用此方法。
  2. error:显示红色出错提示,但 build 仍会通过。建议将此设置用于正式版 build。
  3. false:不显示任何警告或错误。
Webpack 性能错误(红色字体)
Webpack 性能提示“错误”🚨

优化

性能预算旨在在性能问题变得难以解决之前向您发出警告。构建应用的方法不止一种,有些技术可以缩短加载时间。(其中许多内容都记录在优化 JavaScript 中。🤓)

框架和库让开发者的工作变得更轻松,但最终用户并不真正关心应用是如何构建的,他们只关心应用是否功能齐全、运行快速。如果您发现自己超出了性能预算,则需要考虑可能的优化。

在现实世界中,大型客户端框架通常很难替换,因此明智地使用它们非常重要。通过一些研究,您通常可以找到热门库的较小替代方案,这些替代方案同样可以很好地完成工作(date-fns 是 moment.js 的一个很好的替代方案)。 有时,如果框架或库对性能有重大影响,则完全不使用框架或库会更合理。

移除未使用的代码是优化包含大型第三方库的应用的好方法。移除未使用的代码指南详细介绍了此过程,下面提供了一种在不使用 moment.js 的情况下重写倒计时代码的快速方法。

在 app/components/Countdown.jsx 中,移除以下代码:

const today = moment();
const yearEnd = moment().endOf('year');
const daysLeft = yearEnd.diff(today, 'days');

并删除以下行:

const moment = require('moment');

这需要一些数学计算,但您可以使用原生 JavaScript 实现相同的倒计时:

const today = new Date();
const year = today.getFullYear();
const yearEnd = new Date(year,11,31); //months are zero indexed in JS
const timeDiff = Math.abs(yearEnd.getTime() - today.getTime());
const daysLeft = Math.ceil(timeDiff / (1000 * 3600 * 24));

现在,从 package.json 中移除 moment.js,然后在控制台中再次运行 webpack 以构建经过优化的 bundle。

搞定!您已缩减 223 KiB (230KB),应用大小已在预算范围内。🎉

优化后的 Webpack 软件包大小输出为 97.7 KiB

监控

在 webpack 中设置性能预算只需几行代码,如果您(不小心)添加了大型依赖项,它会向您发出警告。俗话说“眼不见,心不烦”,但 webpack 可以确保您始终了解性能影响。