Next.js Favicon:现代 App Router 指南

你刚启动了一个全新的 Next.js 项目,把一个 favicon.ico 文件扔进了 public 文件夹,然后……什么也没发生。或者更糟,它在本地能用,但在生产环境就坏了。这是怎么回事?

如果这听起来很耳熟,你可能正巧碰上了旧的 pages router 和现代 App Router 之间的差异。好消息是,一旦你了解了它的约定,新的方式其实更简单、更强大。

官方方式:基于文件的元数据

忘了手动在你的 layout.tsx 文件里添加 <link> 标签吧。Next.js App Router 使用一种特殊的基于文件的系统。你只需将特定命名的图标文件放在你的 app 目录下,Next.js 就会自动为你生成必要的 HTML head 标签。

这是我推荐的方法。它更整洁,不易出错,并且利用了框架的内置优化。

分步指南:添加你的 Favicon

我们用不到五分钟的时间搞定它。除了一个正在运行 App Router 的 Next.js 项目外,不需要任何先决条件。

第一步:准备你的图标文件

为了实现广泛的兼容性,你需要几个关键文件。虽然你可以自己创建这些文件,但使用生成器能确保它们的尺寸和格式都正确无误。(不害臊地插播一句:我们的免费 favicon 生成器能完美处理这一切)。

第二步:将图标放在 `app` 目录的根路径下

这是最重要的一步。将你生成的图标直接移动到 /app 文件夹中。不要把它们放在 /public 文件夹里。

你的项目结构应该看起来像这样:

app/
├── layout.tsx
├── page.tsx
├── favicon.ico       <-- 用于旧版浏览器
├── icon.svg          <-- 用于现代浏览器 (推荐)
└── apple-icon.png    <-- 用于 iOS 主屏幕
public/
└── ... (你的其他静态资源)

Next.js 会自动检测这些文件,并在你网站的 <head> 中生成相应的 <link> 标签。

第三步:移除任何旧的或手动的声明

如果你的 public 文件夹里有一个旧的 favicon.ico,请删除它。虽然 /app 目录下的文件会优先使用,但最好还是避免混淆。

另外,检查你的根 layout.tsx 文件,移除任何手动添加的 <link rel="icon" ...> 标签。基于文件的方法使它们变得多余。

第四步:验证结果

运行你的开发服务器 (npm run dev),并检查页面的源代码。你应该能看到 Next.js 已经为你生成了这些标签,大概是这样:

<head>
  ...
  <link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="any">
  <link rel="icon" href="/icon.svg" type="image/svg+xml" sizes="any">
  <link rel="apple-touch-icon" href="/apple-icon.png" type="image/png" sizes="any">
  ...
</head>

看到这些标签就意味着它成功了。框架已经处理好了一切。

真实案例:GitHub 是怎么做的

好奇大公司是怎么处理这个问题的吗?看看 GitHub。他们提供了一个 favicon.ico,为不同设备提供了多种尺寸的 PNG,还有一个用于 Safari 固定标签页的特殊单色 SVG。Next.js 基于文件的方法就是为了能自动构建这种强大的、支持多设备的方案,让你不必手动编写所有这些 <link> 标签。

需要避免的常见陷阱

如果你的图标没有显示出来,通常是以下三个原因之一。

1. `public` 文件夹的陷阱

再次强调,对于像 favicon 这样的元数据文件,在现代 Next.js 中,app 目录才是正确的位置。虽然 public 文件夹仍然可以用于存放通用静态资源,但放在 /app 目录下的图标有特殊含义并拥有更高优先级。

2. 顽固的浏览器缓存

你的代码完美无缺,但你看到的仍然是旧图标(或者没有图标)。这几乎总是浏览器的锅。浏览器会非常积极地缓存 favicon。

简单的页面刷新通常是不够的。你需要进行硬刷新或清除浏览器缓存。如果你卡住了,我们写了一篇关于如何强制清除 favicon 缓存的详细指南。

3. 不正确的文件名

favicon.ico、icon.png、icon.svg 和 apple-icon.png 这些名字不是随便起的。它们是 Next.js 特意寻找的约定。像 my-icon.svg 这样的拼写错误是不会被自动识别的。

就是这样。通过遵循基于文件的约定,你是顺应框架而行,而不是与之对抗。你可以免费获得优化且正确的 HTML,并且你的项目能保持整洁。再也不用为了在浏览器标签页上显示一个小小的品牌标志而和 <head> 标签搏斗了。