TL; DR
普通にデプロイしてしまうとprisma generate
をしていないせいでエラーが出る。解決策は以下の2つ。
案1. postinstallスクリプトに登録する
"scripts": {
// 中略
"postinstall": "prisma generate"
},
"dependencies": {
"prisma": "<version>" // devDependenciesではなく、dependenciesに入れる
}
案2. prisma generate の出力先を変更する
generator client {
provider = "prisma-client-js"
// ここを追加するだけ
output = "../src/generated/client"
}
// 生成先のパスを参照する
import { PrismaClient } from './generated/client'
概要
- Node.jsでバックエンドを書いている
- ORMにはPrismaを使っている
- インフラは Google App Engine (以下、GAE)を使う
以上の条件のとき、問題が発生したので、その解決策を残す。
問題1 prisma generate しないとクライアントが使えない
prisma のクライアントを使うときは、事前にprisma generate
を実行する必要がある。GAE ではインスタンス開始時に npm scripts のstart
に設定したコマンドが実行されるので、start
を以下のように変更した。
"scripts": {
"start": "prisma generate && node dist",
}
問題2 GAEのファイルは read only
しかし、GAEのファイルは read only であるため、prisma generate
が失敗してしまった。
Error: EROFS: read-only file system, unlink '/workspace/node_modules/.prisma/client/index.js'
解決策
案1
npm scripts のpostinstall
に指定したコマンドはnpm install
もしくはyarn install
が実行された後に続けて実行される。ここにprisma generate
を設定する。
ただし、GAEではデプロイ時にdependencies
のみがインストールされ、devDependencies
がインストールされないことに注意したい。primsa
ライブラリは基本的にdevDependencies
のほうにインストールするが、この解決策を取る場合は、dependencies
に移動する必要がある。
"scripts": {
// 中略
"postinstall": "prisma generate"
},
"dependencies": {
"prisma": "<version>" // devDependenciesではなく、dependenciesに入れる
}
かんたんに設定できるが、prismaライブラリの分、node_modulesが肥大化する。スピンアップが遅くなり、コールドスタートが長くなる可能性がある。
※一応、本番環境でのみyarn remove prisma
を走らせることで回避できそう。
#!/bin/bash
yarn prisma generate
if [[ $NODE_ENV = 'production' ]]; then
yarn remove prisma
fi
"postinstall": "bash scripts/prisma_init.sh"
案2
prisma generate
の出力先はデフォルトだと、node_modules内だが、GAEはデプロイ時にインスタンス側でnpm install
が走り、その後は read only になるため都合が悪い。つまり、出力先を node_modules外に変更できれば、解決する。
公式ドキュメントを読んだところ、↓を見つけた。
https://www.prisma.io/docs/concepts/components/prisma-client/working-with-prismaclient/generating-prisma-client#using-a-custom-output-path
以下のようにすれば解決した。
generator client {
provider = "prisma-client-js"
// ここを追加
output = "../src/generated/client"
}
PrismaClient
をインポートしているコードも書き換えた。
import { PrismaClient } from './generated/client'
この方法のメリットはprisma
をdependenciesに入れなくてすむので、サイズが軽くなり、コールドスタートが軽減されること。(ただし、ベンチマークを測ったわけではない)
デメリットはprisma generate
を実行した環境がWindowsやMacだと、そのOS用の prisma バイナリが生成され、これがGAE環境では実行できないこと。
最後に
GAE はインフラにかかる工数を大幅に削減できるメリットがあるが、自由度は低い。
ただ、その低い自由度の中でも解決策は案外見つかる。