如何利用代码拆分和智能加载策略提升 Next.js 应用的运行速度。
您将学到什么?
此博文介绍了不同类型的代码 拆分以及如何使用 来提升 Next.js 应用的运行速度。
基于路由和基于组件的代码拆分
默认情况下,Next.js 会针对每条路线将 JavaScript 拆分成多个单独的块。 当用户加载您的应用时,Next.js 只会发送 。当用户在应用中导航时,他们会提取数据块 与其他路由相关联基于路由的代码拆分可最大限度地减少 同时需要进行解析和编译的脚本数量, 缩短网页加载时间。
虽然基于路由的代码拆分是很好的默认设置,但您还可以进一步优化 在组件级别进行代码拆分。如果您的集群 组件,最好将它们拆分成多个独立的部分。 这样,任何不重要的或仅在特定环境下呈现的大型组件 可以对用户互动(如点击按钮)进行延迟加载。
Next.js 支持动态 import()
,
它允许您导入 JavaScript 模块(包括 React 组件)
并且将每次导入作为单独的分块进行加载这样您就可以
组件级代码拆分,让您能够控制资源加载,
确保用户只下载他们需要的代码
他们正在观看的内容在 Next.js 中,这些组件在服务器端呈现
(SSR)
默认情况。
动态导入的实际应用
这篇博文包含示例应用的多个版本,其中包含一个简单的 只需一个按钮。点击该按钮后,您会看到一只可爱的小狗。如 浏览应用的各个版本时,会发现动态导入 不同于静态 导入 以及如何与它们合作
在应用的第一个版本中,小狗住在 components/Puppy.js
中。接收者
在页面上显示 Puppy
组件,
将 index.js
替换为静态 import 语句:
import Puppy from "../components/Puppy";
如需了解 Next.js 如何捆绑应用,请在开发者工具中检查网络跟踪记录:
如需预览网站,请按查看应用。然后按 全屏
。
按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
点击网络标签页。
选中停用缓存复选框。
重新加载页面。
加载页面时,所有必需的代码(包括 Puppy.js
)
组件捆绑在 index.js
中:
![开发者工具的“Network”标签页,显示了以下 6 个 JavaScript 文件:index.js、app.js、webpack.js、main.js、0.js 和 dll(动态链接库)文件。](https://web.developers.google.cn/static/articles/code-splitting-with-dynamic-imports-in-nextjs/image/devtools-network-tab-show-c3449cc648185.png?authuser=6&hl=sv)
当您按 Click me 按钮时,只有请求小狗 JPEG 添加到网络标签页中:
![点击按钮后开发者工具的“Network”标签页,显示了相同的 6 个 JavaScript 文件和 1 个图片。](https://web.developers.google.cn/static/articles/code-splitting-with-dynamic-imports-in-nextjs/image/devtools-network-tab-the-94b209c5e4e56.png?authuser=6&hl=sv)
这种方法的缺点是,即使用户不点击该按钮
看到小狗,他们必须加载 Puppy
组件,因为它包含在
index.js
。这个小例子没什么大不了,但在现实世界中
通常,只有当应用加载大组件时,
。
现在,请查看应用的第二个版本,其中静态导入是
已替换为动态导入Next.js 包含 next/dynamic
,因此
为 Next 中的任何组件使用动态导入:
import Puppy from "../components/Puppy";
import dynamic from "next/dynamic";
// ...
const Puppy = dynamic(import("../components/Puppy"));
按照第一个示例中的步骤检查网络跟踪记录。
首次加载应用时,系统只会下载 index.js
。这次是
由于
不包含 Puppy
组件的代码:
![显示相同的 6 个 JavaScript 文件的开发者工具网络,但 index.js 现在缩小了 0.5 KB。](https://web.developers.google.cn/static/articles/code-splitting-with-dynamic-imports-in-nextjs/image/devtools-network-showing-8cbd4309d29c5.png?authuser=6&hl=sv)
Puppy
组件现在位于单独的块 1.js
中,该块仅加载
按钮:
![点击按钮后的 DevTools 的 Network 标签页,显示额外的 1.js 文件和添加到文件列表底部的图片。](https://web.developers.google.cn/static/articles/code-splitting-with-dynamic-imports-in-nextjs/image/devtools-network-tab-the-e42cc1846b47f.png?authuser=6&hl=sv)
在实际应用中,组件通常会 更大,以及延迟加载 可以将初始 JavaScript 载荷减少数百 KB
带有自定义加载指示器的动态导入
延迟加载资源时,最好提供加载指示器
以免发生延迟情况在 Next.js 中,您可以通过提供一个
dynamic()
函数的一个附加参数:
const Puppy = dynamic(() => import("../components/Puppy"), {
loading: () => <p>Loading...</p>
});
要查看加载指示器的实际效果,请在以下应用中模拟慢速网络连接: 开发者工具:
如需预览网站,请按查看应用。然后按 全屏
。
按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
点击网络标签页。
选中停用缓存复选框。
在 Throttling 下拉列表中,选择 Fast 3G。
按点击此处按钮。
现在,当您点击该按钮时,需要一段时间才能加载组件和应用 会显示“正在加载...”消息。
![显示文本的深色屏幕](https://web.developers.google.cn/static/articles/code-splitting-with-dynamic-imports-in-nextjs/image/a-dark-screen-the-text-914039a8f2589.png?authuser=6&hl=sv)
不使用 SSR 的动态导入
如果您只需要在客户端呈现组件(例如,聊天窗口),
微件),可以通过将 ssr
选项设置为 false
来实现此目的:
const Puppy = dynamic(() => import("../components/Puppy"), {
ssr: false,
});
总结
Next.js 支持动态导入,可为您提供组件级代码 从而最大程度地减少 JavaScript 负载 加载时间。默认情况下,所有组件均在服务器端呈现,您可以 必要时停用此选项。