
在使用 next.js 13.3 及更高版本进行开发时,开发者常会利用 next/font/local 模块来优化本地字体的加载和性能。然而,一个常见的困境是,即使本地开发环境(如 macos 或 windows)一切运行正常,项目部署到 vercel 后却可能遭遇 module not found: can't resolve './fonts/brfirma-thin.woff2' 这样的构建错误。这通常表明字体文件路径解析在部署环境中出现了问题。
问题根源分析
此问题的核心在于不同操作系统文件系统的行为差异。本地开发环境,尤其是 macOS 和 Windows,默认情况下文件系统通常不区分大小写(case-insensitive)。这意味着 myfont.woff2 和 MyFont.woff2 可能被视为同一个文件。然而,Vercel 的部署环境基于 Linux,其文件系统是严格区分大小写(case-sensitive)的。
当字体文件或其所在目录的名称包含大写字母或空格时,即使本地路径引用看起来正确,在 Vercel 上,构建工具可能无法准确匹配到文件,从而抛出“模块未找到”的错误。例如,./fonts/Woff/Font Something.woff 这样的路径,在区分大小写的环境中,Woff 和 Font Something 都可能导致解析失败。
解决方案与最佳实践
为了确保本地字体在 Next.js 应用中能够稳定地在 Vercel 上部署,最关键的解决方案是遵循严格的文件和目录命名规范。
1. 统一命名规范
这是解决问题的根本方法。请确保所有字体文件及其所在目录的名称:
- 全部使用小写字母。
- 避免使用空格。 如果需要分隔单词,请使用连字符 (-)。
错误示例:
- ./fonts/Woff/Font Something.woff
- ./Fonts/BrFirma-Regular.woff2
- ./assets/Fonts/My Font.ttf
正确示例:
- ./fonts/woff/font-something.woff
- ./fonts/brfirma-regular.woff2
- ./assets/fonts/my-font.ttf
2. 字体文件存放位置
尽管命名规范是首要因素,但将字体文件放置在项目中的合理位置也很重要。通常,可以将字体文件放在项目源代码目录(如 src)下的一个专门的字体子目录中。
- 放置在源代码目录: 更推荐的做法是将字体文件放置在与 font.js 或 _app.js 相关的源代码目录中,例如 src/styles/fonts/。这样,next/font/local 可以更好地处理这些资源,将其作为模块进行打包和优化。
- 放置在 public 目录: 理论上也可以将字体文件放在 public 目录下(例如 public/assets/fonts/),并通过 next/font/local 引用。然而,next/font/local 的设计意图是优化字体加载,它会处理字体文件,而不是将其作为纯粹的静态资源直接从 public 提供。如果选择 public 目录,路径引用方式也需严格遵守命名规范。但为了避免不必要的复杂性,通常建议将 next/font/local 引入的字体放在 src 目录下。
3. next/font/local 配置示例
结合上述命名规范和文件放置策略,以下是一个优化的 font.js 配置示例。假设字体文件位于 src/styles/fonts/ 目录下。
// src/styles/font.js
import localFont from 'next/font/local';
export const BRFirma = localFont({
src: [
{
path: './fonts/brfirma-regular.woff2', // 注意:全部小写,无空格
weight: '400',
style: 'normal',
},
{
path: './fonts/brfirma-semibold.woff2', // 注意:全部小写,无空格
weight: '600',
style: 'normal',
},
],
display: 'swap', // 推荐使用 'swap' 提升用户体验
});在 _app.js 或其他布局组件中引用:
// src/_app.js
import { BRFirma } from 'styles/font'; // 假设通过 jsconfig.json 配置了路径别名
// 或者如果 font.js 在同一目录: import { BRFirma } from './styles/font';
function MyApp({ Component, pageProps }) {
return (
);
}
export default MyApp;4. 路径别名配置(jsconfig.json/tsconfig.json)
虽然 jsconfig.json 或 tsconfig.json 中的 baseUrl 和 paths 配置通常不会直接导致字体解析失败,但正确的配置有助于保持代码整洁和模块导入的一致性。
// jsconfig.json
{
"compilerOptions": {
"baseUrl": "src", // 设置基础路径为 src 目录
"paths": {
"@/*": ["./*"] // 允许使用 @/ 别名引用 src 目录下的文件
}
},
"exclude": ["node_modules", "build", "dist", "jest"]
}通过 baseUrl: "src",可以直接从 src 目录开始引用模块,例如 import { BRFirma } from 'styles/font';。
注意事项
- 清除缓存: 在 Vercel 上部署新版本后,如果问题依然存在,尝试清除 Vercel 的部署缓存并重新部署。有时旧的构建产物或缓存可能导致意外行为。
- Next.js 版本: 确保使用的 Next.js 版本支持 next/font API,并根据官方文档进行配置。尽管本文主要关注命名问题,但版本兼容性始终是值得关注的。
- 本地测试: 在本地开发时,即使文件系统不区分大小写,也建议使用推荐的命名规范,以便及早发现潜在的部署问题。
- 其他静态资源: 这种命名规范的原则不仅适用于字体文件,也适用于所有可能在不同文件系统间部署的静态资源(如图片、视频等)。
总结
Next.js 在 Vercel 部署时本地字体解析失败的问题,其根本原因在于本地开发环境与部署环境文件系统对大小写和特殊字符处理方式的差异。通过严格遵循文件和目录的命名规范——即全部使用小写字母并用连字符替代空格——可以有效避免此类“模块未找到”错误。结合合理的字体文件存放位置和清晰的 next/font/local 配置,能够确保 Next.js 应用在 Vercel 上稳定、高效地加载和使用本地字体。










