JavaScript 分块并不只是把一个大文件机械地切成几个小文件。真正影响页面加载速度的,是哪些代码进入首屏、哪些代码延迟下载,以及多个页面能否复用已经缓存的模块。Turbopack 正围绕这些目标改进 Next.js 的构建结果,并在 Next.js 16.3 中加入了新的实验性分块能力。
由于实验特性的具体配置接口可能随版本变化,下面不假设某个未公开的配置项,而是从可观察的构建产物和应用边界入手,说明如何评估并改善分块效果。
分块解决的是依赖图问题
假设 /dashboard 和 /reports 都依赖同一个图表库。构建器大致有三种选择:
- 把图表库分别打进两个页面的 chunk,首次访问独立,但重复下载和缓存占用增加。
- 提取共享 chunk,两个页面都能复用,但访问任一页面时可能增加一次请求。
- 如果图表只在用户展开面板后出现,则创建异步 chunk,让首屏完全不加载它。
因此,chunk 数量越少并不必然越好。一个超大的共享 chunk 可能迫使轻量页面下载从未执行的代码;过度细分又会带来更多请求、模块解析和调度成本。合理的结果通常需要同时考察:
- 路由首次加载需要多少 JavaScript。
- 页面切换时有多少代码可以从缓存复用。
- 低频功能是否进入了初始 chunk。
- 修改一个页面后,是否导致大量无关 chunk 的内容哈希变化。
Turbopack 的分块价值正在于利用完整依赖图寻找这些边界,而 Next.js 16.3 的新实验能力则意味着这套策略仍在继续演进。实验阶段应通过真实构建和性能数据验证收益,而不是只比较 chunk 文件数量。
用代码边界表达加载时机
构建器可以分析依赖,但无法自动知道某个昂贵组件是否必须出现在首屏。开发者仍然需要用动态导入表达业务上的加载边界。
下面是一个可以直接改造的 App Router 示例。先创建项目;如果 16.3.0 不是你的包源中实际提供的版本,请替换成可用的 Next.js 16.3 版本:
npx create-next-app@latest turbopack-chunks --ts --app --eslint
cd turbopack-chunks
npm install next@16.3.0
mkdir -p app/reports
创建 app/reports/heavy-report.tsx:
'use client';
export default function HeavyReport() {
const rows = Array.from({ length: 2000 }, (_, index) => index + 1);
return (
<table>
<tbody>
{rows.map((row) => (
<tr key={row}>
<td>Report row {row}</td>
</tr>
))}
</tbody>
</table>
);
}
再创建 app/reports/page.tsx:
'use client';
import dynamic from 'next/dynamic';
import { useState } from 'react';
const HeavyReport = dynamic(() => import('./heavy-report'), {
loading: () => <p>Loading report...</p>,
ssr: false,
});
export default function ReportsPage() {
const [visible, setVisible] = useState(false);
return (
<main>
<h1>Reports</h1>
<button onClick={() => setVisible(true)}>Open report</button>
{visible ? <HeavyReport /> : null}
</main>
);
}
运行开发服务器时可显式使用 Turbopack:
npm run dev -- --turbopack
这个例子把报表组件放到动态导入边界之后。访问 /reports 时,浏览器不需要立刻执行该模块;点击按钮后才会请求对应代码。实际项目中,更适合延迟加载的通常是图表、富文本编辑器、地图、代码编辑器和只在弹窗中出现的管理工具。
检查生产构建,而不是猜文件名
开发模式优先考虑增量编译与快速刷新,其 chunk 形态不一定代表生产结果。评估页面加载成本时,应执行生产构建:
npm run build
find .next/static/chunks -type f -name '*.js' -exec du -h {} + | sort -h
不要依赖某个固定 chunk 文件名,因为内容哈希和分块策略都可能改变。更可靠的检查方式是:
- 在浏览器无痕窗口中打开目标路由。
- 在开发者工具的 Network 面板中筛选
JS。 - 记录首次访问时的传输体积、请求数和执行时间。
- 导航到共享依赖较多的第二个页面,观察哪些请求命中缓存。
- 触发动态功能,确认延迟 chunk 只在交互后加载。
如果要比较 Next.js 16.3 的实验能力,建议保留一份基准构建,并使用同一批路由、同一设备和相同缓存条件重复测试。单看 .next 目录总大小容易误判,因为用户通常只会下载与当前导航路径相关的部分产物。
升级时关注边界与回归
采用新的实验性分块能力前,可以按下面的清单执行:
- 先选择 JavaScript 较重且具有跨页面共享依赖的路由进行试点。
- 同时测试首次直达和客户端导航,两者会触发不同的加载路径。
- 检查错误监控与 source map,避免新的 chunk 边界降低线上问题的可诊断性。
- 验证部署平台和 CDN 对带哈希静态资源设置了长期缓存。
- 关注实验配置在后续 Next.js 版本中的变更,不把它当作稳定接口。
分块优化的目标不是生成最漂亮的文件列表,而是让当前页面少下载、后续页面多复用、低频功能晚加载。把动态导入边界放在真实交互节点,再用生产环境指标验证 Turbopack 的构建结果,通常比手工追求某个 chunk 大小更可靠。