【Cloudflare Workers】最近困ったことのメモ

Cloudflare Workersで個人用のちょっとしたワークロードを組んでいるのだが、開発中にちょっと困ったことがあったので、対応した内容をここにメモで載せる。

## いくつかのパッケージがCloudflare Workers上で（nodejs_compatでも）使用できない

もともとLambdaで動かしていたワークロードをCloudflare Workersにそのまま移植したものがあったのだが、これの一部処理で使っていたパッケージが動作しなかった。

### sharp

[`sharp`](https://www.npmjs.com/package/sharp)はCloudflare Workerのランタイム上で使えないっぽい。「ぽい」というのは、実際にdeployして試したというよりローカルで`wrangler dev`実行してエラーになったことからそうだと判断した。もちろん`wrangler.toml`に`nodejs_compat`は設定済である。`wrangler dev`すると以下のようなエラーが出て、`wrangler`が起動しない。
```
✘ [ERROR] service core:user:hogehoge: Uncaught Error: [unenv] process.report.getReport is not implemented yet!

    at null.<anonymous> (index.js:50:10) in createNotImplementedError
    at null.<anonymous> (index.js:54:11) in fn
    at null.<anonymous> (index.js:51387:36) in getReport
    at null.<anonymous> (index.js:51962:23) in familyFromReport
    at null.<anonymous> (index.js:52035:21) in familySync
    at null.<anonymous> (index.js:52045:73) in isNonGlibcLinuxSync
    at null.<anonymous> (index.js:53653:63) in runtimeLibc
    at null.<anonymous> (index.js:53654:82) in runtimePlatformArch
    at null.<anonymous> (index.js:53805:27) in node_modules/sharp/lib/sharp.js
    at null.<anonymous> (index.js:20:50) in __require2



✘ [ERROR] The Workers runtime failed to start. There is likely additional logging output above.
```

### jsdom

これも↑と同じ。[`jsdom`](https://www.npmjs.com/package/jsdom)はCloudflare Workersでは使えない。こっちはワンチャンCloudflare Workers上だと動いたりしないかなと思って思い切ってDeployしてみたが、同じエラーでDeployに失敗した。なので`wrangler`でダメなものはCloudflare Workersでもダメ、なんだと思う。

```
▲ [WARNING] Import "default" will always be undefined because there is no matching export in "node_modules/unenv/dist/runtime/npm/whatwg-url.mjs" [import-is-undefined]

    required-unenv-alias:whatwg-url:6:27:
      6 │         "default" in esm ? esm.default : {}
        ╵                                ~~~~~~~


[wrangler-UserWorker:wrn] Miniflare 3 does not currently trigger scheduled Workers automatically.
Use `--test-scheduled` to forward fetch triggers.
⎔ Starting local server...
✘ [ERROR] service core:user:hogehoge: Uncaught Error: [unenv] whatwg-url.parseURL is not implemented yet!

    at null.<anonymous> (index.js:59:10) in createNotImplementedError
    at null.<anonymous> (index.js:64:27) in fn
    at null.<anonymous> (index.js:130676:34) in DocumentImpl
    at null.<anonymous> (index.js:131400:16) in exports.setup
    at null.<anonymous> (index.js:131350:22) in exports.create
    at null.<anonymous> (index.js:131353:31) in exports.createImpl
    at null.<anonymous> (index.js:134911:24) in exports.createImpl
    at null.<anonymous> (index.js:134914:37) in exports.createWrapper
    at null.<anonymous> (index.js:188912:37) in installOwnProperties
    at null.<anonymous> (index.js:188826:7) in exports.createWindow



✘ [ERROR] The Workers runtime failed to start. There is likely additional logging output above.
```

scheduler云々のエラーが出ているのはこの処理がCronトリガーで呼び出されるものだったためである。

**2025/06/21追記**

`wrangler.jsonc`に以下の記述することで回避可能との情報をいただいた。私は試してないけど載せておきます。Thank you @EqualMa for sharing the way!
```jsonc
{
"alias": { "whatwg-url": "whatwg-url" }
}
```

## Cronトリガーでちょっとハマった

CloudflareのCronトリガーは[Weekdayの部分の規定値が"1-7"になっており](https://developers.cloudflare.com/workers/configuration/cron-triggers/#supported-cron-expressions)、一般的には（というか私の理解がそうだったというだけなのだが）"0-7"が規定値だと思い込んでいたので、ちょっとハマった。Weekdayに規定外の値、たとえばここで言うと"0"を含めてDeployすると、エラーになってDeployが失敗する。ちなみに以下のようなエラーが出てくる:
```
...
X [ERROR] A request to the Cloudflare API failed
  invalid cron string [code: 10100]
...
```

厄介なのは、ローカルで`wrangler dev --test-scheduled`で試している分には、このエラーは出てこないことだ。これで`curl "http://localhost:8787/__scheduled?cron=0+12+*+*+0"`とかやってもこのエラーが起きず正常動作するので、何が原因なのか最初ちょっとよくわからなかった。つまりローカルで`--test-scheduled`つけて動かしたときの動作は、パラメータに渡した文字列をそのまま素通りでアプリに回してるだけで、Cron式のvalidationなんか一切していないんだと思われる。極論、`cron=aaa`とかでも動くんだろう（試してないけど）。ちなみにCloudflare WorkersのCron式のWeekdayは、"1"が日曜日、"2"が月曜日、…で"7"が土曜日である。"0"を許容するCron式の一般的な体系(?)では、"0"と"7"が日曜日で、"1"が月曜日、…、"6"が土曜日、となるので、一般的なCron式のWeekdayの体系とCloudflareのCron式は数値と曜日が1つずつズレていることになる。わかりづらい。なんで特殊な体系にしてしまったのだ？

##  指定したVersionのPrismaがインストールされない(のでDBに接続できずエラー)

これは（おそらく）Cloudflare WorkersとPrismaの複合的な問題（？）である。最初に発見したのは4/10 18:30JST頃のDeployだが、このときDeployのログに以下のメッセージを見つけた
```
npm warn exec The following package was not found and will be installed: prisma@6.6.0
```

このとき`package.json`に指定していたPrisma関連のパッケージはおおむね6.4.1を指定していた
```
    "@prisma/adapter-pg-worker": "6.4.1",
    "@prisma/client": "6.4.1",
    "@prisma/pg-worker": "6.4.1",
```

で、どうも6.6.0からPrismaClientの生成方法が変わってるらしく、6.4.1までなら以下の実装でいけたんだが
```typescript
import { Prisma, PrismaClient, } from "@prisma/client"
import { Pool, PoolConfig } from "@prisma/pg-worker";
import { PrismaPg } from "@prisma/adapter-pg-worker";
...
  const databaseUrl = String(process.env.DATABASE_URL);
  const schema = new URLSearchParams(new URL(databaseUrl).searchParams).get('schema');
  const pool = new Pool({
    connectionString: databaseUrl,
  });
  const adapter = new PrismaPg(pool, { schema: schema || 'public' });
  const prisma = new PrismaClient({
    adapter,
  });
```

6.6.0だとこれではコンパイルエラーになる(`adapter`の生成部分がエラーになる)ようで、以下に変更が必要になった
```typescript
import { Prisma, PrismaClient, } from "@prisma/client"
import { Pool, PoolConfig } from "@prisma/pg-worker";
import { PrismaPg } from "@prisma/adapter-pg-worker";
...
  const databaseUrl = String(process.env.DATABASE_URL);
  const schema = new URLSearchParams(new URL(databaseUrl).searchParams).get('schema');
  const config:PoolConfig = {
    connectionString: databaseUrl,
  };
  const adapter = new PrismaPg(config, {schema: schema || 'public'});
  const prisma = new PrismaClient({
    adapter,
  });
```

要するに`PrismaPg`の第一引数に`new Pool({connectionString: hogehoge})`を渡すか（～6.4.1）、`{connectionString: hogehoge}`を渡すか（6.6.0～）の違いである。この`{connectionString: hogehoge}`の部分が[PoolConfigというnode-pgのInterfaceになっていて](https://node-postgres.com/apis/pool)、いちいち`Pool`オブジェクト生成しなくてもよくなったということのようだ。が、こういうちょっとしたことでも破壊的変更はしないでほしかったというのが個人的にな正直な感想である。これのせいでDBにつながるワークロードはすべて全滅してしまい軽く阿鼻叫喚に陥った。

この件は、Prisma関連のパッケージのバージョンを6.4.1->6.6.0にアップデートして、コードを上記の内容に修正したうえでDeployし、とりあえず復旧させた。

一方、上のログメッセージの通りなら「6.4.1が見つからないから代わりに6.6.0インストールするね」ということらしいが、`npm view`やっても以下の通りちゃんとバージョン返ってくるので、こんなこと言われる筋合いはないはずなのである
```bash
$ npm view @prisma/adapter-pg-worker@6.4.1 version
6.4.1
```

かつ、不思議なのは、このログメッセージは、Prisma関連のパッケージを6.6.0にアップデートした後でも出てくることである。もう6.4.1は`package.json`には存在してないのにも関わらず、である。キャッシュかな？Cloudflare WorkersのDISCORDを検索してみたが同じことに悩んでる人はいなかった。ので、特殊な事情なのかもしれない。Cloudflare Workersがビルドのときに個別のパッケージレジストリ使ってるとか、そういうことなんだろうか？