React 代码分割实战:用 React.lazy 与 Vite manualChunks 把首屏包拆薄
test12026-09-304 次阅读
为什么需要代码分割
单页应用打包后往往是一个巨大的 JS 文件,用户首屏就要下载全部代码,即使很多路由暂时用不到。代码分割(code splitting)把不同路由、不同第三方库拆成独立的 chunk,浏览器按需加载,首屏体积和解析时间都能明显下降。
用 React.lazy 与 Suspense 懒加载路由
React 内置了 React.lazy,配合 Suspense 可以把路由组件改成按需加载。组件被访问时才会去请求对应的 chunk。
import { lazy, Suspense } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
// 只有访问到对应路由时才会加载这个 chunk
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Settings = lazy(() => import("./pages/Settings"));
export default function App() {
return (
<BrowserRouter>
<Suspense fallback={<div>加载中…</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
</BrowserRouter>
);
}
用 Vite manualChunks 拆分第三方库
路由级懒加载之外,把体积大的第三方库单独拆包,能让它们被浏览器长期缓存,也避免业务代码一改就让用户重新下载整个 vendor。
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
output: {
manualChunks: {
"react-vendor": ["react", "react-dom", "react-router-dom"],
"chart-vendor": ["echarts"],
},
},
},
},
});
给最可能的下一步预加载
懒加载会带来短暂白屏。对最可能进入的路由,可以在用户 hover 或空闲时提前 import,把 chunk 悄悄拉到本地。
function preload(routeImport: () => Promise<unknown>) {
routeImport();
}
// <Link to="/dashboard" onMouseEnter={() => preload(() => import("./pages/Dashboard"))}>仪表盘</Link>
几个常见坑
- Suspense 的 fallback 必须能正常渲染,且在 SSR 场景下要改用服务端支持的流式方案。
- 被 lazy 的模块必须默认导出(export default),否则动态 import 拿不到组件。
- manualChunks 不要切得太碎,chunk 数量过多会变成大量小请求,反而拖慢加载。
- 懒加载组件内部如果还有数据请求,注意 loading 态要覆盖「代码加载」和「数据加载」两个阶段。
T
test1
文章作者
为什么需要代码分割 单页应用打包后往往是一个巨大的 JS 文件,用户首屏就要下载全部代码,即使很多路由暂时用不到。代码...
- 分类
- 技术
- 发布时间
- 2026-09-30
- 字数
- 约 1811 字
- 阅读
- 4 次
