优化 Next.js App Bundle 并提升其性能
优化 Next.js App Bundle 并提升其性能
在本文中,我们将学习如何优化 Next.js 应用程序( 链接到应用程序 ) 通过将捆绑包大小减少 43% 并将分数从 Google 的 36 提高到 73 PageSpeed 见解 .
让我们从分析 Next.js 的生产构建开始。当我们执行 npm 运行构建 , Next.js 为我们提供了生产构建的统计信息。它指定将传递给浏览器的页面和块的大小。
Next.js 创建通用文件,并将在页面之间共享。这些文件称为 First Load JS。 First Load JS 文件包含框架代码和多个页面使用的代码。
如果组件重用了超过 50% 的文件,则 Next.js 会将该组件包含在 First Load JS 中。我们无法改变这种行为,但我们可以优化我们的代码。
以下是输出 npm 运行构建 命令和 Google PageSpeed Insights 得分。如您所见,文件的大小为红色和黄色。我们的目标是让它们变成绿色。
我们走吧。
分析首次加载 JS
我们首先分析和识别 First Load JS 中包含的包。为了找到它,我们需要安装以下开发依赖项。
npm install -save-dev @next/bundle-analyzer 跨环境
安装好后在里面添加如下代码 包.json 在下面 脚本 .
“脚本”:{
"analyze": "cross-env ANALYZE=true next build",
"analyze:server": "cross-env BUNDLE_ANALYZE=server next build",
"analyze:browser": "cross-env BUNDLE_ANALYZE=browser next build"
},
在 next.config.js 中添加以下代码。如果您没有此文件,请在项目的根目录中创建它。
const withBundleAnalyzer = require('@next/bundle-analyzer')({
启用:process.env.ANALYZE === 'true'
})
module.exports = withBundleAnalyzer({
环境:{
NEXT_PUBLIC_ENV: 'PRODUCTION', //你的下一个配置在这里
},
})
接下来,执行这个命令 npm 运行分析 ,这将在您的浏览器中打开两个带有图表的新选项卡。专注于 客户端.html 图形。
然后,用较小的等效库替换较大的库,并删除不相关的库。要替换任何库,请转到 https://bundlephobia.com/ ,查看您的图书馆的大小,并检查您是否有任何尺寸较小的替代品。否则,请尝试编写自己的自定义代码。在这个演示中:
-
我们删除了 js-cookie 库,用于读取和写入 cookie,并将其替换为自定义代码。
-
我们更换了 成帧运动 带有 react-transition-group 的库,因为它小了 10 倍。
-
而不是使用 反应-gpt ,用于显示 Google 广告,我们创建了自己的自定义广告组件(更多详细信息如下)。
-
我们移动了 片刻 文件从客户端到服务器端,大小为 片刻 很大。通过这样做,我们既可以从 API 发送格式化的日期,也可以在服务器端格式化日期,如下所示。
导出异步函数 getServerSideProps(context) {
const moment = (await import('moment')).default(); //默认方法是访问默认导出
返回 {
日期:moment.format('dddd D MMMM YYYY'),
}
}
现在这个日期将作为道具发送给组件,可以使用 (getServerSideProps 只能用于页面而不是组件内部) .现在, 片刻 不会发送到浏览器。
动态导入
在页面初始加载时不可见的组件和基于某些条件显示的组件应动态导入,而不是正常导入。这确保了这些组件仅在需要时才发送到浏览器。请参考以下代码示例。
从“下一个/动态”导入动态
const Modal = dynamic(() => import('../components/header'));
导出默认函数 Home() {
返回 (
{showModal &&<Modal /> }
)
}
打开网络选项卡。当条件满足时,你会看到一个新的网络请求被用来获取动态组件(点击按钮打开一个模式)。
使用 next/image 延迟加载图像
Next.js 有一个名为的内置组件 下一张/图片 .它仅在图像位于视口中时加载图像。
从“下一个/图像”导入图像;
常量索引 = () => {
返回 (
<>
<p>
外部域必须在<Code>next.config.js</code>中使用
<Code>domains</code>属性。
</p>
<Image
alt="Next.js 徽标"
src="https://assets.vercel.com/image/upload/v1538361091/repositories/next-js/next-js-bg.png"
宽度={1200}
高度={400}
/>
</>
);
};
延迟加载 Google Ads
Google Ads 脚本通常会阻塞主线程,因此我们将在页面加载八秒后加载脚本。最初,我们使用 反应-gpt 包以加载 Google Ads 脚本。我们将用我们优化的自定义代码替换它。
为此,我们创建了一个自定义挂钩来注入任何脚本。注入 Google Ads 脚本时,它会根据注入的状态返回状态。一旦返回 准备好 ,我们运行广告代码。
从“反应”导入反应;
const useScript = (src, delay = null) => {
const [status, setStatus] = React.useState(src ? "loading" : "idle");
React.useEffect(() => {
如果(!src){
设置状态(“空闲”);
返回“空闲”;
}
让 script = document.querySelector(`script[src="${src}"]`);
让超时=空;
如果(!脚本){
如果(延迟){
超时 = setTimeout(() => {
注入脚本();
// 添加脚本后添加事件监听器
script.addEventListener("加载", setStateStatus);
script.addEventListener("错误", setStateStatus);
}, 延迟);
} 别的 {
注入脚本();
}
} 别的 {
setStatus(script.getAttribute("数据状态"));
}
常量 setStateStatus = (事件) => {
setStatus(event.type === "load" ? "ready" : "error");
};
//注入脚本的代码
函数注入脚本(){
script = document.createElement("script");
脚本.src = src;
script.async = true;
script.setAttribute("数据状态", "加载中");
document.body.appendChild(脚本);
常量 setDataStatus = (事件) => {
脚本.setAttribute(
“数据状态”,
event.type === "加载" ? “准备好”:“错误”
);
};
script.addEventListener("加载", setDataStatus);
script.addEventListener("错误", setDataStatus);
}
如果(脚本){
//脚本将在延迟时未定义可用,因此在添加侦听器之前检查它
script.addEventListener("加载", setStateStatus);
script.addEventListener("错误", setStateStatus);
}
返回 () => {
如果(脚本){
script.removeEventListener("加载", setStateStatus);
script.removeEventListener("错误", setStateStatus);
}
如果(超时){
清除超时(超时);
}
};
}, [src]);
返回状态;
};
导出默认使用脚本;
使用这个钩子 页面/index.js .
常量 MyApp = () => {
常量状态 = 使用脚本(脚本,8000);
返回 (
<>
<p>父母身份:{status}</p>
{状态 === '空闲' &&<Ads /> }
</>
);
};
如果您想创建这样的自定义广告组件,请按照 本文 .
您还可以延迟加载其他脚本,例如 Google Analytics 脚本。
具体进口
如果您正在使用类似的库 罗达什 和 日期-fn ,我们可以通过只导入特定函数而不是完全导入来轻松减小包大小,就像这样。
//老的
从'lodash'导入_get
//新的
从 'lodash/get' 导入 _get
我们可以优化多个其他库的使用。更多细节, 看看这篇文章 .不要忘记从项目中删除未使用的导入。
优化下一个/链接
如果您正在使用 下一个/链接 在您的项目中,将 prefetch 属性添加到其中并将其设置为 false。 Next.js 默认预取链接在视口中的页面。假设您有一个带有两个链接的标题, '/家' 和 '/关于' .即使用户在主页上,也将加载关于页面的资产,因为在视口中可以看到关于链接。
当预取设置为 错误的 , 预取仍然会发生,但只有在链接悬停时才会发生。
<li>
<Link href="/about" prefetch={false}>
<a>关于我们</a>
</Link>
</li>
<li>
<Link href="/blog/hello-world" prefetch={false}>>
<a>博客文章</a>
</Link>
</li>
优化字体
当我们使用图标库时 字体真棒 ,我们最多只使用 15 个图标,但会加载完整的库。问题是它是渲染阻塞资源。因此,您无需加载完整的库,只需将所需的图标下载为 SVG 文件并使用它们。您还可以延迟加载这些 SVG 图像。
你也可以使用 字体显示:交换; 为您的字体,因为它不会阻止渲染。相反,字体被赋予了一个无限的交换周期和一个最小的块周期。
@字体脸{
字体系列:ExampleFont;
src: url(/path/to/fonts/examplefont.woff) 格式('woff'),
url(/path/to/fonts/examplefont.eot) 格式('eot');
字体粗细:400;
字体样式:正常;
字体显示:交换;
}
如果您直接通过链接使用 Google 字体,请下载字体并自行托管它们。
延迟加载 React 组件(可选)
我们也可以仅在组件位于视口中时使用 反应延迟加载 库,它也支持 SSR。我们也可以提供偏移量,因此用户不会意识到这种延迟加载行为。
从'react-lazyload'导入LazyLoad;
<LazyLoad offset={100}>
<Footer />
</LazyLoad>
从捆绑包中排除大型库
正如我之前所讨论的,库被添加到 First Load JS 中。在我们的项目中,我们使用 同步融合图 库在多个页面上,所以 同步融合图 库被捆绑到第一次加载中。
未使用的页面 同步融合图 也在加载 同步融合图 库,因为它已添加到 First Load JS 或主包中。为了优化它,我们关注了 Robert S 的这篇很棒的文章 如何排除大图书馆 .
最终结果
*我们目前正在优化最后一个红页
奖金
如果您想说服您的经理或客户从网站上删除某些部分或稍后加载它们,请访问 https://www.performancebudget.io/ .
输入您希望 Web 应用程序加载所需的秒数。然后,选择 3G 网络(因为 Google PageSpeed Insights 使用 3G 速度进行测试)。按 计算 .
您将获得您的大小预算(应发送到浏览器的资源的总大小),这将允许您的 Web 应用程序在指定的秒数内加载。
只需从这一步开始您的项目。
结论
如果您想要良好的性能和更好的 Google PageSpeed Insights 分数,请向浏览器发送更少的资源。
在添加任何包裹之前,请检查尺寸 https://bundlephobia.com/ .您不能同时保留多个复杂的功能并拥有出色的性能。
我希望您现在对如何优化 Next.js 应用程序以提高其在 Google PageSpeed Insights 上的得分有了一个很好的了解。使用这些技术来优化您的旧网站,使其更快。
感谢您的阅读!
同步融合 基本 JS 2 是您构建应用程序所需的唯一套件。它在一个包中包含超过 65 个高性能、轻量级、模块化和响应式 UI 组件。下载一个 免费试用 评估今天的控制。
如果您有任何问题或意见,您可以通过我们的 支持论坛 , 支持门户 , 或者 反馈门户 .我们随时乐意为您提供帮助!
相关博客
最初发表于 https://www.syncfusion.com 2022 年 9 月 9 日。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明