惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
人人都是产品经理
人人都是产品经理
The GitHub Blog
The GitHub Blog
月光博客
月光博客
T
Tailwind CSS Blog
小众软件
小众软件
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Proofpoint News Feed
B
Blog RSS Feed
博客园 - 司徒正美
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
博客园 - Franky
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
T
The Blog of Author Tim Ferriss
GbyAI
GbyAI
Apple Machine Learning Research
Apple Machine Learning Research

V2EX

我用 AI 写代码,但终端管理反而成了累赘——于是我做了 codux [调研] 各位在公司都用什么 ide 和 agent 写代码? 老运维 share 一个运维平台 新电脑 brew install node 之后,一个小设置可以提升对供应链投毒的防御 GLM-Coding 调用持续报错: z.ai 的 Lite 套餐几乎无法使用,官方 Pro/Max 是否稳定? 上海漕河泾内推,本组有 2 个 hc,一个后端,一个前端,预算都是 20k 左右,不打卡,氛围好 如果 V2EX 上有一组不永久保存聊天记录(比如只保存 7 天或者 24 小时)的聊天室,那么会开启哪些有用或者有趣的可能? gemini cli 貌似挂了,一直返回 403 第一次在自媒体上赚到钱 收集了最近在使用的低价 GPT, Gemini,邮箱等 AI 会员的小店合集 讨论个大实话:现在企业还在说 AI 编程提效 20%, 30%的,真的太落后,没用懂 AI。因为包括很多前沿公司,已经狂奔到提效 200%-500%的情况 [招聘][远程][币安] 前端/后端/QA/iOS/Android 至少 3 年以上经验 目前有大量 HC 欢迎投递 Chatgpt Pro 用量用不完的可以开这些设置 面试的时候好像遇到钓鱼了,给各位避个坑 cursor 年续费 22 号到期, 自动续费是否还是老的计次套餐呢 被两件破事毁掉的一下午,琐碎的内耗消磨人的精力 使用 Planet 存储 Codex 的会话或者重要信息 如果业务部门领导不要你开发功能,而是要求你教会它用 claude code 开发功能,你会怎么做? 分享一个 MacOS 接绿联 CM818 USB 转 DP 转接器使用感受 我的 HR 朋友 10 年老 Java ,非全大专,大家帮忙看看简历 开源了一个 AI 口语练习工具,音素级发音评分,完全免费可自部署 V2EX 上有哪些你觉得很有趣、印象深刻的妹纸? 字节为啥不出个国内版 Vercel? 有在大马的朋友吗? 问个运营商问题 你们在有领导的公司大群发过的最大胆的消息是什么 公司裁员,目前没有工作。想试试摆摊,做一个移动鲜啤打酒车 我的硬盘 Memblaze Pblaze 5 Linux 下不识别,给 Linux 内核提交了补丁, AI 说有望被合并 只有我一个人觉得 codex 不好用? 做了个 AI + 真人专家监督的广告投放平台 Auxora, 7 个品牌跑出 6x ROAS
Next.js 多语言路由性能优化:从 5.8s LCP 到极致体验
hazellin549 · 2026-02-20 · via V2EX

为什么你的英文版比中文版慢 3 倍?


01 一个诡异的性能问题

上周,我在检查网站的性能报告时,发现了一个诡异的现象:

语言版本 LCP CLS
中文 (默认) 2.3s ✅ 0.06 ✅
英语 /en/ 5.8s ❌ 0.68 ❌

同一套代码,同一个页面,为什么英文版比默认语言慢了整整 2.5 倍?

这篇文章记录我的排查过程和最终解决方案。


02 先搞清楚 LCP 是什么

LCP (Largest Contentful Paint) 是 Core Web Vitals 的核心指标之一。

简单说,它测量的是:页面主要内容出现的时间

Google 的标准是:

  • < 2.5s — 良好
  • ⚠️ 2.5s - 4s — 需要改进
  • > 4s — 较差

我的英文版 5.8s ,妥妥的「红牌警告」。


03 第一个嫌疑人:缓存策略

在 Next.js 的多语言路由中,默认语言和非默认语言的处理逻辑是不同的。

默认语言: example.com/product
非默认语言: example.com/en/product

我检查了 CDN 缓存命中率:

路由 缓存命中率
/product 89% ✅
/en/product 31% ❌

问题出现了:非默认语言的缓存命中率低得可怜。

原因分析

Next.js 默认生成的 Cache-Control 头对于动态路由是这样的:

Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate

而我的多语言路由 /[locale]/... 被识别为「动态路由」,导致 CDN 几乎不缓存。

解决方案

next.config.js 中显式配置缓存策略:

async headers() {
  return [
    {
      source: '/:locale(en|es|fr)/:path*',
      headers: [
        {
          key: 'Cache-Control',
          value: 'public, s-maxage=3600, stale-while-revalidate=86400',
        },
      ],
    },
  ];
}

