案例研究:我将 React 打包体积降低了 68%

发布: (2025年12月13日 GMT+8 16:31)
4 min read
原文: Dev.to

Source: Dev.to

引言

我在一个 B2B 应用上工作时,遇到了一个常见的误解:企业会对糟糕的 Google Core Web Vitals 和臃肿的 bundle 大小更宽容,因为“用户在办公室的电脑上使用高速网络”。实际上,主要用户是通过移动电话和移动网络访问该应用的。当我发现这一点后,优化变得至关重要。

起始点: 生产环境的 bundle 大小为 1,542 KB(gzip 压缩后)。
目标: 500 KB(遵循行业最佳实践)

第一步:压缩 – 已经优化

显而易见的第一步是启用 Brotli 压缩,相比 gzip 通常可以节省 15–25 %。然而基础设施已经开启了 Brotli,所以这里无法再获得收益。

第二步:基于路由的代码拆分

React Router 本身就支持懒加载。我为所有路由实现了动态导入:

// Before
import Dashboard from './Dashboard';

// After
const Dashboard = React.lazy(() => import('./Dashboard'));

结果: Bundle 大小降低了 37 %,至 971 KB

第三步:依赖分析与 Vendor 拆分

使用 Webpack Bundle Analyzer,我发现了占据 bundle 大部分体积的第三方库:

  • 日期选择/日历库
  • 功能标记管理
  • 分析 SDK
  • PDF 编辑器
  • 富文本编辑器
  • 文件上传组件

这些库在多个模块中被直接导入。我创建了包装模块并使用动态导入:

// Before – Direct imports everywhere
import { DatePicker } from 'heavy-date-library';

// After – Wrapper with lazy loading
export const loadDatePicker = () =>
  import('heavy-date-library').then(module => module.DatePicker);

结果: Bundle 缩小至原始大小的 57 %879 KB)。

第四步:模块解耦与依赖链

Bundle Analyzer 显示出紧耦合的依赖链。例如:

// ❌ Tightly coupled
// Module A imported Module B, which imported Module C,
// which imported a heavy utility library
// All loaded together even if only one piece was needed

// ✅ Solution: Extract shared code to independent modules
// Created small, focused modules with only necessary shared code
// Broke circular dependencies

我识别并拆分了这些链路,创建了仅包含必要共享代码的小而专注的模块。

结果: Bundle 实现 63 % 的减小(571 KB)。

第五步:本地化优化

应用支持多种语言,但所有翻译文件都会同步加载,且不考虑用户的语言偏好。

之前: 所有语言文件一起打包(约 120 KB 的 JSON)。
之后: 仅在初始加载时加载用户选中的语言:

// Dynamic locale loading
const loadLocale = (locale) =>
  import(`./locales/${locale}.json`);

最终结果: 493 KB —— 68 % 的减小,成功突破我们的 500 KB 目标!

关键要点

  • 假设很危险: 没有数据不要随意假设用户环境。
  • 先分析再优化: Webpack Bundle Analyzer 是不可或缺的工具。
  • 第三方库代价高: 对重量级依赖要有策略地使用。
  • 依赖链很重要: 紧耦合会导致 bundle 膨胀。
  • 本地化可能很重: 动态加载语言文件。
Back to Blog

相关文章

阅读更多 »

不要让你的 bundles 超重

说实话:我们都在乎 bundle size。多年来,bundlesize 是首选工具,但它现在已经过时且不再维护。安全检查开始标记…