Cloudflare Workersの最小限のテンプレートの作り方

この記事は[syumai Advent Calendar 2024](https://adventar.org/calendars/11019)の5日目の記事です。
木曜なので、Cloudflare Workersがテーマとなります。

# Cloudflare Workersのテンプレートとは

Cloudflare Workersのプロジェクトは、[C3(create-cloudflare-cli)](https://developers.cloudflare.com/workers/get-started/guide/) と呼ばれるCLIツールで簡単に立ち上げることができます。

```console
$ npm create cloudflare@latest
```

このコマンドを実行すると、いくつかのステップに分けてプロジェクトの初期化が進んでいきますが、初手でどのテンプレートを使うか尋ねられます。

```console
╰ What would you like to start with?
  ● Hello World example
  ○ Framework Starter
  ○ Application Starter
  ○ Template from a GitHub repo
  ◁ Go back
```

ここで「Framework Starter」を選択すると、選択可能なWebフレームワークのテンプレート一覧が表示されます。

```console
╰ Which development framework do you want to use?
  ● Analog
  ○ Angular
  ○ Astro
  ○ Docusaurus
  ○ Gatsby
  ○ Hono
  ○ Next
  ...
```

これらのテンプレートは、C3に組み込みのものとなっていますが、サードパーティの開発者がテンプレートを用意して、ユーザーに使ってもらうこともできます。こうしたテンプレートのことを、**リモートテンプレート** (remote-template)[^1] といいます。

リモートテンプレートでプロジェクトを初期化したい場合は、先ほどの「What would you like to start with?」の選択肢として「Template from a GitHub repo」を選んで進む形となります。または、　`npm create cloudflare@latest -- --template ${リモートテンプレートの識別子}` のオプションも使うことができます。 

リモートテンプレートの識別子として使えるのは、以下の表現です。 `user/repo` から始まるものは、自動的にGitHubが選択されます。

* `user/repo`
* `git@github.com:user/repo`
* `https://github.com/user/repo`
* `user/repo/some-template (subdirectories)`
* `user/repo#canary (branches)`
* `user/repo#1234abcd (commit hash)`
* `bitbucket:user/repo (BitBucket)`
* `gitlab:user/repo (GitLab)`

[^1]: "remote-template: Template from a GitHub repo"  https://developers.cloudflare.com/pages/get-started/c3/#cli-arguments
[^2]: "The value for this option may be specified as any of the following"  https://developers.cloudflare.com/pages/get-started/c3/#cli-arguments

# リモートテンプレートの構成

テンプレートは、下記の3点を含む必要がある[^2]とドキュメントに記載されています。

* `package.json`
* `wrangler.jsonc`
* `wrangler.jsonc` から参照されるWorkerのスクリプトを含む `/src` ディレクトリ

色々試したり、C3の実装を読んでみたりしましたが、実際のところはWorkerのスクリプトが存在しなくてもC3自体は動作するようでした。`package.json` と `wrangler.jsonc` は必須となります。とは言え、Workerのスクリプトが存在しないテンプレートを作っても、利用者が困惑するだけなので含めておくべきでしょう。

## C3の機能

C3はプロジェクトの初期化時に、テンプレートをダウンロードした上で、以下の作業を自動的に行ってくれます。

* package.json内のアプリケーション名の差し替え
* wrangler.jsonc内のアプリケーション名の差し替え
* wrangler.jsonc内の `compatibility_date` の最新版への差し替え
* .gitignoreへのwrangler関連ファイルのパスの追加
* 依存関係のインストール

このおかげで、ユーザーが自身の手でアプリケーション名を設定ファイルに書く必要がありませんし、自動的に差し替えや追加が行われる情報は常に最新のものに保たれるので、テンプレート提供者の立場としては非常に楽です。

[^3]: "At a minimum, templates must contain the following" https://developers.cloudflare.com/pages/get-started/c3/#cli-arguments

## package.jsonの内容

以下に、実際のpackage.jsonの内容例を示します。

```json
{
	"name": "<TBD>",
	"version": "0.0.0",
	"scripts": {
		"deploy": "wrangler deploy",
		"dev": "wrangler dev",
		"start": "wrangler dev"
	},
	"devDependencies": {
		"wrangler": "^3.92.0"
	}
}
```

`"name"` キーは、C3によって値が自動的に差し替えられるので、検知のために`"<TBD>"`, `"TBD"`, `""`のいずれかを値として設定しておく必要があります[^3]。 C3のリポジトリ ([workers-sdk](https://github.com/cloudflare/workers-sdk/blob/create-cloudflare%402.33.2/packages/create-cloudflare/templates/common/ts/package.json#L2)) では `"<TBD>"` が使われているようなので、これに合わせるのがよいでしょう。

`"scripts"` は親切のためにではありますが、deploy, dev, startくらいは登録しておくのがよさそうです。

[^4]: package.jsonの `"name"`キーの差し替え処理 https://github.com/cloudflare/workers-sdk/blob/create-cloudflare%402.33.2/packages/create-cloudflare/src/templates.ts#L705

## wrangler.jsoncの内容

以下に、実際のwrangler.jsoncの内容例を示します。

```jsonc
{
  "name": "<TBD>",
  "main": "index.js",
  "compatibility_date": "<TBD>"
}
```

`name` キーの内容は何でもOKです。ここは、nameキーの内容を丸ごと置き換える実装[^4]となっています。
`compatibility_date` キーについては、有効なcompatibility_dateの形式の文字列が設定されていない場合に、最新の値へ更新する実装[^5]となっています。

:::note info
実は、wrangler.jsoncはもっと内容を削ることができそうです。具体的には、 `main` キーだけ残す形を許容する実装のように見えました。この場合、`name` と `compatibility_date` が自動的に追加されます。
:::

[^5]: wrangler.jsoncの `name` キーの差し替え処理 https://github.com/cloudflare/workers-sdk/blob/create-cloudflare%402.38.1/packages/create-cloudflare/src/wrangler/config.ts#L10

[^6]: wrangler.jsoncの `compatibility_date` キーの差し替え処理 https://github.com/cloudflare/workers-sdk/blob/create-cloudflare%402.38.1/packages/create-cloudflare/src/wrangler/config.ts#L18

## .gitignoreの内容

.gitignoreについては、空ファイルを設置しておくだけで下記の内容が自動的に書き込まれます。便利ですね。

```
# wrangler files
.wrangler
.dev.vars
```

## Workerのスクリプトの内容

C3はWorkerのスクリプトの内容を操作しないので、何でも大丈夫だと思います。
一応示しておくと、以下の内容でほぼ最小ではないでしょうか。

```js
export default {
  fetch() {
    return new Response("Hello, world!");
  },
};
```

# 実際のコード

ここまでで説明した内容の通りのテンプレートを、以下に設置しました。

https://github.com/syumai/workers-playground/tree/main/minimum-template

次のコマンドで、実際にこのテンプレートからプロジェクトを立ち上げられるので、ぜひ試してみてください。

```console
npm create cloudflare@latest -- --template syumai/workers-playground/minimum-template
```

npmではなくyarnやpnpmを使いたければ、呼び出し方法を変えるだけでOKです。pnpmで試してみましたが、C3が自動的に行う依存のインストールできちんとpnpmが使われ、pnpm-lock.yamlが生成されていました。C3は、この辺りも含めてかなり気が利くという印象です。

```console
pnpm create cloudflare@latest --template syumai/workers-playground/minimum-template
```

# 最後に

C3は、Cloudflare Workersで使えるライブラリやフレームワークを開発している方にとっても、便利に使うことができるテンプレート機能を提供してくれています。
皆さんも、自作のライブラリ・フレームワークをCloudflare Workersで活用して欲しいと思ったらぜひ本機能の利用を検討してみてください。