Hono+React+Typescript+Prisma+Dockerで環境構築

## はじめに
環境構築を Docker でするぞ！と思ったら思いの外詰まったのでメモを残しておきます。
初心者の備忘録的なメモです。

## ファイル構成
```
.
├── compose.yaml
├── db.Dockerfile
├── Dockerfile
├── frontend/
│   ├── package.json
│   ├── tsconfig.json
│   └── ... (React + Vite関連ファイル)
├── backend/
│   ├── package.json
│   ├── tsconfig.json
│   ├── prisma/
│   │   ├── schema.prisma
│   │   └── migrations/
│   └── src/
│       └── ... (Hono関連ファイル)
├── package.json
└── yarn.lock
 ```

## 手順
### ①Docker関連のファイルを作成する
```compose.yaml
services:
  app:
    build: .
    tty: true
    ports:
      - 3000:3000 #Hono用のポート
      - 5173:5173 #React用のポート
    volumes:
      - .:/app
    environment:
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/app
    depends_on:
      - db
  db:
    build:
      context: "."
      dockerfile: "db.Dockerfile"
    ports:
      - "5432:5432"
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
      - POSTGRES_DB=app

volumes:
  pgdata:
 ```

```Dockerfile.
FROM node:22-slim

RUN apt-get update && \
    apt-get install -y locales git procps vim tmux curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

RUN corepack enable

RUN locale-gen ja_JP.UTF-8 && \
    localedef -f UTF-8 -i ja_JP ja_JP
ENV LANG=ja_JP.UTF-8
ENV TZ=Asia/Tokyo

WORKDIR /app

CMD [ "yarn", "dev" ]
```
```db.Docker
FROM postgres:16.1
RUN apt-get update && \
    apt-get install -y curl
RUN locale-gen ja_JP.UTF-8
RUN localedef -f UTF-8 -i ja_JP ja_JP
USER postgres
ENV LANG=ja_JP.UTF-8
ENV TZ=Asia/Tokyo
```
### ②コンテナの起動を行う
```
$ docker compose up -d --build
```

### ③yarn の設定を変更する
package.json を作成する前に```.yarnrc.yml```ファイルを作成します。

```.yarnrc.yml
nodeLinker: node-modules
```
これが非常に重要です。
yarn のバージョンによっては、 node_modules が作成されないことが原因となり、VSCode が型定義を認識しないエラーが発生します。
原因となる Yarn の Plug'n'Play（PnP）モードを無効化することがこのファイルの目的です。

### ④package.json を作成する
コンテナの作成ができたら、 package.json ファイルの作成と typescript の導入を行なっていきましょう。
```
$ docker compose exec app bash
$ yarn init
$ yarn add typescript
```
この際```Corepack is about to download ...```と質問される場合は```Y``` (または ```y```) を入力してEnterキーを押しましょう。
これにより必要なファイルが作成されます。
また、package.jsonの一部記述を変更します。
```package.json
// 省略
  "private": true,
  "workspaces": [
    "frontend",
    "backend"
  ],
//省略
  ```
- ```"private": true```:  monorepo のルートパッケージは npm に公開するものではないため、通常 true にします。
- ```"workspaces"```: どのディレクトリがワークスペースであるかをyarnに伝えます。
今回はルートディレクトリ直下に作成した```frontend```、```backend```を指定します。
- 他にも必要な設定がある場合は適宜記述を追加してください。


### ⑤Vite + Reactの導入
では、先ほどインストールしたyarnを使用して frontend ディレクトリ(React)を作成していきます。
今回は vite を利用するため、以下のコマンドでアプリの作成を行います。
```
yarn create vite frontend --template react-ts
```
これで必要なファイルの作成が行えました。
Docker環境を利用するため、　vite にコンテナ外部からもアクセスできるようにオプションを追加しましょう。
```frontend/package.json
  "scripts": {
    "dev": "vite --host", ##--hostオプションを追加する
```
実際に起動して、アプリが動いているかを確かめてみましょう
```
$ cd frontend
$ yarn
$ yarn dev
```
[http://localhost:5173/](http://localhost:5173/)にアクセスし、無事に Vite + React の画面がブラウザに表示されれば成功です。
### ⑥Hono の導入
backend ディレクトリの作成も同様に行なっていきましょう。
```
$ cd ../ #ルートディレクトリに戻る
$ yarn create hono backend
```
オプションは作成したい内容に合わせて適宜選択してください。
frontend ディレクトリと同様に backend ディレクトリにも設定をしていきましょう。
まずは package.json の設定をしていきましょう。
```backend/package.json
{
  "name": "backend",
  "version": "0.1.0", #追加
  "private": true, #追加
  "license": "MIT", #追加
  "type": "module",
  "scripts": {
    "dev": "tsx watch src/index.ts", #追加
    ...
  },
    ...
}
```
Yarn を用いてのパッケージをインストールに必要な情報と、Hono の開発サーバーを起動するための dev スクリプトを追加しました。
これで backend ディレクトリで yarn コマンドが使用できるようになります。
次に Typesctipt と hono/node-server の導入もしていきましょう。
```
$ cd backend
$ yarn
$ yarn add -D tsx @types/node typescript
$ yarn add @hono/node-server
```
ここまでできたらまた起動ができるかを確認しましょう。
```backend/src/index.ts``` に以下を記述します。
※今回は Hono の作成時に aws_lambda オプションを使用していますが、ご自身の設定に応じて書き換えてください。
```index.ts
import { Hono } from 'hono'
import { handle } from 'hono/aws-lambda'
import { serve } from '@hono/node-server';

const app = new Hono();

app.get('/', (c) => {
  return c.text('Hello Hono from backend!')
})

app.get('/api/message', (c) => {
  return c.json({ message: 'This is a message from Hono backend API' })
})

export const handler = handle(app)

const port = 3000
console.log(`Backend server is running on http://localhost:${port}`)

serve({
  fetch: app.fetch,
  port: port
})
```

以下のコマンドを使用して、[http://localhost:3000/](http://localhost:3000/)にアクセスできれば成功です。
```
$ yarn dev
```
### ⑦ Prisma の導入
以下のコマンドを backend ディレクトリで実行して、Prisma の導入と Prisma プロジェクトの初期化をしていきましょう。
```
$ yarn add -D prisma
$ npx prisma init
```

このコマンドを実行すると、以下のものが作成されます。

- ```prisma/schema.prisma```: データモデルやデータベース接続情報を定義するファイル。
- ```.env```: データベース接続URLなどの環境変数を記述するファイル。

あとはご自身の環境に合わせて```.env```ファイルにデータベースの接続設定と、```prisma/schema.prisma```にデータモデルの定義の定義を行なってください。

## 何で詰まったのか
### node_modules の設定
初回の環境構築で詰まった原因の80%がこれです。
tsconfig の記述の見直しを何度もさせられました。
Yarn のバージョンにまで気が回らなかったのと、PnP 関連のファイルをなんとなく流してしまったのは反省。

### Docker での環境構築に慣れていなかった
workspaces の設定を忘れたり、 --host オプションをつけ忘れたりと Docker で monorepo の開発を行う前提知識が欠けていたことを実感しました。
実際動きはするもののこれが最適かはわからない。
もう少し勉強が必要。