🕳️
Cloudflare Durable Objects を TypeScript で使おうとしてハマった
起こった問題と解決策
環境
MacOS: Ventura 13.4.1(c)
Wrangler: wrangler 3.5.0
言語: TypeScript
問題
- 公式のドキュメントを参考に Durable Objects を TypeScript で実装した
- コード上特にエラーは起きていないが、
wrangler dev/deploy
実行時にエラーが発生した
原因と解決方法
- Durable Objects の定義クラスを別クラスとして切り出していたのが原因
- 別クラスに切り出す場合は
wrangler.toml
内のmain =
で指定されている root module から、切り出したクラスをexport
する必要がある
以下は実際のコードを交えた解説です
実装
公式の手順に沿って Durable Objects を使えるように定義
TypeScript で実装したいので後者のページを参考に実装しました
Durable Objects class
counter.ts
export class Counter {
constructor(private readonly state: DurableObjectState) {}
async fetch(_request: Request): Promise<Response> {
const id: number = await this.state.storage?.get("id") || 0;
await this.state.storage?.put("id", id+1)
return new Response(id.toString());
}
}
worker.ts
worker.ts
export interface Env {
COUNTER: DurableObjectNamespace;
}
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
const doID = env.COUNTER.idFromName("id");
const counter = env.COUNTER.get(doID);
const res = await counter.fetch(request.url);
return new Response(await res.text());
},
};
wrangler.toml
wrangler.toml
name = "wrangler-test"
main = "src/worker.ts"
compatibility_date = "2023-08-07"
[durable_objects]
bindings = [
{ name = "COUNTER", class_name = "Counter" }
]
[[migrations]]
tag = "v1"
new_classes = ["Counter"]
wrangler dev/deploy の実行
wrangler dev
$ wrangler dev
⛅️ wrangler 3.5.0
------------------
wrangler dev now uses local mode by default, powered by 🔥 Miniflare and 👷 workerd.
To run an edge preview session for your Worker, use wrangler dev --remote
Your worker has access to the following bindings:
- Durable Objects:
- Counter: Counter
⎔ Starting local server...
service core:user:wrangler-test: Uncaught TypeError: Class extends value undefined is not a constructor or null
at worker.js:90:44 in maskDurableObjectDefinition
at worker.js:99:16
✘ [ERROR] MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.
エラーが発生して起動できない
wrangler deploy
$ wangler deploy
⛅️ wrangler 3.5.0
------------------
Your worker has access to the following bindings:
- Durable Objects:
- Counter: Counter
Total Upload: 0.33 KiB / gzip: 0.22 KiB
✘ [ERROR] A request to the Cloudflare API (/accounts/xxxx/workers/scripts/wrangler-test) failed.
Cannot apply new-class migration to class Counter that is not exported by script [code: 10070]
If you think this is a bug, please open an issue at:
https://github.com/cloudflare/workers-sdk/issues/new/choose
エラーが発生してデプロイ出来ない
答え
原因
counter.ts
で export class
しているが wrangler.toml
で定義している root module からは export
していないため、定義した Durable Objects class を wrangler が認識できていなかった
解決策1. worker.ts に定義する
worker.ts
に直接定義して export
することでエラーが解消されます
worker.ts
+export class Counter {
+ constructor(private readonly state: DurableObjectState) {}
+ async fetch(_request: Request): Promise<Response> {
+ const id: number = await this.state.storage?.get("id") || 0;
+ await this.state.storage?.put("id", id+1)
+ return new Response(id.toString());
+ }
+}
解決策2. worker.ts 側からも export する
参考:wrangler.toml
の main =
で指定している root module から Durable Object
クラスを export
することでエラーが解消されます
worker.ts
+ export { Counter } from "./counter";
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext,
): Promise<Response> {
const doID = env.COUNTER.idFromName("id");
const counter = env.COUNTER.get(doID);
const res = await counter.fetch(request.url);
return new Response(await res.text());
},
};
修正後の実行
wrangler dev
⛅️ wrangler 3.5.0
------------------
wrangler dev now uses local mode by default, powered by 🔥 Miniflare and 👷 workerd.
To run an edge preview session for your Worker, use wrangler dev --remote
Your worker has access to the following bindings:
- Durable Objects:
- Counter: Counter
⎔ Starting local server...
[mf:inf] Ready on http://127.0.0.1:8787/
ローカルで起動成功
wrangler deploy
$ wrangler deploy
53.3s 月 8/14 22:12:22 2023
⛅️ wrangler 3.5.0
------------------
Your worker has access to the following bindings:
- Durable Objects:
- Counter: Counter
Total Upload: 0.59 KiB / gzip: 0.31 KiB
Uploaded wrangler-test (1.63 sec)
Published wrangler-test (3.75 sec)
https://xxx.workers.dev
Current Deployment ID: e3e4927d-7c39-466e-8147-46d29cc41287
デプロイ成功
備考
公式のドキュメントには別クラスとして Durable Objects を実装しているケースの情報が少なく、export
の必要性に気づくのに時間がかかりました
以下のような issue も上がっているので、いずれ改善されるかもしれません
Discussion