How can I use Cloudflare workers to optimize TTFB for a static website?

Viewed 649

I have a website that is hosted on GitHub Pages, fully static HTML that loads reasonably fast. I have been trying to cut the TTFB Time (as well as FCP, LCP and Fully Loaded).
Trying to focus on TTFB now, I made several attempts.

  1. Using Cloudflare in DNS Only mode, I'm getting a consistent TTFB that's 99% below 30ms.
  2. Using Cloudflare in Proxy mode with page rules to "Cache Everything", the TTFB is always above 100ms.

Then I tried using Cloudflare workers, the idea was simple:

  • a. Fetch the current site content into a worker.
  • b. cache the content
  • c. Serve the cached content

Surprisingly, I could get nothing better than 80ms, though I was expecting a much less TTFB than my 1st trial (DNS-Only mode), on average, the TTFB is somewhere between 100ms and 150ms; I'm testing the Worker's url (random-name.organization-name.workers.dev). I suspect there is something not right with my worker code, Here is what I tried so far (Mostly from the docs)

const url = "https://domain.extension"
async function gatherResponse(response) {
  const { headers } = response
  return await response.text()
}
async function handleRequest() {
  const init = {
    headers: {
      "content-type": "text/html;charset=UTF-8",
    },
    cf: {
      cacheTtl: 50000,
      cacheEverything: true,
    },
  }
  const response = await fetch(url, init)
  const results = await gatherResponse(response)
  return new Response(results, init)
}
addEventListener("fetch", event => {
  return event.respondWith(handleRequest())
})

Could there be a way to cache everything and let the worker serve that faster than the DNS-Only Option? I tried upgrading my Cloudflare plan and also got a paid worker hoping to get few more milliseconds saved hopelessly.

4 Answers

When it comes to basic caching like you describe, Workers will not provide any benefit over Cloudflare's built-in HTTP caching options. If you have already set page rules to specify "cache everything" and "edge cache TTL 50000", then the Worker code you wrote won't have any additional effect. Workers are useful when you have more complicated logic that can't be expected using Page Rules alone.

(In fact, the specific code you posted will actually makes the TTFB worse, because it does await response.text() before returning the response -- this forces the Worker to wait for the entire response body to reach Cloudflare before any of the response is sent to the client. Normally, Workers would stream the response content through as it arrives.)

If you find that your site is faster in DNS-only mode than it is in proxied mode, this most likely means that the location you are measuring the speed from (e.g. your home internet) is coincidentally closer to your origin servers than it is to Cloudflare. This is unusual, but it can happen. To get a more realistic idea of the performance difference, you will need to measure from several locations around the world. Note that because GitHub itself already uses a caching CDN to serve Pages, you may still find that the average performance difference is not very large.

Github Pages has a 10 minute/600 second Cache Control header. This "works" enough. If you break you website with "git push" to your customers, the defects on your site go away in 10 minutes.

I keep my github pages with Cloudflare infront as

foosite.tk/* Browser Cache TTL: 8 days, Cache Level: Cache Everything, Edge Cache TTL: 7 days

Github Pages raw will result in your browser always doing a ton of
"304 not modified" requests on all assets after "a few minutes" "when you come back" to the tab. Use the above settings to make the browser cache things almost forever and make CF cache things almost forever. You will have to use in CF Dash "purge everything" to make your git push to github show up on client site, plus force refreshing the clients.

I m working on the TTFB too and have the same observation that CF increases TTFB in certain locations (in my case Hong Kong and Taiwan).

My ticket to CF - https://vocus.cc/article/609f1dfdfd897800011cbfa2

Read from CF that their routing may not be 100% geo optimized if u r not on Enterprise plan (that post said test from India traffic was found routed to CF server in Singapore then back to India)

My measure now is to "cache everything" with page rules, though it still couldn't fall below 100ms (but DNS only can), it reduces a lot on the peaks, seldom see over 400ms TTFB with cache everything.

If you modify your worker to use Cloudflare's Cache API, and then serve results out of there you should see much faster times than 100ms or even 30ms. I've observed that a worker returns cached data (in Cache API) in ~10ms quite consistently, though of course this can/will vary.

Here's a decently close example to what you're asking about, based on this Cloudflare tutorial:

async function serveAsset(event) {
  const url = new URL(event.request.url);
  const cache = caches.default;   // this hooks up the Caches API
  let response = await cache.match(event.request);
  if (!response) {
    response = await fetch(...); // github url goes here
    const headers = { 'cache-control': 'public, max-age=14400' };
    response = new Response(response.body, { ...response, headers });
    event.waitUntil(cache.put(event.request, response.clone()));
  }
  return response;
}
Related