Ruddra.com

Rollout your Google fonts faster with Cloudflare Cache

Rollout your Google fonts faster with Cloudflare Cache

If you are already using Cloudflare, you know that Cloudflare caches fonts (and other contents). But it won’t work if you are using Google font’s CDN. Cloudflare has a detailed guide on how to improve Google fonts performance, but it heavily relies on workers, which might cost a lot of money if your website has a lot of users.

So, in this article, we will see two ways to use Cloudflare Cache to serve fonts faster and without any extra costs.

Use Cloudflare Cache (CDN)

Cloudflare provides a caching mechanism through their CDN. But you can’t upload contents directly to that CDN, rather the CDN will cache certain files (like images, pdfs, fonts etc.) automatically if they are available in your server. For storing Google Fonts in your local server, you can follow these steps:

  1. Generate the CDN links from Google Fonts. Click on any of the font from Google Font page, click on which styles and google will generate the link. For example, for Roboto font regular 400 and bold 700, the link looks like this:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
  1. Then go to the link https://fonts.googleapis.com/css2?family=Roboto:wght@400;700 and it will return a css response. Copy the urls for latin font faces:
/* latin */
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 400;
  src: url(https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2)
    format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

/* latin */
@font-face {
  font-family: "Roboto";
  font-style: normal;
  font-weight: 700;
  src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmWUlfBBc4AMP6lQ.woff2)
    format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
  1. Now go to those URLs, and they will return those woff2 files needed for rendering your page. Rename them for readability and store them on your server.

  2. Now, from caching/configure settings, enable cache level standard, then the Cloudflare CDN will automatically cache those fonts, and you will see response time come down to 100ms.

  3. This approach will work for any custom fonts as long as you have them in your server.

Use Cloudflare Workers (Serverless)

If you don’t want to store the font files in the server, an alternative is to use Cloudflare workers, where you will use the cache API. We will be proxying requests from our domain to Google Font. Then we will store the responses in the cache. Let’s see the steps for setting up the worker:

  1. Go to your worker settings from your dashboard and click on the “Manage Workers” button to go to the worker manage page.
  2. Then create the worker by clicking on the “Create Worker” button.
  3. Copy paste the following code (the original source code with explanation is available on GitHub):
const domain = "/domain.com/fonts/";
const cssHostName = "fonts.googleapis.com";
const fontHostName = "fonts.gstatic.com";

async function handleRequest(event) {
  const request = event.request;
  const url = new URL(request.url);
  const cacheKey = new Request(url.toString(), request);
  const cache = caches.default;
  let response = await cache.match(cacheKey);

  if (!response) {
    if (url.pathname.includes("/s/")) {
      response = await processFontResponse(url, request, response);
    } else {
      response = await processCssResponse(url, request, response);
    }
    event.waitUntil(cache.put(cacheKey, response.clone()));
  }
  return response;
}

addEventListener("fetch", (event) => {
  return event.respondWith(handleRequest(event));
});

async function processCssResponse(url, request, response) {
  url.hostname = cssHostName;
  response = await fetch(url.toString(), request);
  const originalBody = await response.text();
  const modified = originalBody.replaceAll(fontHostName, domain);
  response.headers.append(
    "Cache-Control",
    "max-age=31536000, s-maxage=31536000"
  );
  response = new Response(modified, {
    status: response.status,
    statusText: response.statusText,
    headers: response.headers,
  });
  return response;
}

async function processFontResponse(url, request, response) {
  url.hostname = fontHostName;
  response = await fetch(url.toString(), request);
  return response;
}
  1. In this code, we will accept any request and replace the hostname with Google font’s one. Then we will send the request to Google and store the response in cache, then return it to the client. Then we need to save it. Also, update the domain variable to point to your own domain.

  2. (Optional) If you have a different CDN for serving the fonts, then updated the code for cssHostName and fontHostName to point to the CDN. You can mask the CDN with your own URL with this worker and add prevention methods (like checking the origin of the request) so that the URL can’t be called from outside of your own domain.

  3. The next step here is to add a route to the worker we have developed. Go to your worker page and click on add route.

  4. Suppose your domain serves font at path /fonts, for example like this https://domain.com/fonts/css2?family=Roboto:wght@400;700 (like google fonts), then you can add the worker to that path like this:

*.domain.com/fonts/*
  1. Finally, add these lines in the header for loading the fonts:
<link
  href="https://domain.com/fonts/css2?family=Roboto:wght@400;700&display=swap"
  rel="stylesheet"
/>

In this approach, the worker cache will store the fonts, and it won’t call Google CDN all the time for loading fonts. Also, there won’t be many requests to the worker as we have added max-age=31536000, s-maxage=31536000 (1 year); hence browser will cache those calls.

In Conclusion

In this article, we saw two different ways to serve Google fonts in your website. I prefer the first approach because it is consistent and easier to implement. If you have any opinions, please share via the comment section below. Cheers!!

Last updated: Apr 05, 2024


← Previous
Create Workflow using Alacritty, Fish Shell, tmux, and Vim

With the power of Alacritty, Fish Shell, tmux, and Vim, take your coding experience to the next level.

Next →
Add Search Functionality in Hugo

A simple step by step guide to build search functionality in Hugo using Lunr and a few lines of JavaScript.

Share Your Thoughts
M↓ Markdown