先说明一下:这篇文章针对仍然运行在Next.js 14 App Router上的既有博客项目,不代表Next.js 14是当前最新版本。
维护旧版本项目时,我不会一看到性能问题就立刻升级大版本。升级和优化是两个任务。先测量瓶颈、做低风险优化,再单独评估升级,原因会更容易判断。
先测量,不凭感觉
我会先确认:
- 首页和文章页的LCP、CLS、INP
- 首次加载的JavaScript大小
- 最大图片和字体请求
- 服务端响应时间
- 缓存命中情况
- 移动网络下的实际表现
Lighthouse适合发现问题,但还要结合Chrome DevTools的Network、Performance以及真实用户数据。一次本地高分不能代表所有用户。
尽量保留Server Component
App Router下组件默认可以在服务端执行。只有需要浏览器状态、事件和浏览器API时才添加'use client'。
// Server Component
export default async function ArticlePage({ params }: Props) {
const article = await getArticle(params.slug)
return <Article article={article} />
}如果在页面最上层加入'use client',下面大量组件可能进入客户端边界,JavaScript体积也会增加。
更好的方式是把真正交互的部分缩小:
<ArticleBody article={article} />
<LikeButton articleId={article.id} />正文保持Server Component,点赞按钮单独成为Client Component。
图片通常是第一优化对象
博客的首图很容易成为LCP元素。使用next/image时要设置正确尺寸和sizes。
<Image
src={article.coverUrl}
alt={article.coverAlt}
width={1200}
height={675}
sizes="(max-width: 768px) 100vw, 800px"
priority
/>priority只给首屏真正重要的图片,不能每张都加。图片尺寸要接近实际显示尺寸,不能让手机也下载超大原图。
还要确认:
- WordPress等远程图片域名配置
alt是否准确- 封面尺寸比例是否统一
- 正文图片是否懒加载
- 是否存在布局抖动
字体与CLS
使用next/font可以减少外部字体请求并改善加载方式,但字体种类和字重仍然要控制。
const notoSansJP = Noto_Sans_JP({
subsets: ['latin'],
weight: ['400', '700'],
display: 'swap'
})如果中文、日文、英文混合,字体文件可能很大。不要为了一个标题导入过多字重。还要准备合理的fallback字体,减少切换时的版面变化。
数据获取与缓存策略
博客首页、分类页、文章页的更新频率不同,不应该全部使用相同缓存。
思路可以是:
- 基本不变的介绍页:长缓存
- 文章详情:发布后缓存,更新时再验证
- 首页最新文章:较短再验证时间
- 登录状态或预览:不使用公开缓存
缓存不是越久越好。最重要的是编辑者更新文章后,页面什么时候变化,以及失败时如何发现。
如果数据来自WordPress,可以在发布时通过Webhook触发Next.js的再验证。Webhook必须验证密钥,并记录失败日志。
减少不必要的客户端依赖
博客常见的体积来源包括:
- 整套UI库只使用一个组件
- 大型日期库只用于格式化日期
- 所有页面加载代码高亮
- 所有文章加载轮播或图表库
使用Bundle分析工具确认实际内容,不要只根据package.json猜测。
只在需要时动态加载重组件:
const Chart = dynamic(() => import('./Chart'), {
loading: () => <p>Loading...</p>
})但普通文本组件没有必要全部dynamic。拆分本身也有网络和维护成本。
Markdown与代码高亮
技术博客经常在构建时处理Markdown和代码高亮。如果把高亮库整个送到客户端,文章页会变重。
可以优先考虑:
- 构建时或服务端高亮
- 只加载实际使用的语言
- 普通文章不加载代码功能
- 对生成后的HTML进行安全处理
TypeScript如何帮助优化
TypeScript不会直接让页面更快,但能让数据边界更清楚。
type ArticleCard = {
slug: string
title: string
excerpt: string
coverUrl: string
}首页卡片不需要正文,就不要把完整文章对象传给客户端组件。明确的小型View Model能减少误用,也让接口更容易优化。
SEO和性能一起检查
速度优化不能破坏SEO。文章页还要确认:
- 服务端输出标题和正文
- metadata、canonical和Open Graph
- sitemap更新时间
- 文章删除后的404或301
- 分类与分页链接
- JSON-LD内容正确
如果为了减少HTML而把正文改成客户端请求,搜索引擎和分享预览可能受到影响。
第三方脚本
GA、广告、聊天、热图等脚本可能比自己的代码更重。每个脚本都要回答:
- 是否真的需要
- 哪些页面需要
- 能否延后加载
- 用户同意前是否应该加载
- 加载失败会不会影响主功能
不要只优化几十KB的业务代码,却忽略多个第三方脚本。
升级与优化分开
Next.js 14项目已经属于旧版本维护场景。完成性能基线后,应另外评估:
- Node.js版本与部署环境
- Next.js 14使用的具体小版本
- 已知安全问题
- React与第三方库兼容性
- App Router行为变化
- 测试与回滚方案
升级可能带来性能与安全收益,但最好单独开分支、阅读目标版本迁移文档并完整回归,而不是混在图片优化中一起上线。
检查清单
- 找到了真实LCP元素
'use client'边界足够小- 首图尺寸、
sizes、优先级正确 - 字体种类与字重受控
- 页面缓存符合更新频率
- 发布后的再验证流程可观察
- Bundle中没有明显无用依赖
- 代码高亮没有全部放到客户端
- 第三方脚本按需加载
- SEO、404、sitemap没有被破坏
- 升级任务与性能优化分开
总结
博客优化通常不需要先做复杂技巧。最大的收益往往来自缩小Client Component范围、正确处理首图和字体、制定清晰缓存策略,以及删除不必要的第三方脚本。
对Next.js 14旧项目,我会先建立性能基线,完成低风险优化,再单独安排版本升级。这样出了问题更容易回滚,也更容易知道哪项修改真正有效。

