iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌥️

Hosting a Site with Cloudflare Pages (Functions and KV): A Practical Guide

に公開

Introduction

This article will create a project that leverages Cloudflare Pages as a starting point to explore various aspects of the Cloudflare ecosystem. Specifically, it will cover the following:

  • How to use a custom domain with Cloudflare Pages
  • How to try out Cloudflare Functions (beta)
  • How to use Cloudflare Worker KV
  • How to apply IP filter settings to a site hosted on Cloudflare Pages

Architecture

As shown in the figure below, the architecture involves reading and writing to Cloudflare KV via Cloudflare Functions from a site hosted on Cloudflare with a custom domain. (Hereafter, Cloudflare Functions may be abbreviated as Functions, and Cloudflare KV as KV.)

img

Environment Information

  • Domain acquired with Google Domains (you can use any registrar by replacing it as appropriate)
  • Zone Apex domain set for Cloudflare Pages
Tool Version
node v16.10.0

Cloudflare WebSites Setup

Set up Cloudflare WebSites. This setting is a prerequisite for applying a custom domain.

img

Enter the domain name you have acquired.
img

Select the free plan.
img

img

Cloudflare will check the domain and display additional setup instructions. In this case, it explains how to change the Name Server on Google Domains. Make a note of the Name Servers.
img

Go to Google Domains settings. Set the Name Servers you copied from the Cloudflare console earlier.
img

Return to the Cloudflare console and open WebSites to confirm that the status is Active.
img

Creating a Cloudflare Pages Project

Project Template Initialization

Initialize the project using vite.

$ npm init vite@latest
 Project name: cf-sample-site
 Select a framework: react
 Select a variant: react-ts

Scaffolding project in /Users/hoge/repos/github.com/shuntaka9576/cf-sample-site...

Done. Now run:

  cd cf-sample-site
  npm install
  npm run dev
$ cd cf-sample-site
$ yarn install
$ yarn dev

Installing Necessary Libraries

Install cloudflare/wrangler2, the official Cloudflare CLI. Although not used in this article, it's good practice to install the type definition files along with it. (It can also be installed with wrangler init.)

$ yarn add -O wrangler@beta
$ yarn add -D @cloudflare/workers-types
$ yarn wrangler --version
(truncated)
0.0.16

Creating and Configuring Cloudflare KV

Initialize the wrangler configuration file.

$ yarn wrangler init
(truncated)
Would you like to install wrangler into your package.json? (y/n)
# => Enter n because it's already installed
Would you like to create a Worker at src/index.ts? (y/n)
# => Enter n because it won't be used

The generated configuration file looks like this:

wrangler.toml
compatibility_date = "2022-02-07"

Create Cloudflare KV via CLI.

$ yarn wrangler kv:namespace create "MY_KV_DEV"

Executing this command will launch a browser, and after logging in, you will be redirected to an authorization screen like the one below.

img

After setup is complete, a screen like this will be displayed.
img

Return to the console and confirm that the KV creation process is complete.

$ yarn wrangler kv:namespace create "MY_KV_DEV"
yarn run v1.22.17
warning package.json: No license field
(truncated)
Successfully configured. You can find your configuration file at: /Users/hoge/.wrangler/config/default.toml
🌀 Creating namespace with title "worker-MY_KV_DEV"
 Success!
Add the following to your configuration file in your kv_namespaces array:
{ binding = "MY_KV_DEV", id = "xxxxx" }
  Done in 12.52s.

After creation, confirm that the created KV exists on the console.
img

You can also check it from the CLI.

$ yarn wrangler kv:namespace list
[
  {
    "id": "xxxxx",
    "title": "worker-MY_KV_DEV",
    "supports_url_encoding": true
  }
]

As per the CLI output, add the Cloudflare KV configuration to wrangler.toml.
[ts gutter="false" title="wrangler.toml"]

wrangler.toml
compatibility_date = "2022-02-07"

kv_namespaces = [
  { binding = "MY_KV_DEV", id = "xxxxx" }
]

Implementing Cloudflare Functions and a UI for verification

We will implement the verification UI and Cloudflare Functions.

