Webpack 打包体积太大,React 项目首屏加载慢怎么办?

UP主~桂霞 阅读 24

我最近在优化一个 React 项目的构建性能,发现 Webpack 打包后的 main.js 超过 2MB,首屏加载特别慢。我已经用了 SplitChunks 把 vendor 单独拆出来了,但效果不明显。是不是哪里配置错了?

比如下面这个组件,只是简单引入了 lodash 和一个图表库,但打包后体积就暴涨:

import React from 'react';
import _ from 'lodash';
import { LineChart } from 'recharts';

const Dashboard = () => {
  const data = _.range(10).map(i => ({ name: <code>Day ${i}</code>, value: i * 10 }));
  return <LineChart width={500} height={300} data={data} />;
};

export default Dashboard;

有没有办法按需加载这些第三方库?或者我的 splitChunks 配置需要调整?

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
A. 治霞
A. 治霞 Lv1
你的问题很典型,lodash 和 recharts 这两个坑我之前也踩过。让我帮你分析一下。

先说问题根源:你这样直接 import _ from 'lodash',不管用不用,lodash 整个库都会被装进去。recharts 也是一样,虽然你只用了 LineChart,但没做特殊处理的话,整个包都在。

第一步:解决 lodash 按需加载

有两种方式,第一种是换用 lodash-es:

npm uninstall lodash
npm install lodash-es


然后改成这样导入:

import range from 'lodash-es/range';
import map from 'lodash-es/map';

// 使用时直接用函数
const data = map(range(10), i => ({ name: Day ${i}, value: i * 10 }));


第二种是用 babel-plugin-lodash,在 babel 配置里加这个插件,它会自动帮你做按需导入,不需要改代码:

// babel.config.js 或者 .babelrc
{
plugins: [
'lodash'
]
}


装一下依赖:

npm install --save-dev babel-plugin-lodash


第二步:解决 recharts 按需加载

recharts 虽然宣传支持 tree-shaking,但实际效果经常不理想。更稳妥的做法是直接导入具体组件,绕过整个包的打包:

// 不要这样 import { LineChart } from 'recharts'
// 改成直接导入具体的组件文件
import LineChart from 'recharts/lib/chart/LineChart';
import Line from 'recharts/lib/series/Line';
import { XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import './recharts.css'; // recharts 的样式也要单独引


这样只有你用到的组件会被打包,体积能小很多。

第三步:优化 splitChunks 配置

你说已经用了 splitChunks 但效果不明显,我猜配置可能比较简单。给你一个更细致的配置思路:

// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // 改成 all,不仅是 async
cacheGroups: {
// 单独把 react/react-dom 拆出来
react: {
test: /[\/]node_modules[\/](react|react-dom)[\/]/,
name: 'react-vendor',
priority: 20,
reuseExistingChunk: true,
},
// 单独把大的第三方库拆出来
vendors: {
test: /[\/]node_modules[\/]/,
name: 'vendors',
priority: 10,
minChunks: 1,
},
// 公共模块
common: {
minChunks: 2,
priority: 5,
reuseExistingChunk: true,
},
},
},
},
};


关键点是把 react/react-dom 这种几乎不变化的库单独拆出来,它们的缓存命中率会很高。

第四步:检查你的 webpack 模式

确保你用的是 production 模式,不是 development:

// webpack.config.js
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',


production 模式默认会做 tree-shaking 和压缩,体积能差好几倍。

第五步:路由级别的代码分割

如果你的应用有多个页面,路由可以用 React.lazy 做懒加载:

import { Suspense, lazy } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));

function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}


这样每个路由会打成单独的 chunk,首屏只加载需要的代码。

最后检查手段

用 webpack-bundle-analyzer 看看最终打包都是什么在占体积:

npm install --save-dev webpack-bundle-analyzer


在 webpack 配置里加:

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

plugins: [
new BundleAnalyzerPlugin(),
],


跑一遍构建,它会生成一个可视化的报告,告诉你哪个包最大,一目了然。

按照这套流程搞下来,你的 main.js 应该能从 2MB 降到几百KB甚至更低。有问题再问我。
点赞
2026-03-20 12:01