INTEGRITY Dokumentace

Statický frontend, kontejnerizovaný backend

Běžným postupem je obsluhovat statickou frontendovou aplikaci (například React, Vue, Svelte) pomocí Static Assets a požadavky na backend předávat kontejnerizované backendové aplikaci.

V tomto příkladu si ukážeme použití jednoduchého index.html soubor obsluhovaný jako statické aktivum, ale můžete si vybrat i z mnoha frontendových frameworků. Podívejte se na naši příklady frameworků pro Workers s dalšími informacemi.

Úplný příklad najdete v Šablona statický frontend + kontejnerizovaný backend ↗.

Konfigurace Static Assets a Containeru

{
  "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"

Přidejte jednoduchý soubor index.html, který se má obsluhovat

Vytvořte jednoduchý index.html soubor v ./dist adresář.

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>

V tomto příkladu používáme Alpine.js ↗ k načtení seznamu widgetů z /api/widgets.

Jde o velmi jednoduchý příklad, ale řešení může být výrazně složitější. Viz příklady integrace Workers s frontendovými frameworky s dalšími informacemi.

Definice Workeru

Váš Worker musí umět zároveň obsluhovat statická aktiva i směrovat požadavky na kontejnerizovaný backend.

V tomto případě předáme požadavky jedné ze tří instancí kontejneru, pokud trasa začíná na /api, a všechny ostatní požadavky budou obslouženy jako statická aktiva.

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);
	},
};

Definice backendového kontejneru

Váš kontejner by měl umět zpracovávat požadavky na /api/widgets.

V tomto případě použijeme jednoduchý backend v Go, který vrací pevně zadaný seznam widgetů.

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))
}