更新日:

Cloudflare Workers。GitHub Actionsで自動デプロイして静的ファイルをホスティングする。

環境変数

CF_API_TOKEN → APIトークン
CF_ACCOUNT_ID → アカウントID

ソースコード

.github/workflows/deploy.yml
name: CD
on:
  push:
    branches:
      - main

jobs:
  deploy:
    name: CD
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2
        
      - name: Publish
        uses: cloudflare/wrangler-action@1.3.0
        with:
          apiToken: ${{ secrets.CF_API_TOKEN }}
        env:
          CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
wrangler.toml
name = "project-name"
type = "webpack"
account_id = ""
workers_dev = true
route = ""
zone_id = ""

[site]
bucket = "dist"
entry-point = "workers-site"
workers-site/index.js
import {
  getAssetFromKV,
  mapRequestToAsset,
  serveSinglePageApp,
} from '@cloudflare/kv-asset-handler';

addEventListener('fetch', event => {
  try {
    event.respondWith(handleEvent(event));
  } catch (e) {
    event.respondWith(new Response('Internal Error', { status: 500 }));
  }
});

async function handleEvent(event) {
  try {
    let resp = await getAssetFromKV(event, {});

    // SPA用
    // let resp = await getAssetFromKV(event, {
    //   mapRequestToAsset: serveSinglePageApp,
    // });

    resp = new Response(resp.body, {
      status: resp.status,
      headers: resp.headers,
      statusText: resp.statusText,
    });

    resp.headers.set('X-Frame-Options', 'SAMEORIGIN');
    return resp;
  } catch (e) {
    try {
      let notFoundResponse = await getAssetFromKV(event, {
        mapRequestToAsset: req =>
          new Request(`${new URL(req.url).origin}/404.html`, req),
      });

      return new Response(notFoundResponse.body, {
        ...notFoundResponse,
        status: 404,
      });
    } catch (e) {}
    
    return new Response(e.message || e.toString(), { status: 500 });
  }
}
workers-site/package.json
{
  "main": "index.js",
  "dependencies": {
    "@cloudflare/kv-asset-handler": "~0.0.11"
  }
}
dist/index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>top page</title>
  </head>
  <body>
    <h1>top page</h1>
  </body>
</html>
dist/404.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>404 page</title>
  </head>
  <body>
    <h1>404 page</h1>
    <a href="/">top pageへ</a>
  </body>
</html>