如何使用 Vercel/Next.js 改进字体 loading/caching?

How to improve font loading/caching with Vercel/Next.js?

我在网站上使用自定义字体。它有效,但看起来它们缓存的时间不够长,因为我经常得到 FOUT。有时一天多次,在生产中。我希望我可以将字体缓存更长的时间(或其他解决方案)以防止这种情况经常发生。

字体在 _document.tsx 中预加载如下:

<link
   rel='preload'
  as='font'
  href='/fonts/Calibre-Regular.woff2'
  type='font/woff2'
  crossOrigin='anonymous'
  />

然后在 _app.tsx 中这样:

<script jsx>{`
 @font-face {
  font-family: 'Calibre';
  font-display: swap;
  src: url('/fonts/Calibre-Regular.woff2') format('woff2'),
    url('/fonts/Calibre-Regular.woff') format('woff');
}
`}</script>

我该如何改进?或者为字体设置更长的缓存时间?

在没有看到完整示例的情况下,我会:

  • 首先确认您的 React 应用程序是服务器呈现的。对于 Next.js,我想是的,但是 link 标签和 script(应该是 style 标签?)应该是初始 [=41] 的一部分=]
  • 检查是否将内联 CSS 更改为 <link /> 标记并分隔 CSS 样式,它只包含 @font-face 声明。是的,这增加了一个额外的 HTTP 请求,但是 CSS 可能会遵循 Vercel 的静态缓存规则并且在 31 天内不会更改:https://vercel.com/docs/edge-network/caching#static-files(尽管这里不清楚缓存是否在您重新部署时失效文件,或者当你进行任何部署时)
  • 决定使用一些自定义的东西来覆盖 Vercel 的默认缓存设置,并添加一个 Routes property in your vercel.json file

例如,要将 fonts/ 目录中的所有内容缓存一周(并假设新的外部 CSS 文件也存在),配置为:

{
  "routes": [
    {
      "src": "/fonts/(.*)",
      "headers": { "cache-control": "s-maxage=604800" },
      "dest": "/fonts/"
    }
  ]
}

这基于文档中的配置示例:https://vercel.com/docs/configuration#routes/headers

希望其中的一个或多个对您有所帮助!

我不太确定 FOUT 是由字体缓存时间不够长引起的。例如,它们可以尚未加载吗? preload link 应该会导致浏览器请求字体并正常缓存它 - WOFF(2) 文件无论如何都是静态文件。除非特别努力缓存它们,否则应该缓存它们并且保持缓存。

所以,我会首先检查那些 WOFF 文件的请求和响应headers,它们都来自客户端和服务器。发送 Vercel 层的到底是什么?而且,更重要的是,从服务器发送到缓存的是什么?(我自己放错了很多 cache-related pragma,所以我现在总是先检查那些)。

如果可以,我不会打赌,我会查看实际加载时间并在 FOUT 期间从站点请求瀑布流。这可能指向加载序列中的缓存问题或错误(很少见,但我也有一些)。

如果此时没有任何结果,您可以尝试以其他方式摆脱 FOUT - 加载动画、加载延迟或只是 hiding the text

但我的钱在旅程的 server-Vercel 段,70% 在服务器发送 borked headers,30% 在 Vercel 反应不正常。

确定它是缓存还是其他东西的肮脏和可怕的方法是让另一台机器以适当的时间间隔从同一网络连续生产缓存(例如 cron 作业,或者更残酷的是,while 使用 curlsleep 从商品 Raspberry 上的终端循环),频率高于 FOUT 出现的频率。如果这使得 FOUT 消失,那么它可能真的是缓存时间——但坦率地说,我真的很惊讶。