Implement the verification UI. (Apologies, I'm not strong in frontend development, please submit an issue if there are any code deficiencies.)

src/App.tsx
import { useEffect, useState } from "react";

type WriteItem = {
  key: string;
  value: string;
};

const App = () => {
  const [schedulePostData, setSchedulePostData] = useState<WriteItem>();
  const [data, setGetData] = useState('');

  useEffect(() => {
    const timestamp = Date.now();
    const key = `key:${timestamp}`;
    const value = `value:${timestamp}`;

    setSchedulePostData({ key: key, value: value });
  }, [])

  const updateTime = () => {
    const timestamp = Date.now();
    const key = `key:${timestamp}`;
    const value = `value:${timestamp}`;

    setSchedulePostData({ key: key, value: value });

  }

  const post = async () => {
    await fetch("/api/data", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ key: schedulePostData?.key, value: schedulePostData?.value })
    });
  };

  const get = async () => {
    const data = await fetch(`/api/data/${schedulePostData?.key}`, {
      method: "GET",
      headers: {
        "Content-Type": "application/json"
      },
    });

    const parsedJson = await data.json();
    setGetData(parsedJson.value)
  };


  return (
    <div className="App">
      <p>Data to write<button onClick={() => updateTime()}>Update</button></p>
      <ul>
      <li>Key: {schedulePostData?.key}</li>
      <li>Value: {schedulePostData?.value}</li>
      </ul>
      <button onClick={() => post()}>Write to Cloudflare KV</button>
      <hr/>

      <p>Get value for key {schedulePostData?.key}</p>
      <button onClick={() => get()}>Get</button>
      <p>Result: {data}</p>
    </div>
  );
};

export default App;

The Functions implementation refers to the official documentation.

Implement Functions for POST requests. The following shows a schematic diagram of its behavior.
img

functions/api/data/index.ts
export const onRequestPost = async ({ request, env }) => {
  const body = await request.clone().text();
  const parsedBody = JSON.parse(body);
  const { key, value } = parsedBody;

  await env.MY_KV_DEV.put(key, value); // Write to Cloudflare KV

  return new Response();
};

Implement GET Functions to retrieve the data written by the aforementioned Functions. The id will contain the key entered during the POST request. The following shows a schematic diagram of its behavior.
img

functions/api/data/[id].ts
export const onRequestGet = async ({ params, env }) => {
  const res = await env.MY_KV_DEV.get(params.id); // Read from Cloudflare KV

  return new Response(JSON.stringify({ value: res }));
};

Local Preview

For previewing, we will use wrangler instead of vite. This is because wrangler allows running Cloudflare KV and Cloudflare Functions locally for testing. Building is necessary, so use the following command to trigger a build when changes are detected.

$ yarn build --watch

Run wrangler. A tab will automatically open at http://localhost:8788/ by default.

Option Description
pages dev Cloudflare Pages preview
-k Specify Cloudflare KV (a simulated local KV will be run instead of the one created previously)
--live-reload Reload if changes in build assets are detected
./dist Specify build assets
$ yarn wrangler pages dev -k MY_KV_DEV --live-reload ./dist

# To set environment variables
$ yarn wrangler pages dev -k MY_KV_DEV --binding ENV_VALUE="3" --live-reload ./dist

When executed, the screen will look like this. It writes a key,value pair to Cloudflare KV and retrieves the written value.

img

Deploying to Cloudflare Pages

When creating a project for the first time, GitHub Apps authorization is required.
img

Select the repository to host.
img

This time, we will simply specify the build command and the asset directory.
img

The site deployment is complete (it won't work yet).
img

Set up the integration between Functions and KV.
img

After performing the above, please re-deploy from the Cloudflare Pages screen: View Build -> Manage deployment -> Retry development (※ This might not be necessary).

img

This setting will read/write to the actual Cloudflare KV created in the previous section. The written data can also be checked on the console.

img

Applying a Custom Domain

This time, we will assign an Apex domain like xxx.dev.

Open the Pages settings screen.
img

img
img
img

After a while, it will become Active.
img

The custom domain has been successfully applied.

img

Applying Firewall Rules

Since there might be a need for IP filtering in development environments, we will set it up.

img
img

The image below shows settings to block all addresses except the specified IPv4 and IPv6 (range) addresses. (The Rule Name is

ipv4 but it's a typo). Conditions like blocking all but multiple IPs can be achieved by using the is not in clause and entering multiple IPs into a single input box.
img

If blocked, it will appear as shown below.
img

Conclusion

In this article, we experimented with KV and Functions, starting with Cloudflare Pages. As CDN Edge technology evolves year by year, I believe there will be an increasing number of cases where it is more efficient to do what was previously done on the server-side on the CDN Edge. I hope this serves as a reference for future technology choices.

References

Discussion