Prismaとモノレポ
この記事は、npmのworkspace機能を使ってモノレポ且つPrismaの型・スキーマを共有する構成を作るチュートリアルです。今回Turborepoは使いません。 元々workspaceは、yarnやpnpmに存在していた機能で、npmが倣って実装した経緯があるため、以下はyarn、pnpmに置き換えても問題ないかと思います。
参考
2023年現在、Prismaのスキーマを共有する方法を検索すると、下記の記事と、この記事内のコメントにたどり着くかと思います。今回まとめるのはこのコメントで提示されている方法の具体的な実装です。
npm workspaceの使い方はこちら。
1. 構成
下記のpackages/database/
にPrismaをインストールし、全てのアプリケーションでスキーマ(PrismaClient)を共有することを目的とします。
project/
├ apps/
│ ├ app1/
│ └ ...
└ packages/
└ database/
app1
は、frontend
, backend
などと置き換えてもらって構いません。
2. プロジェクトの初期化
$ cd /path/to/project
$ npm init -y
3. Prismaのインストール
ワークスペースの作成
まず、database
というワークスペースを用意します。下記のコマンドで、packages/database/
ディレクトリと、ディレクトリ内のpackage.json
が作成されます。
$ npm -w packages/database init -y
また、ルートのnode_modules/
には、database
ワークスペースへのシンボリックリンクが自動生成されます。
必要なパッケージのインストール
database
ワークスペースにPrismaをインストールしていきましょう。ワークスペース内でnpmコマンドを使うには、基本的にnpm -w {workspace} {command}
と記述します。npxも同様に使えます。
$ npm -w database i @prisma/client
$ npm -w database i prisma -D
$ npx -w database prisma init
npx prisma init
コマンドで、下記ファイルの雛形が用意されます。
packages/database/.env
packages/database/prisma/schema.prisma
スキーマを記述
SQLite3のデータベースを用意してみます。適宜読み替えてください。
DATABASE_URL="file:/path/to/database.sqlite"
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model Record {
id Int @id @default(autoincrement())
title String
content String
}
マイグレーションとPrismaClientの生成
$ npx -w database prisma migrate dev
マイグレーションが必要ない場合はこちら。
$ npx -w database prisma generate
テストデータの用意
Prismaには、Prisma Studioという簡易的なビジュアルエディタがあるので、簡単にテストデータの追加・削除を行うことができます。
$ npx -w database prisma studio
4. アプリケーションでPrismaを使う
TypeScriptの初期設定
TypeScriptはモノレポ全体で共通の設定で使いたいため、各ワークスペースではなくプロジェクト自体に設定します。tsconfig.json
については、適宜変更してください。
$ npm i -D @types/node ts-node typescript
$ npx tsc --init
ワークスペースごとにTypeScriptを設定したい場合は、これまでと同様に-w
オプションを使います。
$ npm -w app1 i -D @types/node ts-node typescript
$ npx -w app1 tsc --init
ワークスペースの作成
database
と同様にワークスペースを用意します。
$ npm init -y -w apps/app1
実際にPrismaClientを使ってみる
作成したワークスペースapps/app1
に、テスト用のスクリプトを用意します。
import { PrismaClient } from "@prisma/client"
main()
async function main() {
const prisma = new PrismaClient()
const records = await prisma.record.findMany({})
console.log(records)
}
コンパイル
下記を実行し、apps/app1/index.js
が生成されたら成功です。
$ npx -w app1 tsc
実行
生成されたファイルを実行し、Prisma Studioで入力したテストデータが表示されたら成功です。
$ node apps/app1/index.js
[
{ id: 1, title: 'テスト1', content: 'テスト' },
{ id: 2, title: 'テスト2', content: 'テスト' }
]
5. その他のアプリケーションを追加する
ワークスペースからのPrismaClientのインポートについては、上記で見たように、階層を特に気にせずに読み込むことができます。
import { PrismaClient } from "@prisma/client"
npm create vite
各種フレームワークをセットアップする場合、Viteなどのツールを使うかと思います。
$ npm -w apps/app2 init -y
$ npm -w apps/app2 create vite@latest
✔ Project name: … .
...
この時Project name
を指定すると、ワークスペース下にもう一つ階層ができてしまうので、.
と入力しましょう。npm create
コマンド時に指定することもできます。
$ npm -w apps/app2 create vite@latest .
npm initは必要?
なくても問題なさそうです。
node_modules
にシンボリックリンクが貼られるかどうかの違いがあります。
npm -w apps2 create viteじゃ駄目?
これまでのコマンドではディレクトリを省略できましたが、createではワークスペースのパスを正しく入力する必要があるみたいです。
他のセットアップツールも、使い方は基本的に同じです。
$ npm -w apps/app2 create svelte@latest
npm init以外のワークスペースの追加方法
開発中に、特定のディレクトリをワークスペースとして追加したい場合は、ルートのpackage.json
を編集する必要があります。workspaces
配列にパスを追加しましょう。
{
...
"workspaces": [
"apps/app1"
]
}
終わりに
ワークスペース機能を触ってみて、慣れれば全く難しいものではないことが分かりました。Prismaだけでなく独自の型やユーティリティもモノレポ間で共有できて、各アプリケーションの連携が簡単になるので、選択肢の一つとして覚えておくことをオススメします。
Discussion