Ultrafast Serverless Sites: Our Cloudflare Pages Prototype

At Whitespectre, we’ve continued to experiment with the growing number of platform-as-service options for building websites over the years. Netlify and Vercel have already proven the power of the JAMstack framework to create ultra-fast, secure, and decoupled sites with zero setups. ‘Pages’, launched in 2021 and officially full-stack as of November, is Cloudflare’s response to that.

With Pages, it’s now possible to create full-stack applications by running code on the Cloudflare network with support from Cloudflare Workers. On top of that, Cloudflare Functions enables to run server-side code to allow dynamic functionality without having to run a dedicated server.

So just how easy is it to create a web app with Pages and how quickly can you do it? Read on to see how Alex N. put a JAMstack-like application on Cloudflare using Pages, Workers and Functions.

Working with Functions

The difference between functions and workers is built-in routing. Functions provides a Next.js alike routing convention. The general idea is that the path and the filename is the same as a route that would be exposed on the server. The only thing you need to do to make the function happen is to put it in the functions folder of the app root, and it’s ready to be used. And the best part about it is that it supports TypeScript out of the bot. That’s correct; you do not need to set up any deployment pipelines to make TypeScript functions work.


    export const onRequestPost: PagesFunction = async () => new Response('pong');

Once you send post to the server, you will receive pong as a response. Note how the exported method name indicates what is the HTTP verb would be set for the route.

How to Create an App

In addition, with skeleton screens, the parts of the application that depend on different network requests can gradually load, and those that don’t depend on the data, like menu links, are ready to use from the start. So skeleton screens also improve usability– they’re not just a neat trick to hack the human perception of time.

So let’s create a simple note-sharing tool. The idea behind it would be a simple UI that’ll allow you to paste any text. Backend will generate a unique code for the text to share the link later on. The note itself will be stored in the Cloudflare KV.

Before we start, I should mention a slight limitation of Cloudflare workers. It’s not a NodeJs, and it uses a V8 engine; therefore, you won’t be able to use node-specific packages such as fs or net.

To prepare Pages' environment, first, you’d need to create a Key Value namespace which will store all the notes. To do that you need to go to the Workers page, go to the KV tab, and create a new namespace.

The App

Cloudflare supports multiple types of applications but I’ll start with a simple react app. Once the application is set up you can create a Cloudflare Pages, connect it to the repository and the project would be deployed automatically.

The next step would be to connect our KV storage to the Pages project. This could be achieved on the settings page. KV storage will be available at the requested time in the function by the name that is put to the variable’s name input.

Adding a function is quite simple as well, just create a functions/create_note.ts file.

    const generateId = async (kv: KVNamespace) => {
     while(true) {
       const randomBytes = crypto.getRandomValues(new Uint8Array(8));
     
       const id = [...randomBytes].map(byte => byte.toString(16).padStart(2, '0')).join('');
       if(await kv.get(id)) {
         continue;
       }
       return id;
     }
    }
     
    export const onRequestPost : PagesFunction<{ NOTES: KVNamespace }> = async ({ request, env }) => {
     
     const body = await request.json();
     const id = await generateId(env.NOTES);
     
     await env.NOTES.put(id, body.text);
     
     return new Response(JSON.stringify({ id }));
    };

The generateId function creates a unique key to store a note. Also, it performs a check in the KV storage to see whether that key already exists and retry if it does.

The saving portion is not any more interesting; it’s basically getting what to save and respond with the id.

Note that the Notes environment variable that’s been set up in the settings is available through the environment parameter that is coming along with every request to the function. That’s a KV client binding that is provided automatically.

Receiving value is even simpler than creating. To begin with, we need to create a file functions/get_note/.ts. is a special notation for wildcard param type. Any url that looks like get_note/* would be routed to that function. In addition you’ll receive param value as well.

The code would look like this:

    export const onRequestGet : PagesFunction<{ NOTES: KVNamespace }> = async ({ params, env }) => {
    
     const { id } = params;
     
     if (!id) {
       return new Response(JSON.stringify({ error: 'No id provided'}), { status: 400 });
     }
     
     const text = await env.NOTES.get(id);
     
     if (text !== null) {
       return new Response(JSON.stringify({ text }));
     }
     
     return new Response(JSON.stringify({ error: 'Not found'}), { status: 404 });
    };

So the final result would look like this:

As you can see we have developed an app in minutes, which creates unique notes that are loaded in no time. And this is just a simple example of the power of Cloudflare Pages.

Let’s Chat