Closed7

モノレポ環境でPrismaを利用する

アルクアルク

Prismaを利用することが多いがこれまではPrismaについてはこれ1つでProjectを作成していた。
でDB Migrationをするという役割を与えていた。

理由として一番大きな理由はコミット履歴。
何をいつ誰がという情報がコミット履歴に集約されるためDB更新履歴としていたから。

モノレポについてはまだ賛否両論あるがモノレポの環境化でのPrismaの扱いについて検討したくなった。

アルクアルク

こんな構成を考えてみる。

APIエリア、JOBエリアがあり、それぞれがDBへの接続をPrismaを利用する。
Prismaの定義が記述されているschema.prismaファイルを両方に配置してgenerateするのは効率が悪いのでモノレポ方式でうまく運用できないかを考えたい。

アルクアルク

方法としてはこれなんだろうなと思う。
1つ目 prisma clientモジュールをAPIエリアのProjectで参照できるようにパス解決する方法

アルクアルク

このあたりで一回 chatgpt 4oに要件を整理してもらう。
以下、chatgpt 4oの回答


以下の手順で「multi-project-prisma」をモノレポとして構築することを提案します。

構成概要

  1. プロジェクトA:

    • S3に格納されたデータをLambdaを経由して取得。
    • Prismaを用いてMySQLにデータを登録。
    • 関連リソース: S3、Lambda、Prisma、MySQL。
  2. プロジェクトB:

    • API GatewayからのリクエストをLambda経由で受け取り、Prismaを使用してMySQLからデータを取得。
    • 関連リソース: API Gateway、Lambda、Prisma、MySQL。
  3. プロジェクトC:

    • Prismaを用いてDBスキーマを定義し、AとBで共通使用する。
    • 関連リソース: Prisma。

モノレポ構成の提案

1. ディレクトリ構造

multi-project-prisma/
│
├── packages/
│   ├── project-a/           # S3 → Lambda → MySQL へのデータ登録機能
│   │   ├── src/
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── ...
│   ├── project-b/           # API Gateway → Lambda → MySQL へのデータ取得機能
│   │   ├── src/
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── ...
│   └── project-c/           # Prismaのスキーマ定義
│       ├── prisma/
│       │   ├── schema.prisma
│       ├── package.json
│       ├── tsconfig.json
│       └── ...
│
├── node_modules/
├── package.json
└── tsconfig.json
  • packages/project-apackages/project-bは、それぞれLambda関数を実装。
  • packages/project-cは、Prismaスキーマ定義を管理。

2. パッケージ管理と共有

multi-project-prismaのルートにpackage.jsonを配置し、モノレポとしてYarnやnpmのワークスペース機能を利用します。

package.jsonの設定例:

{
  "name": "multi-project-prisma",
  "private": true,
  "workspaces": [
    "packages/project-a",
    "packages/project-b",
    "packages/project-c"
  ]
}

3. 共通リソースの管理

プロジェクトCで定義したPrismaスキーマをAとBで利用します。project-c内に定義されたPrismaのスキーマは、ワークスペースを介して他のプロジェクトから参照されます。

  • project-aproject-bでは、project-cのPrismaスキーマをインポートして使用します。

4. デプロイ戦略

  • project-aproject-bは、それぞれ独立してデプロイ可能にするため、Serverless Frameworkを使用します。
  • Prismaは、共通のDB定義として、マイグレーション時にproject-cからコマンドを実行します。

次のステップ

  1. パッケージのセットアップ: 各プロジェクト内でyarnまたはnpmを使って依存関係をインストール。
  2. Prismaスキーマ定義: project-cでスキーマを作成し、各プロジェクトで利用できるように設定。
  3. Lambdaの実装: project-aproject-bで、それぞれのビジネスロジックをLambdaに実装。
  4. デプロイの設定: Serverless FrameworkやAWS CDKを使用して、AWS LambdaとAPI Gatewayの設定を行う。

この構成により、効率的なモノレポ管理が可能になり、リソースや処理の重複を最小限に抑えることができます。

アルクアルク

だいぶ優秀なアウトプットをもらったので、さらにchatgpt o1-previewに上記の結果をそのままインプットに利用してさらに具体的な構築手順を検討してもらう。

以下、結果


具体的なプロジェクト構築方法

あなたの提案を基に、具体的なプロジェクト構築手順を以下にまとめました。各プロジェクトのセットアップから、Prismaスキーマの共有、デプロイ方法まで詳しく説明します。

目次

  1. モノレポのセットアップ
  2. Project-C(Prismaスキーマ定義)の構築
  3. Project-AとProject-Bの構築
  4. Prismaスキーマの共有方法
  5. デプロイの設定
  6. 環境変数の管理
  7. 注意点
  8. まとめ

モノレポのセットアップ

1. ルートディレクトリの作成と初期化

mkdir multi-project-prisma
cd multi-project-prisma
npm init -y

2. パッケージマネージャーの選択

  • Yarnの場合: Yarn Workspacesを利用します。
  • npmの場合: npm v7以降のワークスペース機能を利用します。

この例では、npmを使用します。

