优化 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 &&
)
}
打开网络选项卡。当条件满足时,你会看到一个新的网络请求被用来获取动态组件(点击按钮打开一个模式)。
使用 next/image 延迟加载图像
Next.js 有一个名为的内置组件 下一张/图片 .它仅在图像位于视口中时加载图像。
从“下一个/图像”导入图像;
常量索引 = () => {
返回 (
<>
外部域必须在next.config.js中使用
domains属性。
<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);
返回 (
<>
父母身份:{status}
{状态 === '空闲' &&
</>
);
};
如果您想创建这样的自定义广告组件,请按照 本文 .
您还可以延迟加载其他脚本,例如 Google Analytics 脚本。
具体进口
如果您正在使用类似的库 罗达什 和 日期-fn ,我们可以通过只导入特定函数而不是完全导入来轻松减小包大小,就像这样。
//老的
从'lodash'导入_get
//新的
从 'lodash/get' 导入 _get
我们可以优化多个其他库的使用。更多细节, 看看这篇文章 .不要忘记从项目中删除未使用的导入。
优化下一个/链接
如果您正在使用 下一个/链接 在您的项目中,将 prefetch 属性添加到其中并将其设置为 false。 Next.js 默认预取链接在视口中的页面。假设您有一个带有两个链接的标题, '/家' 和 '/关于' .即使用户在主页上,也将加载关于页面的资产,因为在视口中可以看到关于链接。
当预取设置为 错误的 , 预取仍然会发生,但只有在链接悬停时才会发生。
关于我们
>
博客文章
优化字体
当我们使用图标库时 字体真棒 ,我们最多只使用 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;

浙公网安备 33010602011771号