Skip to content

非公式本サイトは非公式の日本語ドキュメントであり、Cloudflare 公式サイトではありません。最新情報はdevelopers.cloudflare.comをご確認ください。

静的フロントエンドと Container バックエンド

コンテナ化したバックエンドを持つシンプルなフロントエンドアプリ

最終更新 Markdown で表示Agent セットアップ

よくある構成は、Static Assets で静的なフロントエンドアプリ(React、Vue、Svelte など)を配信し、バックエンドへのリクエストをコンテナ化したバックエンドアプリへ渡す方法です。

この例では、静的アセットとして配信するシンプルな index.html を使います。フロントエンドフレームワークはほかにも選べます。詳細は Workers のフレームワーク例 を参照してください。

完全な例は Static Frontend + Container Backend Template を参照してください。

Static Assets と Container を設定する

{
  "name": "cron-container",
  "main": "src/index.ts",
  "assets": {
    "directory": "./dist",
    "binding": "ASSETS"
  },
  "containers": [
    {
      "class_name": "Backend",
      "image": "./Dockerfile",
			"max_instances": 3
    }
  ],
  "durable_objects": {
    "bindings": [
      {
        "class_name": "Backend",
        "name": "BACKEND"
      }
    ]
  },
  "migrations": [
    {
      "new_sqlite_classes": [
        "Backend"
      ],
      "tag": "v1"
    }
  ]
}
name = "cron-container"
main = "src/index.ts"

[assets]
directory = "./dist"
binding = "ASSETS"

[[containers]]
class_name = "Backend"
image = "./Dockerfile"
max_instances = 3

[[durable_objects.bindings]]
class_name = "Backend"
name = "BACKEND"

[[migrations]]
new_sqlite_classes = [ "Backend" ]
tag = "v1"

配信用のシンプルな index.html を追加する

./dist ディレクトリに、シンプルな index.html ファイルを作成します。

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Widgets</title>
  <script defer src="https://cdnjs.cloudflare.com/ajax/libs/alpinejs/3.13.3/cdn.min.js"></script>
</head>

<body>
  <div x-data="widgets()" x-init="fetchWidgets()">
    <h1>Widgets</h1>
    <div x-show="loading">Loading...</div>
    <div x-show="error" x-text="error" style="color: red;"></div>
    <ul x-show="!loading && !error">
      <template x-for="widget in widgets" :key="widget.id">
        <li>
          <span x-text="widget.name"></span> - (ID: <span x-text="widget.id"></span>)
        </li>
      </template>
    </ul>

    <div x-show="!loading && !error && widgets.length === 0">
      No widgets found.
    </div>

  </div>

  <script>
    function widgets() {
      return {
        widgets: [],
        loading: false,
        error: null,

        async fetchWidgets() {
          this.loading = true;
          this.error = null;

          try {
            const response = await fetch('/api/widgets');
            if (!response.ok) {
              throw new Error(`HTTP ${response.status}: ${response.statusText}`);
            }
            this.widgets = await response.json();
          } catch (err) {
            this.error = err.message;
          } finally {
            this.loading = false;
          }
        }
      }
    }
  </script>

</body>

</html>

この例では、Alpine.js を使って /api/widgets からウィジェット一覧を取得します。

ごく簡単な例ですが、構成はかなり複雑にもできます。詳細は フロントエンドフレームワークと Workers を組み合わせる例 を参照してください。

Worker を定義する

Worker は、静的アセットの配信と、コンテナ化したバックエンドへのリクエスト振り分けの両方を行う必要があります。

この例では、ルートが /api で始まる場合は 3 つのコンテナインスタンスのいずれかにリクエストを渡し、それ以外は静的アセットとして配信します。

import { Container, getRandom } from "@cloudflare/containers";

const INSTANCE_COUNT = 3;

class Backend extends Container {
	defaultPort = 8080; // pass requests to port 8080 in the container
	sleepAfter = "2h"; // only sleep a container if it hasn't gotten requests in 2 hours
}

export default {
	async fetch(request, env) {
		const url = new URL(request.url);
		if (url.pathname.startsWith("/api")) {
			const containerInstance = await getRandom(env.BACKEND, INSTANCE_COUNT);
			return containerInstance.fetch(request);
		}

		return env.ASSETS.fetch(request);
	},
};

バックエンドコンテナを定義する

コンテナは /api/widgets へのリクエストを処理できる必要があります。

この例では、ハードコードしたウィジェット一覧を返すシンプルな Golang バックエンドを使います。

server.go

package main

import (
	"encoding/json"
	"log"
	"net/http"
)

func handler(w http.ResponseWriter, r \*http.Request) {
	widgets := []map[string]interface{}{
		{"id": 1, "name": "Widget A"},
		{"id": 2, "name": "Sprocket B"},
		{"id": 3, "name": "Gear C"},
	}

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")
	json.NewEncoder(w).Encode(widgets)

}

func main() {
	http.HandleFunc("/api/widgets", handler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

役に立ちましたか?