3. package.jsonの設定

ルートのpackage.jsonにワークスペースの設定を追加します。

{
  "name": "multi-project-prisma",
  "private": true,
  "workspaces": [
    "packages/*"
  ]
}

Project-Cの構築

1. ディレクトリの作成と初期化

mkdir -p packages/project-c
cd packages/project-c
npm init -y

2. Prismaのインストールと初期化

npm install prisma @prisma/client
npx prisma init

3. schema.prismaの設定

prisma/schema.prismaを編集して、データモデルを定義します。

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider        = "prisma-client-js"
  output          = "../generated/project-c-client"
  package         = "project-c-client"
}

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}

4. マイグレーションの実行

npx prisma migrate dev --name init

5. パッケージのエクスポート設定

package.jsonに以下を追加します。

{
  "name": "project-c",
  "version": "1.0.0",
  "main": "index.js",
  "types": "index.d.ts",
  "files": [
    "generated/"
  ],
  "dependencies": {
    "@prisma/client": "^4.0.0"
  },
  "devDependencies": {
    "prisma": "^4.0.0"
  },
  "scripts": {
    "build": "prisma generate"
  }
}

Project-AとProject-Bの構築

1. ディレクトリの作成と初期化

mkdir -p packages/project-a
cd packages/project-a
npm init -y

同様にpackages/project-bも作成・初期化します。

2. 必要なパッケージのインストール

npm install @prisma/client aws-sdk
npm install --save-dev typescript ts-node

3. TypeScriptの設定

tsconfig.jsonを作成します。

{
  "compilerOptions": {
    "module": "commonjs",
    "target": "es2019",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true
  },
  "include": ["src"]
}

4. project-cの依存関係追加

package.jsonproject-cを追加します。

{
  "dependencies": {
    "project-c": "1.0.0",
    "@prisma/client": "^4.0.0",
    "aws-sdk": "^2.1000.0"
  }
}

5. ビジネスロジックの実装

Project-A (packages/project-a/src/index.ts)

import { PrismaClient } from 'project-c/generated/project-c-client';
import { S3 } from 'aws-sdk';

const prisma = new PrismaClient();
const s3 = new S3();

export const handler = async (event: any) => {
  // S3からデータ取得
  const data = await s3.getObject({
    Bucket: 'your-bucket',
    Key: 'your-key'
  }).promise();

  // データをパースしてデータベースに登録
  await prisma.user.create({
    data: {
      name: 'Example Name',
      email: 'example@example.com'
    }
  });

  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'Data inserted successfully' })
  };
};

Project-B (packages/project-b/src/index.ts)

import { PrismaClient } from 'project-c/generated/project-c-client';

const prisma = new PrismaClient();

export const handler = async (event: any) => {
  // データベースからデータ取得
  const users = await prisma.user.findMany();

  return {
    statusCode: 200,
    body: JSON.stringify(users)
  };
};

Prismaスキーマの共有方法

1. パッケージとしての共有

project-cで生成したPrisma Clientをproject-aproject-bから利用します。

  • project-cでPrisma Clientをビルドし、generatedディレクトリに出力。
  • 各プロジェクトでproject-cを依存関係としてインストール。

2. 参照の方法

project-aproject-bで、Prisma Clientを以下のようにインポートします。

import { PrismaClient } from 'project-c/generated/project-c-client';

デプロイの設定

1. Serverless Frameworkのインストール

各プロジェクトでServerless Frameworkと関連パッケージをインストールします。

npm install --save-dev serverless serverless-webpack webpack webpack-node-externals typescript ts-loader

2. serverless.ymlの設定

Project-A (packages/project-a/serverless.yml)

service: project-a

provider:
  name: aws
  runtime: nodejs14.x
  region: ap-northeast-1

functions:
  handler:
    handler: dist/index.handler
    events:
      - s3:
          bucket: your-bucket
          event: s3:ObjectCreated:*

plugins:
  - serverless-webpack

custom:
  webpack:
    webpackConfig: './webpack.config.js'
    includeModules: true

Project-B (packages/project-b/serverless.yml)

service: project-b

provider:
  name: aws
  runtime: nodejs14.x
  region: ap-northeast-1

functions:
  handler:
    handler: dist/index.handler
    events:
      - http:
          path: /users
          method: get

plugins:
  - serverless-webpack

custom:
  webpack:
    webpackConfig: './webpack.config.js'
    includeModules: true

3. webpack.config.jsの設定

各プロジェクトでwebpack.config.jsを作成します。

const path = require('path');
const slsw = require('serverless-webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: slsw.lib.entries,
  target: 'node',
  externals: [nodeExternals()],
  mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
  resolve: {
    extensions: ['.js', '.ts']
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, 'dist'),
    filename: '[name].js'
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader'
      }
    ]
  }
};

4. デプロイの実行

各プロジェクトで以下を実行します。

npx serverless deploy

環境変数の管理

1. .envファイルの使用

各プロジェクトのルートに.envファイルを作成し、データベース接続情報などを記載します。

DATABASE_URL=mysql://user:password@host:port/database

