Cloudflare Workers やる
Cloudflare Workers というものがある。JavaScriptやRustのコードをCDNエッジ上で実行できる serverless 環境らしい。
webpack使ってるのか。esbuildにしたい、と思ったらそういう記事があった。
PrettierとJestの設定は完璧なのにESLintの設定がないの謎すぎる。
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
]
}
tsconfig.json間違ってますよ。
{
"compilerOptions": {
"outDir": "./dist",
"module": "commonjs",
"target": "esnext",
"lib": ["esnext"],
"alwaysStrict": true,
"strict": true,
"preserveConstEnums": true,
"moduleResolution": "node",
"sourceMap": true,
"esModuleInterop": true,
"types": [
"@cloudflare/workers-types",
"@types/jest",
"@types/service-worker-mock"
]
},
- "include": ["src"],
+ "include": ["src/**/*"],
"exclude": ["node_modules", "dist", "test"]
}
.prettierrcに semi:true
と singleQuote:true
が入っていて怒りの変更を行った。
主な型定義は @cloudflare/workers-types
パッケージで行われているようだ。
なお、"lib": ["esnext", "webworker"],
とする資料があるが、
には
⚠️ If you're upgrading from version 2, make sure to remove
webworker
from thelib
array in yourtsconfig.json
. These types are now included in@cloudflare/workers-types
.
とある。Cloudflare Workers は Web Worker に倣ったAPIらしいがそれそのものではないと思うので型定義が全部 Cloudflare の管理下にあることはおそらくいいことなのだろう。
moduleResolutionを見て、そういえばCF Workersは何で動いているんだろうという疑問が出てきた。トランスパイル先バージョンを気にしなければいけない。で、Docsを探し回った結果
に
Cloudflare Workers uses the V8 JavaScript engine from Google Chrome. The Workers runtime is updated at least once a week, to at least the version that is currently used by Chrome's stable release. This means you can safely use the latest JavaScript features, with no need for transpilers.
All of the standard built-in objects supported by the current Google Chrome stable release are supported, with a few notable exceptions:
と書いてあった。「from Google Chrome」というのは「Google Chromeでも使われている」みたいな表現ではなく本当にGoogle ChromeのV8を使っているということだと思う。
これもしかして本物のWeb Workerが動いてるってこと?WorkerGlobalScopeにあるものが全部使えるらしい。
esbuildを導入してこんな感じのコードを書く。Nodeの現行LTS(14.18.0)ではTLA[1]できないのでIIAFE[2]を挟んでおくが、Node v17がついさっき出てもうすぐLTSがv16に移行する頃合いなので剥がせるはず。
/* eslint-env node */
import esbuild from "esbuild";
(async () => {
try {
await esbuild.build({
entryPoints: ["src/index.ts"],
bundle: true,
minify: true,
outfile: "dist/worker.js",
format: "esm",
});
console.log(`✅ successfully bundled`);
} catch (reason) {
console.error(reason);
console.error(`❌ bundle failed`);
}
})();
Workers KV といって、WorkerからKey-Value storeが利用できる。wrangler kv:namespace create "COUNT" --preview
のようなコマンドを叩くとストアができる。同時にCLIから { binding = "COUNT", preview_id = "hogehogefugafuga", id = "foobarbaz" }
のようなオブジェクトが吐き出されるのでこれを wrangler.toml
に追記する。
name = "aumy-playground"
type = "javascript"
zone_id = ""
account_id = ""
route = ""
workers_dev = true
compatibility_date = "2021-10-21"
+ kv_namespaces = [
+ { binding = "COUNT", preview_id = "hogehogefugafuga", id = "foobarbaz" },
+ ]
[build]
command = "npm install && npm run build"
[build.upload]
format = "service-worker"
binding
するとWorkerで動かすコードのグローバル変数として束縛されるので、declare
を使ってその存在を明示しておく。wrangler.toml
を読んで自動的にこれ追加してくれるようにしたら面白そう。TypeScript compiler pluginでできたりするだろうか?
declare let COUNT: KVNamespace;
export async function handleRequest(request: Request): Promise<Response> {
let count = await COUNT.get(request.method, "json");
if (typeof count !== "number") count = 0;
const newCount = (count as number) + 1;
COUNT.put(request.method, String(newCount));
return new Response(`${request.method}: ${newCount}`);
}
ちなみにこのコードはHTTPメソッドごとのアクセス数を数えてくれるアプリ。