🐷

prisma/adapter-d1はフレームワークと組み合わせて使えるのか?

2024/03/19に公開

Wasmバイナリを含むバンドルサイズについて

@prisma/adapter-d1はネイティブコードだったlibquery_engineがWasmバイナリになっています

Cloudflare Workersはup to 1 MB on the Workers Free planの制限があるので、Wasmバイナリがどの程度のサイズを占めているのかが気になり調べました

raw codeに近づけるためにJavaScriptでPrismaClientを呼び出す最小のWorkerを作ってみます

src/index.js
import { PrismaClient } from '@prisma/client'
import { PrismaD1 } from '@prisma/adapter-d1'

export default {
  async fetch(request, env, ctx) {
    const adapter = new PrismaD1(env.MY_DATABASE)
    const prisma = new PrismaClient({ adapter })

    const usersCount = await prisma.user.count()

    return new Response(`There are ${usersCount} users in the database`)
  },
}
❯ npx wrangler deploy --outdir bundled/ --dry-run
--dry-run: exiting now.
Total Upload: 2181.44 KiB / gzip: 815.33 KiB

gzip: 815.33 KiBになりました。gzip圧縮されたサイズで最大1MB制限であることはドキュメントに書かれていますので、8割ぐらいはPrisma Clientが占めるのだなと分かります

以下が内訳です

du -sh bundled/
3.0M    bundled/

❯ tree bundled 
bundled
├── 5343c5664d9b411cd10438666dc2381e8c450cda-query_engine_bg.wasm
├── README.md
├── index.js
└── index.js.map

❯ du -sh bundled/*
2.5M    bundled/5343c5664d9b411cd10438666dc2381e8c450cda-query_engine_bg.wasm
4.0K    bundled/README.md
208K    bundled/index.js
328K    bundled/index.js.map

これをgzip圧縮してみると同サイズになりました

find bundled -type f \( -name "*.js" -o -name "*.wasm" \) -print0 | tar -czvf bundled.tar.gz --null -T -
a bundled/5343c5664d9b411cd10438666dc2381e8c450cda-query_engine_bg.wasm
a bundled/index.js

❯ du -sh bundled.tar.gz
816K    bundled.tar.gz

なので、1000k-816K=184kbが開発者が使えるバンドルサイズになります

Next.js

Next.jsは@cloudflare/next-on-pagesでWorkers形式にビルドします

以下のコードを用意しました

app/page.tsx
import { getRequestContext } from '@cloudflare/next-on-pages'

import { PrismaClient } from '@prisma/client'
import { PrismaD1 } from '@prisma/adapter-d1'

export const runtime = 'edge'

export default async function Home() {
  const adapter = new PrismaD1(getRequestContext().env.MY_DATABASE)
  const prisma = new PrismaClient({ adapter })

  const todos = await prisma.todo.findMany()
  
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <div className="z-10 max-w-5xl w-full items-center justify-between font-mono text-sm lg:flex">
        <pre>
          {JSON.stringify(todos, null, 2)}
        </pre>
      </div>
    </main>
  );
}
❯ npx next build
❯ npx @cloudflare/next-on-pages

❯ find .vercel/output/static/_worker.js -type f \( -name "*.js" -o -name "*.wasm" \) -print0 | tar -czvf bundled.tar.gz --null -T -
a .vercel/output/static/_worker.js/index.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/cache/cache-api.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/cache/kv.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/cache/adaptor.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/manifest/27d10e462fba646daaa29468a0656e12.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/manifest/__RSC_SERVER_MANIFEST.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/wasm/wasm_5343c5664d9b411cd10438666dc2381e8c450cda.wasm
a .vercel/output/static/_worker.js/__next-on-pages-dist__/webpack/44bff480f105853cb03b9b061f5738d6.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/webpack/8090d4b5871bbe46edd85a7368aa285a.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/functions/_not-found.func.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/functions/index.func.js
a .vercel/output/static/_worker.js/__next-on-pages-dist__/functions/api/hello.func.js

❯ du -sh bundled.tar.gz
1.0M    bundled.tar.gz

ギリだ……

試しにデプロイしてみるも、デプロイコマンド自体は成功するも、Status: Failedの結果になり、反映が完了しません

Hono(React SPA)

HonoでAPI付き雑React SPA最小でyusukebeさんが解説されている構成ですが、これは余裕でいけました(Workers側にSPAのSSRを含めてないのでそれはそう)

❯ npx wrangler deploy --compatibility-flag nodejs_compat  --dry-run --outdir bundled dist/_worker.js
 -dry-run: exiting now.
Total Upload: 2275.50 KiB / gzip: 837.49 KiB

❯ find ./bundled -type f \( -name "*js" -o -name "*.wasm" \) -print0 | tar -czvf bundled.tar.gz --null -T - 
a ./bundled/5343c5664d9b411cd10438666dc2381e8c450cda-query_engine_bg.wasm
a ./bundled/_worker.js

❯ du -sh bundled.tar.gz
840K    bundled.tar.gz

D1への読み書きを含めたデモ: https://prisma-d1.pages.dev/

ソースコード: https://gist.github.com/laiso/fe4ddd71f3f041db47daddc35b31c5c2

Remix

Prisma driver adapter for Cloudflare D1をRemixに組み込むによるとnext-on-pagesと同じくデプロイしても動作しない状態になるようです

有料版では動作するのでサイズの問題で刺さっているのでは? という予測ができますね

NuxtやSvelteKitは?

当方未確認なのでご存知の方は教えてください

Discussion