2. serverless.ymlでの環境変数設定

provider:
  environment:
    DATABASE_URL: ${env:DATABASE_URL}

3. dotenvのインストール

npm install dotenv

4. コード内での環境変数の読み込み

import { config } from 'dotenv';
config();

注意点

  1. Prisma Clientの再生成: スキーマが変更された場合、project-cprisma generateを再実行する必要があります。
  2. バージョン管理: すべてのプロジェクトで@prisma/clientprismaのバージョンを一致させます。
  3. 依存関係のループに注意: モノレポ内で依存関係のループが発生しないようにします。

まとめ

以上が、あなたの提案に基づいた具体的なプロジェクト構築方法です。モノレポを活用し、Prismaスキーマを共通化することで、開発効率と保守性を高めることができます。

  • モノレポの利点: 依存関係の管理が容易になり、コードの再利用性が向上します。
  • Prismaの活用: 共通のデータモデルを使用することで、データ整合性を保ちます。
  • Serverless Frameworkの利用: 簡単にLambda関数をデプロイでき、インフラストラクチャの管理が楽になります。

何か不明点や追加の質問があれば、お気軽にお知らせください。

アルクアルク

かなり具体的な手順を生成することができた。
webpackとかオワコンのモジュールを提案しているのでそこは調整が必要。

アルクアルク

schema.prismaを再実行するタイミングについて自動化含めて chatgpt o1-previewに検討してもらう。
ほぼ、完璧な回答じゃないかなと思う。


Prisma Clientの再生成を自動化することで、スキーマ変更時に手動でprisma generateを実行する必要を無くし、開発フローを効率化することが可能です。これを実現するために、いくつかの方法を提案します。

再生成の自動化方法

1. Git Hooksを利用する

Huskyを使って、スキーマ変更時に自動的にprisma generateを実行するGitフックを設定します。

手順:

  1. Huskylint-stagedのインストール
npm install husky lint-staged --save-dev
  1. Huskyのセットアップ
npx husky install
  1. package.jsonにHuskyの設定を追加
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "packages/project-c/prisma/schema.prisma": [
      "npx prisma generate --schema=packages/project-c/prisma/schema.prisma"
    ]
  }
}

この設定では、schema.prismaが変更された場合に自動でprisma generateが実行されます。

2. CI/CDでの自動実行

CI/CDパイプラインにprisma generateを組み込むことで、デプロイ時に自動で最新のPrisma Clientが生成されるようにします。

手順:

  1. GitHub Actionsの設定
    prisma generateを自動で実行するGitHub Actionsのワークフローを設定します。
  • .github/workflows/ci.ymlに以下の設定を追加:
name: CI

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  prisma_generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Set up Node.js
        uses: actions/setup-node@v2
        with:
          node-version: '16'
      - run: npm install
      - run: npx prisma generate --schema=packages/project-c/prisma/schema.prisma
      - run: npm test

この設定により、コードがmainブランチにプッシュされたときやプルリクエスト時に、Prisma Clientが自動生成されます。

3. postinstallスクリプトで自動化

package.jsonpostinstallスクリプトを利用して、依存関係のインストール後に自動的にPrisma Clientを生成する方法です。

手順:

  1. package.jsonpostinstallスクリプトを追加
  • packages/project-c/package.jsonに以下を追加:
{
  "scripts": {
    "postinstall": "prisma generate --schema=prisma/schema.prisma"
  }
}

これにより、npm installyarn installが実行された際に、自動的にPrisma Clientが生成されます。

4. 開発時のウォッチモード

Prismaはprisma generateを自動実行するウォッチモードも提供しています。これにより、スキーマが変更されるたびに自動でPrisma Clientが再生成されます。

手順:

  1. ウォッチモードの設定
npx prisma generate --watch

これにより、開発中にスキーマが変更されるたびにPrisma Clientが再生成されるようになります。

5. Makefileを利用する

Makefileを利用して、ビルドプロセスにPrisma Clientの再生成を含めることができます。makeコマンドで、ビルドやテストなどと一緒にprisma generateを実行できます。

手順:

  1. Makefileの作成
  • プロジェクトルートにMakefileを作成:
build:
	npx prisma generate --schema=packages/project-c/prisma/schema.prisma
	npm run build
  1. 実行方法
make build

この方法では、ビルドの際にPrisma Clientも自動で生成されます。


結論

Prisma Clientの再生成を自動化するためには、開発フローに合った方法を選ぶことが重要です。

  • Git Hooks: スキーマ変更のコミット時に自動で再生成。
  • CI/CD: デプロイ時に必ず再生成を行う。
  • postinstallスクリプト: 依存関係のインストール後に再生成。
  • ウォッチモード: 開発中のスキーマ変更を即座に反映。
  • Makefile: ビルドプロセスにPrismaの再生成を統合。

これらの方法を組み合わせることで、スキーマ変更の際に手動で再生成を行う必要をなくし、開発効率が向上します。

どの方法を採用するかは、プロジェクトの規模やワークフローによって選択するのが良いでしょう。

このスクラップは2ヶ月前にクローズされました