效果:缓存命中率从 31% 提升到 **85%**。


04 第二个嫌疑人:关键资源预加载

优化缓存后,LCP 从 5.8s 降到了 3.9s ,但还是不达标。

Lighthouse 报告给了一个提示:

⚠️ Preload key requests
Fonts and critical CSS are not being preloaded

我检查了页面的资源加载顺序:

1. HTML 文档
2. 等待解析...
3. 发现 CSS 引用
4. 下载 CSS
5. 发现字体引用
6. 下载字体
7. 渲染文字 ← LCP 发生在这里

问题是:字体要等到 CSS 加载完才开始下载,形成了瀑布流。

解决方案

<head> 中添加预加载标签:

<Head>
  {/* 预加载关键字体 */}
  <link
    rel="preload"
    href="/fonts/inter-variable.woff2"
    as="font"
    type="font/woff2"
    crossOrigin="anonymous"
  />
  
  {/* 预加载关键 CSS */}
  <link
    rel="preload"
    href="/_next/static/css/app.css"
    as="style"
  />
</Head>

效果:LCP 从 3.9s 降到 2.7s


05 第三个嫌疑人:图片加载

还差 0.2s 才能达到 2.5s 的「良好」标准。

Lighthouse 又给了提示:

⚠️ Largest Contentful Paint element
<img src="/hero-banner.png" ...>

原来 LCP 元素是首屏的大图。

问题

图片使用了 Next.js 的 <Image> 组件,默认是懒加载的:

<Image src="/hero-banner.png" ... />
// 默认 loading="lazy"

但对于首屏图片,懒加载反而拖慢了显示速度。

解决方案

对 LCP 元素禁用懒加载,并添加 priority 属性:

<Image
  src="/hero-banner.png"
  priority  // 关键!
  loading="eager"
  ...
/>

效果:LCP 从 2.7s 降到 2.2s


06 CLS 问题:页面为什么在「抖动」?

解决完 LCP ,再看 CLS 。

CLS (Cumulative Layout Shift) 测量的是:页面元素的意外位移

我的英文版 CLS 是 0.68 ,而标准是 < 0.1 。

打开页面慢动作回放,发现了两个问题:

问题 1:字体加载导致的「闪烁」(FOUT)

页面先用系统字体渲染,字体加载完后「闪」一下变成自定义字体。

由于两种字体的 metrics 不同,文字位置发生偏移。

解决方案:使用 font-display: optional

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-variable.woff2') format('woff2');
  font-display: optional; /* 如果字体没及时加载,就不换了 */
}

问题 2:图片没有指定尺寸

// ❌ 错误写法
<img src="/card.png" />

// ✅ 正确写法
<img src="/card.png" width={300} height={400} />

Next.js 的 <Image> 组件会自动处理这个问题,但我有几个地方用了原生 <img>

效果:CLS 从 0.68 降到 0.04


07 优化前后对比

指标 优化前 优化后 改善
LCP 5.8s ❌ 2.2s ✅ -62%
CLS 0.68 ❌ 0.04 ✅ -94%
缓存命中率 31% 85% +174%
Lighthouse 52 91 +75%

08 核心经验总结

多语言路由的性能优化,核心要点:

🎯 缓存策略

非默认语言路由容易被当作「动态页面」而跳过缓存。显式配置 Cache-Control

🎯 预加载关键资源

字体和关键 CSS 形成瀑布流是 LCP 的常见杀手。<link rel="preload"> 打破瀑布。

🎯 LCP 元素优先加载

首屏图片不要懒加载。priority 属性告诉 Next.js 这是关键资源。

🎯 防止布局偏移

  • 图片必须指定尺寸
  • 字体使用 font-display: optionalswap + 预加载
  • 避免动态插入内容到首屏

09 一个容易忽略的细节

最后分享一个容易忽略的点:

不同语言版本的字体 metrics 可能不同。

比如中文字体通常比英文字体更高,如果你用同一套 CSS ,line-height 可能导致不同语言的布局高度不一致。

我的做法是为每种语言定义 bodyfont-family 后备栈:

/* 英语/西班牙语 */
body[lang="en"], body[lang="es"] {
  font-family: 'Inter', system-ui, sans-serif;
}

/* 中文 */
body[lang="zh"] {
  font-family: 'Inter', 'PingFang SC', 'Microsoft YaHei', sans-serif;
}

10 写在最后

性能优化是一个「挤牙膏」的过程:

  • 第一轮优化(缓存):5.8s → 3.9s
  • 第二轮优化(预加载):3.9s → 2.7s
  • 第三轮优化(图片):2.7s → 2.2s

每一轮看起来改动不大,但累积下来效果惊人。

如果你的多语言网站也有性能问题,不妨按这个顺序排查:

  1. 缓存是否生效?
  2. 关键资源是否预加载?
  3. LCP 元素是否优先加载?
  4. 有没有布局偏移?

希望这篇文章对你有帮助!