1. 简介:我对 Web 性能的警醒
当我开始从事自由职业时,我的主要关注点是快速推出功能 — 页面看起来很漂亮,动画流畅,客户满意。但有一天,一位客户回来说:
“设计很棒,但我的用户抱怨它很慢 — 尤其是在移动设备上。”
我快速进行了一次 Lighthouse 审核,然后轰隆隆——绩效得分:43。这对我来说是一个警钟。
从那时起,我优化了多个 Next.js 应用,从作品集网站到仪表板和招聘板。在这篇博客中,我将分享10 个实用的性能技巧,这些技巧帮助我加快了实际项目的进度并显著改善了用户体验。
没错,它们对初学者来说很友好。
2. 提示 1:使用标签next/image代替常规标签<img>
错误:
在一个作品集项目中,我使用标准<img>标签和大型 PNG 文件。在桌面上,它看起来还不错。但在移动网络上,它需要很长时间才能加载。
解决方法:
我切换到 Next.js 的内置next/image组件。它会自动:
压缩并优化图像
支持延迟加载
根据设备提供合适的图片尺寸
例子:
import Image from 'next/image';
<Image
src="/profile.jpg"
width={300}
height={300}
alt="My Profile Pic"
/>
影响:
页面加载时间提高了 40%,并且 Lighthouse“最大内容绘制”(LCP) 分数从红色跃升至绿色。
初学者提示:
始终用于next/image静态图像。它可以为您处理大量的性能工作。
3. 提示2:分析包裹大小(并削减多余的部分)
发生了什么:
在一个仪表板项目中,我直接导入了chart.js、moment和其他大型库。一切正常——直到我检查了生产版本。
问题:我的 JavaScript 包非常大。首次加载在 3G 上
耗时超过6 秒。
解决方案:
我运行这个命令来可视化我的捆绑包:
npm install @next/bundle-analyzer
在next.config.js:
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({});
然后跑:
ANALYZE=true npm run build
我看到的情况:
大量碎块moment和未使用的组件。
我做的修复:
替换
moment为date-fns(较小的替代方案)使用以下方法拆分重型部件
dynamic import删除了未使用的 UI 库
结果:
包大小从1.2MB 减小到 600KB。首次加载时间缩短了一半。
4. 提示 3:仅在真正需要时才使用 SSR
我做错了什么:
在使用 Next.js 构建自由职业者工作公告板时,我认为对每个页面使用 SSR(服务器端渲染)是最好的主意。
为什么?因为它听起来很“专业”,而且我想要实时数据。
问题:
每个页面请求都会到达服务器并实时获取数据。结果如何?
服务器负载高
较慢的 TTFB (第一个字节的时间)
用户体验不佳
我的经验是:
SSR 功能强大,但并非总是需要。
我的解决方法:
使用静态站点生成 (SSG)来生成不经常更改的页面(例如主页、关于等)
仅针对具有筛选/搜索功能的职位列表保留SSR
在某些部分,添加了增量静态再生 (ISR)以每隔几分钟更新一次静态页面
初学者提示:
当内容在每次请求时发生变化时,请使用 SSR(例如仪表板或经过身份验证的数据)。
否则,请坚持使用 SSG — 它更快且更便宜。
5. 技巧#4:使用 SWR (Stale-While-Revalidate) 缓存 API 结果
问题:
在个人网站上,每次页面加载时我都会通过 API 获取我的 GitHub 项目。
看起来很动态,对吧?但它减慢了主页的速度。
我的解决方法:
我使用了SWR,这是 Vercel 的一个 React hook,它可以缓存数据并在后台保持数据新鲜。
代码示例:
import useSWR from 'swr';
const fetcher = (url) => fetch(url).then((res) => res.json());
export default function GitHubRepos() {
const { data, error } = useSWR('/api/github', fetcher);
if (error) return <div>Error loading</div>;
if (!data) return <div>Loading...</div>;
return <div>{data.length} repositories found</div>;
}

