diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..53a8817 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,37 @@ +{ + "name": "Pixel Paint War Dev", + "dockerComposeFile": "../docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspace", + + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "20", + "pnpm": "latest" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "EditorConfig.EditorConfig", + "ms-vscode.hexeditor", + "GitHub.copilot" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + } + } + }, + + // 【修正箇所】 + // 1. sudo chown ... : node_modules の所有権を node ユーザーに強制変更 + // 2. pnpm install : その後、安全にインストールを実行 + // 3. build : 最後にビルド + "postCreateCommand": "sudo chown -R node:node /workspace/node_modules && pnpm install && pnpm --filter @repo/shared build", + + "remoteUser": "node" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d47710f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,54 @@ +# ================================================================ +# Stage 1: Builder (ビルド用の環境) +# ================================================================ +FROM node:20-slim AS builder + +# pnpmの準備 +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +WORKDIR /app + +# 1. 依存関係の定義ファイルをコピー +COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./ +COPY apps/server/package.json ./apps/server/ +COPY packages/shared/package.json ./packages/shared/ + +# 2. 依存関係をインストール +RUN pnpm install --frozen-lockfile + +# 3. ソースコードをコピー +COPY packages/shared ./packages/shared +COPY apps/server ./apps/server + +# 4. ビルド(共通ライブラリ -> サーバーの順) +RUN pnpm --filter @repo/shared build +RUN pnpm --filter server build + +# 5. 開発用ライブラリを削除(本番に必要なものだけ残す) +ENV CI=true +RUN pnpm prune --prod + +# ================================================================ +# Stage 2: Runner (実行専用の軽量環境) +# ================================================================ +FROM node:20-slim AS runner + +WORKDIR /app + +# Builderステージから、動かすのに必要なファイルだけをコピー +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/apps/server/node_modules ./apps/server/node_modules +COPY --from=builder /app/apps/server/dist ./apps/server/dist +COPY --from=builder /app/apps/server/package.json ./apps/server/ +COPY --from=builder /app/packages/shared/dist ./packages/shared/dist +COPY --from=builder /app/packages/shared/package.json ./packages/shared/ + +# 実行環境の設定 +ENV NODE_ENV=production +USER node + +# サーバーを起動 +WORKDIR /app/apps/server +CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/apps/client/vite.config.ts b/apps/client/vite.config.ts index 407cb13..dfdf5f7 100644 --- a/apps/client/vite.config.ts +++ b/apps/client/vite.config.ts @@ -1,14 +1,30 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' +// src/index.ts +import { Server } from "socket.io"; +import { createServer } from "http"; // Node.js標準 of HTTPサーバー +import { GameManager } from "./managers/GameManager.js"; +import { SocketManager } from "./network/SocketManager.js"; -export default defineConfig({ - plugins: [react()], - server: { - proxy: { - '/socket.io': { - target: 'http://localhost:3000', - ws: true, - }, - }, +const PORT = 3000; + +// HTTPサーバーとSocket.ioサーバーの作成 +const httpServer = createServer(); +const io = new Server(httpServer, { + cors: { + origin: "*", // 開発用:どこからでも許可 + methods: ["GET", "POST"] }, -}) \ No newline at end of file +}); + +// ゲームマネージャーと通信マネージャーの起動 +const gameManager = new GameManager(); +const socketManager = new SocketManager(io, gameManager); + +socketManager.initialize(); + +// サーバー起動 +httpServer.listen(PORT, () => { + console.log(` + 🚀 Server is running on port ${PORT} + waiting for connections... + `); +}); \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index 210e48d..632e620 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -2,9 +2,11 @@ "name": "server", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "dist/index.js", "scripts": { "dev": "tsx watch src/index.ts", + "build": "tsc", + "start": "node dist/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index bc29276..407cb13 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -1,30 +1,14 @@ -// src/index.ts -import { Server } from "socket.io"; -import { createServer } from "http"; // Node.js標準のHTTPサーバー -import { GameManager } from "./managers/GameManager.js"; -import { SocketManager } from "./network/SocketManager.js"; +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' -const PORT = 3000; - -// HTTPサーバーとSocket.ioサーバーの作成 -const httpServer = createServer(); -const io = new Server(httpServer, { - cors: { - origin: "*", // 開発用:どこからでも許可 - methods: ["GET", "POST"] +export default defineConfig({ + plugins: [react()], + server: { + proxy: { + '/socket.io': { + target: 'http://localhost:3000', + ws: true, + }, + }, }, -}); - -// ゲームマネージャーと通信マネージャーの起動 -const gameManager = new GameManager(); -const socketManager = new SocketManager(io, gameManager); - -socketManager.initialize(); - -// サーバー起動 -httpServer.listen(PORT, () => { - console.log(` - 🚀 Server is running on port ${PORT} - waiting for connections... - `); -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json index 5f884bd..1ed84b5 100644 --- a/apps/server/tsconfig.json +++ b/apps/server/tsconfig.json @@ -5,15 +5,14 @@ "moduleResolution": "NodeNext", "lib": ["ES2022"], "strict": true, - "noEmit": true, + "outDir": "./dist", + "rootDir": "./src", "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - "paths": { - "@repo/shared": ["../../packages/shared/src/index.ts"] - } + "baseUrl": "." + /* "paths" は削除します(pnpm のワークスペース解決を使用するため) */ }, "include": ["src/**/*"], - "exclude": ["node_modules"] -} \ No newline at end of file + "exclude": ["node_modules", "dist"] +} diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..923905c --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,11 @@ +services: + game-server: + build: + context: . + dockerfile: Dockerfile + container_name: pixel-paint-server-prod + restart: unless-stopped + ports: + - "3001:3000" + environment: + - NODE_ENV=production diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9653f7d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.8" + +services: + app: + container_name: pixel-paint-war-dev + # 開発用イメージ: Node.js v20 (定義書準拠) + image: mcr.microsoft.com/devcontainers/typescript-node:20 + + # 永続化とボリュームマウント + volumes: + # カレントディレクトリをコンテナ内の /workspace にマウント + - .:/workspace:cached + + # 【重要】ここを追加してください + # コンテナ内の node_modules をホスト側と切り離して高速化・安定化させる設定 + - node_modules:/workspace/node_modules + + # コマンドの上書き (コンテナを常時起動させる) + command: sleep infinity + + # ネットワーク設定 + # Client(5173) と Server(3000) のポートを開放 + ports: + - "5173:5173" + - "3000:3000" + + # 環境変数 + environment: + - NODE_ENV=development + # pnpmのストアをローカルと分離して高速化したい場合は設定推奨(今回はシンプルにします) + + # ユーザー権限 (Nodeイメージ推奨のユーザー) + user: node + +volumes: + node_modules: diff --git "a/docs/01_Env/ENV_01_\347\222\260\345\242\203\346\247\213\347\257\211\343\203\273\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.txt" "b/docs/01_Env/ENV_01_\347\222\260\345\242\203\346\247\213\347\257\211\343\203\273\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.txt" index ea61c96..ee0305c 100644 --- "a/docs/01_Env/ENV_01_\347\222\260\345\242\203\346\247\213\347\257\211\343\203\273\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.txt" +++ "b/docs/01_Env/ENV_01_\347\222\260\345\242\203\346\247\213\347\257\211\343\203\273\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.txt" @@ -32,6 +32,9 @@ 2-1. 構成一覧 root/ + ├── .devcontainer/ # Dev Containers設定 + ├── docker-compose.yml # 開発用コンテナ構成定義 + ├── Dockerfile # 本番サーバー・デプロイ用定義 (Multi-stage) ├── package.json # pnpm workspace 定義 ├── pnpm-workspace.yaml # ワークスペース設定 ├── .npmrc # 依存関係解決の設定 @@ -83,8 +86,8 @@ ・Package Manager: pnpm ・Build Tool: tsup (高速で軽量なTypeScriptバンドラ) ・Serialization: Custom Binary (Standard DataView API) - - 採用理由: ライブラリ依存をなくし、仕様書要件(30KB/s以下)を満たす最適化を行うため。 - - 用途: 座標データ、入力情報の圧縮通信。 + - 採用理由: ライブラリ依存をなくし,仕様書要件(30KB/s以下)を満たす最適化を行うため. + - 用途: 座標データ,入力情報の圧縮通信. 3-2. フロントエンド (Client) ・Build Tool: Vite @@ -109,28 +112,59 @@ ・Test: Vitest (共通ロジックの単体テスト用) ・AI Assistant: GitHub Copilot Pro, Gemini Pro +3-5. インフラ・コンテナ技術 (Infrastructure) + ・Containerization: Docker + - 採用理由: 開発環境(Dev Containers)と本番環境の差異を排除するため. + ・Orchestration: + - Dev: Docker Compose (ボリュームマウントによるホットリロード) + - Prod: Docker Compose (再起動ポリシーとポート開放のみの最小構成) + ・Deployment Image: Multi-stage Build (Node.js Slim) + - ビルド戦略: + 1. Builderステージ: 全依存をインストールし,TypeScript (Shared -> Server) をコンパイル. + 2. Prune: `pnpm prune --prod` により開発依存を削除. + 3. Copy: pnpmの仕様(シンボリックリンク)に対応するため,`node_modules` を明示的にコピーする. + 4. Runnerステージ: 必要な `dist` と `node_modules` のみをコピーし,イメージサイズを最小化する. + 4. 開発マシンの前提条件 (Prerequisites) ------------------------------------------------------------------------ -以下のツールがインストールされていること. +本プロジェクトは Docker (Dev Containers) による開発環境統一を推奨する. +これにより、ホストOS(Windows/Mac)の環境を汚さずに構築が可能となる。 - 1. Node.js (v20.x LTS) - $ node -v +4-1. 【必須】ホストマシンにインストールするもの + 以下のツールのみ,開発者のPC(ホストOS)にインストールが必要である. - 2. pnpm (Corepack enabled or standalone install) - $ pnpm -v + 1. Docker実行環境 + - Docker Desktop (最新版) + - WSL2 (Windowsの場合必須) - 3. VS Code (推奨エディタ) - 以下の拡張機能を導入推奨: + 2. エディタ + - VS Code (Visual Studio Code) + + 3. VS Code 拡張機能 + - Dev Containers (ID: ms-vscode-remote.remote-containers) + ※ これが「必須」である.これさえあれば,以下の開発ツール群は自動セットアップされる. + + 4. アカウント・AI + - GitHub Copilot Pro (Student) + - Gemini Pro (学校提供ライセンス) + +4-2. 【自動】コンテナ内に構築されるもの (インストール不要) + 以下のツールは `devcontainer.json` に定義済みであり,コンテナ起動時に + 自動的にインストール・設定されるため,手動導入は不要である. + + 1. Runtime & Package Manager + - Node.js (v20.x LTS) + - pnpm (Latest) + + 2. VS Code 拡張機能 (コンテナ内) - ESLint - - Prettier - Code formatter - - EditorConfig for VS Code - - Hex Editor (バイナリパケットのデバッグ用・Microsoft公式) - - GitHub Copilot (要ログイン確認) - - 4. AI・アカウント環境 - - 学校提供の Gemini Pro へのアクセス権限確認 - - GitHub Copilot Pro (Student) の有効化確認 + - Prettier + - EditorConfig + - Hex Editor + + ※ ホスト側で `node -v` や `pnpm -v` を実行する必要はなく, + 全て VS Code の「ターミナル (コンテナ接続済)」で行う. 5. 実装上の重要ルール (Implementation Rules) diff --git "a/docs/01_Env/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206\346\233\270.txt" "b/docs/01_Env/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206\346\233\270.txt" index f8d5e5b..eb01c3b 100644 --- "a/docs/01_Env/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206\346\233\270.txt" +++ "b/docs/01_Env/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206\346\233\270.txt" @@ -1,376 +1,114 @@ ======================================================================== -Pixel Paint War - 環境構築ガイド (Environment Setup Guide) +Pixel Paint War - 開発環境利用ガイド (Development Environment Guide) ======================================================================== 1. 事前準備 (Prerequisites) ------------------------------------------------------------------------ -1-0. 目的 - 本ドキュメントは,「Pixel Paint War」のMonorepo構成による開発環境を構築 - するための手順書である. - ※ 本プロジェクトは Node.js v20 LTS 以上を必須とする. +1-1. 目的 + 本ドキュメントは,「Pixel Paint War」の開発に参加する全メンバー向けの + 環境構築および利用ガイドである. + Monorepo構成とDocker(Dev Containers)を使用し,迅速に開発を開始する手順を記す. -1-1. 必須ツールのインストール - 開発を開始する前に,以下のツールをインストールしバージョンを確認する. +1-2. 【全員必須】 共通ツールのインストール + 開発メンバー全員(管理者・参加者問わず)が以下のツールをインストールする. - 1. Node.js (v20.x LTS) - ・Nodesource リポジトリを使用してインストールする. - # リポジトリのセットアップとインストール - $ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - - $ sudo apt-get install -y nodejs + 1. Docker Engine (Linux環境) + ・開発環境の実体(コンテナ)を動かすために必須である. + + ・インストール手順 (Ubuntu/Debian系の例): + ターミナルで以下のコマンドを順に実行する. + + # 1. 公式GPG鍵とリポジトリのセットアップ + sudo apt-get update + sudo apt-get install -y ca-certificates curl gnupg + sudo install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg + sudo chmod a+r /etc/apt/keyrings/docker.gpg + + echo \ + "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ + "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + + # 2. パッケージのインストール + sudo apt-get update + sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + + # 3. ユーザー権限の設定 (重要: VS Codeからsudoなしで利用するために必須) + sudo usermod -aG docker $USER + newgrp docker ・確認コマンド: - $ node -v # v20.x.x と表示されること + $ docker -v + # Docker version 20.x.x 等と表示されること - 2. pnpm (Package Manager) - ・Node.js 標準の npm ではなく pnpm を使用する. - ・Corepack (Node.js同梱) を有効化してインストールする. - $ sudo corepack enable - $ corepack prepare pnpm@latest --activate + 2. VS Code (Visual Studio Code) + ・メインのエディタとして使用する.最新版をインストールすること. - ・確認コマンド: - $ pnpm -v + 3. VS Code 拡張機能: "Dev Containers" + ・ID: ms-vscode-remote.remote-containers + ・拡張機能マーケットプレイスで検索し、インストールする. + ・これを入れることで、Dockerコンテナ内でVS Codeを開くことが可能になる. -2. プロジェクト初期化 (Project Initialization) +2. 環境セットアップ (Setup) ------------------------------------------------------------------------ + + ■ リポジトリのクローン + 1. ソースコードの取得 + 任意のディレクトリで以下のコマンドを実行する. + $ git clone + + 2. ディレクトリ移動 + $ cd SkillSemiWebGame -2-1. ディレクトリ作成と初期化 - 1. プロジェクトルートの作成 - 任意の場所にプロジェクトフォルダを作成し,移動する. - $ mkdir SkillSemiWebGame - $ cd SkillSemiWebGame + 3. 完了 + これだけで準備は完了である. + パッケージのインストール等はDocker起動時に自動で行われるため、 + 手動での `pnpm install` 等は不要である. - 2. Gitの初期化 - $ git init - 3. pnpm の初期化 - $ pnpm init - -2-2. ワークスペース設定 (Monorepo Setup) - ルートディレクトリに以下の設定ファイルを作成し,モノレポ構成を定義する. - - 1. pnpm-workspace.yaml - ・packages/shared を共通ライブラリとし,apps 配下にアプリを配置する. - ・内容: - packages: - - 'apps/*' - - 'packages/*' - - 2. .npmrc - ・依存関係解決の設定を行う (shamefully-hoist=true 推奨). - ・内容: - shamefully-hoist=true - -2-3. ディレクトリ構造の構築 - 以下の構成になるようにディレクトリを作成する. - - root/ - ├── apps/ - │ ├── client/ # フロントエンド (Browser) - │ └── server/ # バックエンド (Node.js) - └── packages/ - └── shared/ # 共通ロジック (Shared Library) - - ・作成コマンド例: - $ mkdir -p apps/client apps/server packages/shared - -2-4. Git除外設定 (Git Ignore Setup) - 不要なファイル(依存ライブラリやビルド成果物)がGit管理下に置かれないよう, - 除外設定を行う. - - 1. 設定ファイルの作成 - プロジェクトルートディレクトリに `.gitignore` ファイルを作成する. - $ touch .gitignore - - 2. 除外ルールの記述 - 以下の内容をファイルに記述し保存する. - ・node_modules: 依存ライブラリフォルダ. - ・dist, build: ビルド生成物. - ・.env: 環境変数ファイル(セキュリティ保持のため). - - # Dependencies - node_modules/ - .pnpm-store/ - - # Build Outputs - dist/ - build/ - out/ - - # Logs - *.log - npm-debug.log* - pnpm-debug.log* - - # Environment Variables - .env - .env.local - .env.*.local - - # Editor / OS - .vscode/* - !.vscode/extensions.json - !.vscode/settings.json - !.vscode/launch.json - .idea/ - .DS_Store - Thumbs.db - - # Testing - coverage/ - - # Unignore packages (Fix for parent gitignore) - !packages/ - - 3. 設定の反映確認 - Gitのステータスを確認し,`node_modules/` 等が含まれていないことを確認する. - $ git status - -2-5. 初回コミット (Initial Commit) - 環境構築の区切りとして,現在の状態をリポジトリに保存する. - - 1. ステータス確認 - `.gitignore` が正しく適用されているか確認する. - $ git status - ※ `node_modules/` が表示されていないことを確認する. - - 2. ステージング - 変更された全てのファイルをコミット対象に追加する. - $ git add . - - 3. コミット実行 - 構築内容を示すメッセージを付与してコミットする. - $ git commit -m "chore: Project initialization (Monorepo, pnpm, Vite)" - -3. パッケージ・ライブラリ導入 (Dependency Installation) +3. 開発環境(Dev Container)の起動 (Launch) ------------------------------------------------------------------------ + +3-1. プロジェクトを開く + 1. VS Codeを起動し,「ファイル > フォルダを開く」からプロジェクトルートを選択する. -3-1. 共通ライブラリ (packages/shared) - 共通ロジック用のパッケージ設定を行う. +3-2. コンテナでの再起動 (Reopen in Container) + 以下のいずれかの方法で,開発環境をコンテナ内に移行する. - 1. 初期化とビルドツール導入 - $ cd packages/shared - $ pnpm init - $ pnpm add -D typescript tsup + 【方法A: ステータスバーから】 + 1. ウィンドウ左下の緑色(または青色)の「><」アイコンをクリックする. + 2. 表示されるメニューから「Reopen in Container」を選択する. - 2. 設定ファイルの調整 (package.json) - ・name: "@repo/shared" と命名する(推奨). - ・main: "./dist/index.js", types: "./dist/index.d.ts" を指定する. - ・scripts: "build": "tsup src/index.ts --format cjs,esm --dts" を追加する. + 【方法B: コマンドパレットから】 + 1. [F1] または [Ctrl+Shift+P] を押下する. + 2. "Reopen" と入力し,「Dev Containers: Reopen in Container」を選択する. - 3. エントリーポイントの作成 - tsupがビルド対象とするファイルを作成する. + ※ トラブルシューティング: + もし起動後に node_modules が見つからない等のエラーが出た場合は, + 「Reopen」ではなく「Dev Containers: Rebuild Container」を選択して + 環境を完全に作り直してください. - $ mkdir src - $ touch src/index.ts +3-3. 初回ビルドの待機 + 1. 初回起動時は Dockerイメージのビルドと npmパッケージのインストールが行われる. + (数分〜十数分かかる場合がある) + 2. 右下に "Starting Dev Container" 等の通知が表示されている間は待機する. + +3-4. 起動確認 + 1. 左下のアイコンが「Dev Container: Pixel Paint War Dev」と表示されていることを確認する. + 2. VS Codeのターミナルを開き (`Ctrl + @`),パスを確認する. - ※ 現時点では空ファイルでよいが,将来的に constants.ts 等を export する記述を行う. - (例: export * from './constants';) + 成功例: node@...:/workspace$ + (Windowsのパス C:\Users... ではなく Linux形式になっていれば成功) - 4. TypeScript設定ファイルの作成 (tsconfig.json) - ビルドと型定義生成のための設定ファイルを作成する. - ・ファイル: packages/shared/tsconfig.json - ・内容: - { - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "Bundler", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] - } - -3-2. フロントエンド (apps/client) - Vite プロジェクトとして初期化を行う. - - 1. プロジェクト作成 - $ cd ../../apps/client - $ pnpm create vite . --template preact-ts - ※ 実行中に表示される選択肢には以下のように回答すること: - ? Use rolldown-vite (Experimental)? » No - ? Install with pnpm and start now? » No - - 2. 依存ライブラリのインストール - ・Pixi.js (描画エンジン) を追加する. - ・共通ライブラリへの依存を追加する. - $ pnpm add pixi.js - $ pnpm add @repo/shared --workspace - -3-3. バックエンド (apps/server) - Node.js アプリケーションとして初期化を行う. - - 1. 初期化 - $ cd ../../apps/server - $ pnpm init - - 2. 依存ライブラリのインストール - ・ws (WebSocket) を追加する. - ・開発用ツール (tsx, typescript, @types/node, @types/ws) を追加する. - ・共通ライブラリへの依存を追加する. - $ pnpm add ws - $ pnpm add -D tsx typescript @types/node @types/ws - $ pnpm add @repo/shared --workspace - - 3. サーバー用ディレクトリとファイルの作成 - tsxが実行対象とするエントリーポイントを作成する. - $ mkdir src - $ touch src/index.ts - - 4. 実行スクリプトの定義 - package.json にサーバー起動用のコマンドを追加する. - ・編集ファイル: apps/server/package.json - ・内容: - "scripts": { - "dev": "tsx watch src/index.ts" - } - - 5. TypeScript設定ファイルの作成 (tsconfig.json) - 開発時の実行環境とパス解決のための設定ファイルを作成する. - ・ファイル: apps/server/tsconfig.json - ・内容: - { - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "lib": ["ES2022"], - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - "paths": { - "@repo/shared": ["../../packages/shared/src/index.ts"] - } - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] - } - - -4. 開発ツール設定 (Dev Tools Setup) ------------------------------------------------------------------------- - -4-1. VS Code 拡張機能 - 推奨エディタである VS Code に以下の拡張機能をインストールする. - - ■ 必須拡張機能 - ・ESLint - ・Prettier - Code formatter - ・EditorConfig for VS Code - - ■ 推奨拡張機能 - ・Hex Editor (バイナリパケットのデバッグ用・Microsoft公式) - ・GitHub Copilot - -4-2. AI アシスタント設定 - 開発効率化のため,以下のAIツールのアカウント設定を確認する. - - 1. Gemini Pro - ・学校提供ライセンスでのアクセス権限を確認する. - - 2. GitHub Copilot Pro - ・Student Developer Pack が有効化されているか確認する. - ・VS Code 右下のアイコンからログイン状態を確認する. - - -5. 構成確認 (Configuration Check) ------------------------------------------------------------------------- - -5-1. 最終ディレクトリ構成 - 構築完了時点で,以下のディレクトリおよびファイルが存在することを確認する. - - SkillSemiWebGame/ <-- プロジェクトルート - ├── .git/ <-- git init で作成 - ├── .gitignore <-- Git除外設定 - ├── .npmrc <-- 依存解決設定 - ├── package.json <-- ルート定義 - ├── pnpm-lock.yaml <-- pnpm install で自動生成 - ├── pnpm-workspace.yaml <-- ワークスペース定義 - ├── node_modules/ <-- 依存ライブラリ - │ - ├── apps/ <-- アプリケーション格納用 - │ ├── client/ <-- フロントエンド (Vite + Preact) - │ │ ├── node_modules/ - │ │ ├── src/ - │ │ │ ├── main.tsx (または index.tsx) - │ │ │ └── ... (Viteテンプレートファイル群) - │ │ ├── index.html - │ │ ├── package.json <-- pixi.js, @repo/shared 依存あり - │ │ ├── tsconfig.json - │ │ └── vite.config.ts - │ │ - │ └── server/ <-- バックエンド (Node.js) - │ ├── node_modules/ - │ ├── src/ - │ │ └── index.ts <-- エントリーポイント - │ ├── package.json <-- ws, @repo/shared 依存あり - │ └── tsconfig.json <-- pnpm init 等で生成(または要作成) - │ - └── packages/ <-- 共通パッケージ格納用 - └── shared/ <-- 共通ロジック - ├── node_modules/ - ├── dist/ <-- ビルド後に生成される (index.js, index.d.ts) - ├── src/ - │ └── index.ts <-- 空または定数export用 - ├── package.json <-- buildスクリプト定義あり - └── tsconfig.json <-- tsup/typescript設定用 - -5-2. 重要ファイル設定確認 - 各パッケージの連携設定が正しいか確認する. - - ■ root/pnpm-workspace.yaml - packages: - - 'apps/*' - - 'packages/*' - - ■ packages/shared/package.json - ・name: "@repo/shared" - ・main: "./dist/index.js" - ・types: "./dist/index.d.ts" - - ■ apps/client/package.json - ・dependencies: - "@repo/shared": "workspace:*" - - ■ apps/server/package.json - ・dependencies: - "@repo/shared": "workspace:*" - - -6. 動作確認 (Verification) ------------------------------------------------------------------------- - -6-1. ビルド確認 - ルートディレクトリから全体の依存関係をインストールし,ビルドを試行する. - - $ cd ../../ - $ pnpm install - $ pnpm --filter @repo/shared build - - ※ shared のビルドが成功することを確認する. - -6-2. 開発サーバー起動 - モノレポ構成のため,個別のディレクトリに移動せず,プロジェクトルートから - --filter オプションを使用して各アプリを起動する. - ※ ターミナルを2つ開き,両方を同時に起動した状態で開発を進めることを推奨. - - 1.Client (フロントエンド) の動作確認 - ・ルートディレクトリにて以下のコマンドを実行する. - $ pnpm --filter client dev + 3. 動作確認コマンドを実行する. + $ pnpm --filter client dev + + ※ エラー時の対応: + 「sh: vite: not found」等のエラーが出る場合は,自動インストールが完了していない可能性があります. + ターミナルで `pnpm install` を手動実行するか,上記 3-2 の「Rebuild Container」を試してください. ・ブラウザでの確認: ターミナルに「➜ Local: http://localhost:5173/」と表示されたら, @@ -379,7 +117,87 @@ ・正常動作の判断基準: 画面に「Vite + Preact」のロゴと「Vite + Preact + TypeScript」といった テキストが表示されていれば,フロントエンドの環境構築は成功である. - + + +4. 開発ツールの確認 (Tools Verification) +------------------------------------------------------------------------ +Dockerコンテナ起動完了後、定義済みのツールが正しく自動導入されているか確認する. +※ 手動でのインストールは不要である. + +4-1. VS Code 拡張機能 + 拡張機能サイドバーを開き、"Dev Container: Pixel Paint War Dev" セクションに + 以下がインストール済みであることを確認する. + ・ESLint + ・Prettier - Code formatter + ・EditorConfig for VS Code + ・Hex Editor + ・GitHub Copilot + +4-2. AI アシスタント設定 + GitHub Copilot Pro + - VS Code 右下のアイコンから、GitHubアカウントへのログイン状態を確認する. + + +5. 構成確認 (Project Structure) +------------------------------------------------------------------------ + +5-1. ディレクトリ構成 + コンテナ内で以下のディレクトリ構造が見えていることを確認する. + + SkillSemiWebGame/ <-- プロジェクトルート + ├── .devcontainer/ <-- Docker設定 + ├── .git/ + ├── docker-compose.yml <-- Docker構成 + ├── package.json <-- ルート定義 + ├── pnpm-workspace.yaml <-- ワークスペース定義 + ├── node_modules/ <-- 依存ライブラリ + │ + ├── apps/ <-- アプリケーション格納用 + │ ├── client/ <-- フロントエンド (Vite + Preact) + │ │ ├── src/ + │ │ │ ├── main.tsx + │ │ │ └── ... + │ │ ├── package.json <-- pixi.js, @repo/shared 依存あり + │ │ └── vite.config.ts + │ │ + │ └── server/ <-- バックエンド (Node.js) + │ ├── src/ + │ │ └── index.ts <-- エントリーポイント + │ └── package.json <-- ws, @repo/shared 依存あり + │ + └── packages/ <-- 共通パッケージ格納用 + └── shared/ <-- 共通ロジック + ├── dist/ <-- ビルド成果物 + ├── src/ + │ └── index.ts + └── package.json + +6. 動作確認 (Verification) +------------------------------------------------------------------------ + +6-1. ビルド確認 + ※ 注意: 以下のコマンドは全て「Dev Container内のターミナル」で実行すること. + + $ pnpm --filter @repo/shared build + ※ shared のビルドが成功することを確認する. + +6-2. 開発サーバー起動 + モノレポ構成のため,個別のディレクトリに移動せず,プロジェクトルートから + --filter オプションを使用して各アプリを起動する. + ※ ターミナルを2つ開き,両方を同時に起動した状態で開発を進めることを推奨. + + 1.Client (フロントエンド) の動作確認 + ・ルートディレクトリにて以下のコマンドを実行する. + $ pnpm --filter client dev + + ・ブラウザでの確認: + ターミナルに「➜ Local: http://localhost:5173/」と表示されたら, + Google Chrome等のブラウザを開き,アドレスバーに上記URLを貼り付けて実行する. + + ・正常動作の判断基準: + 画面に「Vite + Preact」のロゴと「Vite + Preact + TypeScript」といった + テキストが表示されていれば,フロントエンドの環境構築は成功である. + 2. Server (バックエンド) の動作確認 ・テスト用コードの作成: 動作確認用のエントリーポイントを作成する. @@ -397,5 +215,32 @@ 3.終了方法 (重要) ・動作確認を終了し,開発サーバーを停止させる場合は,ターミナル上で 「Ctrl + C」を押下する. - ・停止後はブラウザでURLにアクセスしても接続不可となるが,再度起動 - コマンドを実行すればいつでも再開可能である. \ No newline at end of file + + +7. (応用) 本番ビルドの動作確認 (Production Build Check) +------------------------------------------------------------------------ +開発環境(Dev Container)ではなく,本番環境と同様のDockerイメージを作成し, +正しくビルド・起動できるかを確認する手順である. +「機能開発が終わった後」や「プルリクエストを出す前」に実施することを推奨する. + +7-1. 準備 + Dev Containerを閉じ,ホストOS(Windows/Mac)のターミナルを開く. + ※ Dev Container内からはDockerコマンドが使用できない場合があるため. + +7-2. ビルドと起動 + プロジェクトルートで以下のコマンドを実行する. + + $ docker compose -f docker-compose.prod.yml up -d --build + +7-3. 動作確認 + 1. ログ確認 + $ docker compose -f docker-compose.prod.yml logs -f + Serverが起動していることを確認する. + + 2. ブラウザ確認 + http://localhost:3001 + ※ ポート番号が開発用(3000/5173)と異なり 3001 に設定されている点に注意. + +7-4. 終了と削除 + 確認が終わったら必ず環境を停止・削除する. + $ docker compose -f docker-compose.prod.yml down \ No newline at end of file diff --git "a/docs/01_Env/ENV_05_Docker\351\201\213\347\224\250\346\223\215\344\275\234\343\202\254\343\202\244\343\203\211.txt" "b/docs/01_Env/ENV_05_Docker\351\201\213\347\224\250\346\223\215\344\275\234\343\202\254\343\202\244\343\203\211.txt" new file mode 100644 index 0000000..be89f13 --- /dev/null +++ "b/docs/01_Env/ENV_05_Docker\351\201\213\347\224\250\346\223\215\344\275\234\343\202\254\343\202\244\343\203\211.txt" @@ -0,0 +1,82 @@ +======================================================================== +Docker 運用・操作ガイド (Docker Operations Guide) +======================================================================== + +1. 目的 (Objective) +------------------------------------------------------------------------ +本ドキュメントは,Pixel Paint War プロジェクトにおける Docker の日常的な +操作コマンドと,トラブルシューティング手順をまとめたものである. +本プロジェクトでは「開発環境」と「本番環境」で異なる運用を行う. + + +2. 開発環境 (Development Environment) +------------------------------------------------------------------------ +VS Code の Dev Containers 機能を使用する. + +2-1. +基本操作 + ・起動: VS Code でプロジェクトを開き,「Reopen in Container」を実行する. + ・停止: VS Code を閉じる(自動的に停止する). + ・ターミナル: VS Code 内のターミナルを使用する. + +2-2. +コンテナの再構築 (Rebuild) + 依存関係の不整合や設定変更が反映されない場合に実行する. + 1. コマンドパレット (F1) を開く. + 2. 「Dev Containers: Rebuild Container」を選択する. + 3. キャッシュを無視したい場合は「Rebuild Without Cache」を選択する. + + +3. 本番環境 (Production Environment) +------------------------------------------------------------------------ +手動で Docker Compose コマンドを実行する. +※ 必ず WSL (Windows) または ホストOSのターミナルで実行すること. + +3-1. +基本コマンド + ■ 起動 (ビルド込み) + $ docker compose -f docker-compose.prod.yml up -d --build + + ■ 状態確認 + $ docker compose -f docker-compose.prod.yml ps + + ■ ログ確認 (リアルタイム) + $ docker compose -f docker-compose.prod.yml logs -f + + ■ 停止 + $ docker compose -f docker-compose.prod.yml down + +3-2. +ポート仕様 + ・ホスト側ポート: 3001 + ・コンテナ内ポート: 3000 + ・接続確認URL: http://localhost:3001 + ※ 開発用コンテナ (Port 3000) との衝突を避けるため,3001番を使用する. + + +4. トラブルシューティング (Troubleshooting) +------------------------------------------------------------------------ + +4-1. +ビルドエラー・反映漏れへの対処 + 修正したコードが反映されない,または原因不明のエラーが出る場合, + キャッシュを使わずに強制的に再ビルドを行う. + + $ docker compose -f docker-compose.prod.yml build --no-cache + $ docker compose -f docker-compose.prod.yml up -d --force-recreate + +4-2. +モジュールが見つからない (MODULE_NOT_FOUND) + 本番起動時に `ws` 等が見つからないエラーが出る場合,`Dockerfile` の + COPY記述を確認する.pnpm のシンボリックリンク構造に対応するため, + 以下が記述されている必要がある. + + COPY --from=builder /app/apps/server/node_modules ./apps/server/node_modules + +4-3. +再起動ループ (Restarting) + `docker ps` でステータスが `Restarting` になる場合,サーバープロセスが + クラッシュまたは終了している. + 1. ログを確認する: + $ docker compose -f docker-compose.prod.yml logs --tail=50 + 2. コード修正後,4-1 の手順で再デプロイする. \ No newline at end of file diff --git "a/docs/01_Env/ENV_06_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.txt" "b/docs/01_Env/ENV_06_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.txt" new file mode 100644 index 0000000..3b39784 --- /dev/null +++ "b/docs/01_Env/ENV_06_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.txt" @@ -0,0 +1,346 @@ +======================================================================== +Pixel Paint War - 管理者用環境構築手順 (Admin Setup Guide) +======================================================================== + +1. はじめに (Introduction) +------------------------------------------------------------------------ + 本ドキュメントは,プロジェクトを「ゼロから新規作成・再構築する管理者」向けの + Monorepo構成およびDocker環境の構築ログである. + ※ 一般の開発メンバー(Git Cloneして参加する人)は本ドキュメントを実施不要である. + +2. 管理者用事前準備 (Prerequisites for Admin) +------------------------------------------------------------------------ + +2-1. プロジェクト作成用ツールのインストール + 1. Node.js (v20.x LTS) + ・Nodesource リポジトリを使用してインストールする. + + # リポジトリのセットアップとインストール + $ curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + $ sudo apt-get install -y nodejs + + ・確認コマンド: + $ node -v # v20.x.x と表示されること + + 2. pnpm (Package Manager) + ・Node.js 標準の npm ではなく pnpm を使用する. + ・Corepack (Node.js同梱) を有効化してインストールする. + $ sudo corepack enable + $ corepack prepare pnpm@latest --activate + + ・確認コマンド: + $ pnpm -v + + +3. 新規プロジェクト構築 (Project Initialization) +------------------------------------------------------------------------ + +3-1. プロジェクト初期化 + 1. ディレクトリ作成 + $ mkdir SkillSemiWebGame + $ cd SkillSemiWebGame + + 2. Git/pnpm 初期化 + $ git init + $ pnpm init + +3-2. Monorepo構成設定 + 1. pnpm-workspace.yaml 作成 + ルート直下に作成し、以下を記述する. + packages: + - 'apps/*' + - 'packages/*' + + 2. .npmrc 作成 + ルート直下に作成し、以下を記述する. + shamefully-hoist=true + +3-3. ディレクトリ構造の構築 + 以下の構成になるようにディレクトリを作成する. + + root/ + ├── apps/ + │ ├── client/ # フロントエンド (Browser) + │ └── server/ # バックエンド (Node.js) + └── packages/ + └── shared/ # 共通ロジック (Shared Library) + + ・作成コマンド例: + $ mkdir -p apps/client apps/server packages/shared + +3-4. Git除外設定 (.gitignore) + ルート直下に `.gitignore` を作成し、以下を記述する. + + node_modules/ + .pnpm-store/ + dist/ + build/ + .env + .DS_Store + .vscode/* + !.vscode/extensions.json + !.vscode/launch.json + coverage/ + !packages/ + + +4. アプリケーション雛形の作成 (Scaffolding) +------------------------------------------------------------------------ + +4-1. 共通ライブラリ (packages/shared) + 1. 初期化とビルドツール導入 + $ cd packages/shared + $ pnpm init + $ pnpm add -D typescript tsup + + 2. 設定ファイルの調整 (package.json) + ・name: "@repo/shared" と命名する(推奨). + ・main: "./dist/index.js", types: "./dist/index.d.ts" を指定する. + ・scripts: "build": "tsup src/index.ts --format cjs,esm --dts" を追加する. + + 3. エントリーポイントの作成 + $ mkdir src + $ touch src/index.ts + ※ (例: export * from './constants';) + + 4. TypeScript設定ファイルの作成 (tsconfig.json) + ・ファイル: packages/shared/tsconfig.json + ・内容: + { + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "Bundler", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] + } + +4-2. フロントエンド (apps/client) + 1. プロジェクト作成 + $ cd ../../apps/client + $ pnpm create vite . --template preact-ts + ※ Use rolldown-vite? » No + ※ Install with pnpm and start now? » No + + 2. 依存ライブラリのインストール + $ pnpm add pixi.js + $ pnpm add @repo/shared --workspace + +4-3. バックエンド (apps/server) + 1. 初期化 + $ cd ../../apps/server + $ pnpm init + + 2. 依存ライブラリのインストール + $ pnpm add ws + $ pnpm add -D tsx typescript @types/node @types/ws + $ pnpm add @repo/shared --workspace + + 3. サーバー用ディレクトリとファイルの作成 + $ mkdir src + $ touch src/index.ts + + 4. 実行スクリプトの定義 (package.json) + "scripts": { + "dev": "tsx watch src/index.ts" + } + + 5. TypeScript設定ファイルの作成 (tsconfig.json) + ・ファイル: apps/server/tsconfig.json + ・内容: + { + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": ["ES2022"], + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + "paths": { + "@repo/shared": ["../../packages/shared/src/index.ts"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules"] + } + +4-4. 初回コミット (Initial Commit) + 1. ルートに戻る + $ cd ../.. + 2. ステータスの確認 (node_modulesが含まれていないこと) + $ git status + 3. Gitへ保存 + $ git add . + $ git commit -m "chore: Initialize project structure and dependencies" + + +5. Docker環境定義ファイルの作成 (Configuration) +------------------------------------------------------------------------ + +5-1. Dockerfile の作成 + プロジェクトルートに `Dockerfile` を作成する. + ※ Node.js v20 をベースとし,pnpm を有効化した開発用イメージ定義. + + FROM node:20-slim + + # pnpmの準備 + ENV PNPM_HOME="/pnpm" + ENV PATH="$PNPM_HOME:$PATH" + RUN corepack enable + + # 作業ディレクトリ設定 + WORKDIR /workspace + + # 依存関係のコピーとインストール (キャッシュ活用) + COPY . . + RUN pnpm install + + # ポート公開 (Vite:5173, Server:3000) + EXPOSE 5173 3000 + + # デフォルトコマンド (docker-composeで上書きするため待機) + CMD ["sleep", "infinity"] + +5-2. docker-compose.yml の作成 (開発用) + プロジェクトルートに `docker-compose.yml` を作成する. + ※ ローカルのソースコードをコンテナにマウントする設定. + + version: "3.8" + + services: + app: + container_name: pixel-paint-war-dev + # 開発用イメージ: Node.js v20 (定義書準拠) + image: mcr.microsoft.com/devcontainers/typescript-node:20 + + # 永続化とボリュームマウント + volumes: + # カレントディレクトリをコンテナ内の /workspace にマウント + - .:/workspace:cached + # 【重要】node_modules をホスト側と切り離して高速化・安定化させる設定 + - node_modules:/workspace/node_modules + + # コマンドの上書き (コンテナを常時起動させる) + command: sleep infinity + + # ネットワーク設定 + # Client(5173) と Server(3000) のポートを開放 + ports: + - "5173:5173" + - "3000:3000" + + # 環境変数 + environment: + - NODE_ENV=development + + # ユーザー権限 (Nodeイメージ推奨のユーザー) + user: node + + volumes: + node_modules: + +5-3. .devcontainer 設定の作成 + 1. ディレクトリ作成 + $ mkdir .devcontainer + + 2. .devcontainer/devcontainer.json 作成 + VS Codeがコンテナを認識するための設定. + + { + "name": "Pixel Paint War Dev", + "dockerComposeFile": "../docker-compose.yml", + "service": "app", + "workspaceFolder": "/workspace", + + "features": { + "ghcr.io/devcontainers/features/node:1": { + "version": "20", + "pnpm": "latest" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig", + "ms-vscode.hexeditor", + "github.copilot", + "github.copilot-chat" + ], + "settings": { + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode" + } + } + }, + + // コンテナ起動後の初期化コマンド + // 1. sudo chown ... : node_modules の所有権を node ユーザーに強制変更 + // 2. pnpm install : その後,安全にインストールを実行 + // 3. build : 最後に共通パッケージをビルド + "postCreateCommand": "sudo chown -R node:node /workspace/node_modules && pnpm install && pnpm --filter @repo/shared build", + + // コンテナ内のユーザー + "remoteUser": "node" + } + +5-4. docker-compose.prod.yml の作成 (本番確認用) + プロジェクトルートに `docker-compose.prod.yml` を作成する. + ※ 本番ビルド確認用にポートをずらし、ビルドコマンドを実行する設定. + + services: + app: + build: . + ports: + - "3001:3000" + environment: + - NODE_ENV=production + command: pnpm start + + +6. 本番デプロイ構成の補足 (Deployment Config) +------------------------------------------------------------------------ +本番環境へデプロイする際は,上記 `Dockerfile` をマルチステージビルドに修正し, +軽量化を図ることが推奨される. + +6-1. Dockerfile (本番用最適化例) + ※ 必要に応じて `Dockerfile.prod` として作成する. + + FROM node:20-slim AS base + ENV PNPM_HOME="/pnpm" + ENV PATH="$PNPM_HOME:$PATH" + RUN corepack enable + COPY . /app + WORKDIR /app + + FROM base AS prod-deps + RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile + + FROM base AS build + RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile + RUN pnpm run build + + FROM base + COPY --from=prod-deps /app/node_modules /app/node_modules + COPY --from=build /app/apps/server/dist /app/apps/server/dist + COPY --from=build /app/apps/client/dist /app/apps/client/dist + + EXPOSE 3000 + CMD [ "pnpm", "start" ] \ No newline at end of file