Search code examples
cachingfontsnext.jswebfontsvercel

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


I use custom fonts on a website. It works, but it looks like they aren't cached long enough, as I way too often get FOUT. Some times multiple times a day, on production. I'm hoping I can cache fonts for a longer period (or another solution) to prevent this from occurring as often.

Fonts are preloaded in _document.tsx like this:

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

Then in _app.tsx like this:

<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>

How can I improve this? Or set a longer cache time for the fonts? šŸ™šŸ»


Solution

  • Without seeing the full example, Iā€™d:

    • confirm first that your React app is server rendered. With Next.js, Iā€™d imagine it is, but the link tag and script (which should be a style tag?) should be part of the initial HTML
    • check if changing the inline CSS into a <link /> tag and separate CSS style that, which only contains the @font-face declarations. Yes, this adds one additional HTTP request, but then that CSS would presumably follow Vercelā€™s static caching rules and not change for 31 days: https://vercel.com/docs/edge-network/caching#static-files (although itā€™s unclear here whether the cache is invalidated when you redeploy that file, or when you do any deploy)
    • decide to use something custom to override Vercelā€™s default cache settings, and add a Routes property in your vercel.json file.

    For example, to cache everything in the fonts/ directory for one week (and assuming the new, external CSS file is there as well), the config would be:

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

    This is based on the config example in the docs: https://vercel.com/docs/configuration#routes/headers

    Hope one or more of those together is helpful!