🐳

Docker上でNext.js/Express.jsを環境構築

2024/11/02に公開

はじめに

初めまして、きょうへいと申します。
この度は私の記事をご覧いただきありがとうございます!

私は未経験からエンジニアとして就職し、現在の企業でTypeScript、Next.js、Express.jsを使用した開発に携わっています。
まだまだ駆け出しのエンジニアなので、技術についての理解を深めるために本記事を作成しました。
良ければお付き合い下さい!

本記事の目的

  • Docker を使用したフルスタック開発環境の構築方法の解説
  • Next.js(フロントエンド)とExpress.js(バックエンド)の連携環境の作成
  • データベース(PostgreSQL)を含めた実践的な開発環境の構築

前提知識

環境構築の流れ

1.プロジェクト構成
2.docker-compose.yaml作成
3.Next.jsの環境構築
4.Expreess.jsの環境構築

プロジェクト構成

今回は以下のような構成で進めようと思います。

project-root/
├── front/
│   ├── Dockerfile
│   └── (Next.jsプロジェクトファイル)
├── back/
│   ├── Dockerfile
│   └── (Express.jsプロジェクトファイル)
└── docker-compose.yml

リポジトリの作成とサブモジュール化

まずは、リポジトリを作成していきます。
※リポジトリの作成方法については、公式の記事を参照ください。

今回は

  • project-root(任意のファイル名)
  • front
  • back

この3つのリポジトリを作成したのち、front,backproject-rootのサブモジュール化します。

サブモジュール化は以下のコードで行って下さい。

git submodule add <frontリポジトリのSSH> front
git submodule add <backリポジトリのSSH> back

project-rootをリモートリポジトリにpushしてback@〇〇〇〇〇〇〇のようになっていれば反映できています。

dockerfileの作成

Dokcerfileの作成

frontbackdockerfileを作成し、以下のように記載してください

FROM node:20
WORKDIR /app

Docker Compose設定

また、docker-compose.ymlは以下のようになります。

services:
  front:
    build:
      context: ./front
      dockerfile: Dockerfile
    ports:
      - "3000:3000"  # Next.jsのデフォルトポート
    volumes:
      - ./front:/app  # ソースコードの同期
    environment:
      - NEXT_PUBLIC_API_URL=http://back:8000  # バックエンドのURL
    depends_on:
      - back
    restart: unless-stopped

  back:
    build:
      context: ./back
      dockerfile: Dockerfile
    ports:
      - "8000:8000"  # Express.jsのポート
    volumes:
      - ./back:/app
      - /app/node_modules  # node_modulesはコンテナ内に保持
    environment:
      - DATABASE_URL=postgresql://user:password@db:5432/dbname
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:15
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data  # データの永続化
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password  # 本番環境では必ず変更してください
      - POSTGRES_DB=dbname
    restart: unless-stopped

volumes:
  postgres_data:  # PostgreSQLのデータを永続化

設定が完了したら、以下のコマンドでビルドを実行します。

docker-compose build

next.jsの環境構築

プロジェクトの作成

まず、Dockerfileを一時的にルートディレクトリに移動します(権限の問題を回避するため)
移動させた後、Next.jsプロジェクトを作成します。
root-projectに戻り以下のコマンドを実行してください

docker-compose run --rm front npx create-next-app .

すると、next.jsで以下の内容を使用するか出てくるので好きなように選んでください。
今回、僕は初期のままにしています。

Would you like to use TypeScript? … No / Yes
  → 型安全な開発のために推奨
✔ Would you like to use ESLint? … No / Yes
  → コード品質管理のために推奨
✔ Would you like to use Tailwind CSS? … No / Yes
  → CSSフレームワークの導入
✔ Would you like to use `src/` directory? … No / Yes
  → ソースコードの整理のために推奨
✔ Would you like to use App Router? (recommended) … No / Yes
  → 新しいルーティングシステムの採用
✔ Would you like to customize the default import alias (@/*)? … No / Yes
  → インポートパスの簡略化

Dockerfileの更新

Dockerfileにこちらを追記してfrontに戻してください

FROM node:20
WORKDIR /app

COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

EXPOSE 3000
CMD ["npm", "start"]

ビルドと動作確認

再度buildを行い、dockerとnext.jsの初期化を実施します。

docker-compose build
docker-compose run --rm front npx next build

next.jsのビルドが終わると起動の確認ができます。
必要があれば適宜確認を行ってみてください。

docker-compose up front

Expreess.jsの環境構築

root-projectにて以下のコマンドを使用します。
以下のコマンドを使用することにより、npmの初期化と必要なパッケージのインストールを行います。

docker-compose run --rm back npm init -y
docker-compose run --rm back npm install express 
docker-compose run --rm back npm install typescript @types/express @types/node ts-node nodemon -D

Dockerfileの更新

Dockerのコンテナ内で処理を行うため、Dockerfileに以下の記載を行ってイメージをビルドします。

FROM node:20
WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

#tscの初期化を行ったらコメントアウトを外す RUN npm run build

EXPOSE 8000

CMD ["npm", "run", "dev"]

Dockerfileの変更を行なったら、再度ビルドを行って下さい。

docker-compose build

TypeScript設定

ビルドが終わり次第、TypeScriptの設定を行なっていきます。
以下のコマンドで初期化を行うようにしましょう。

docker-compose run --rm back npx tsc --init

package.jsonの更新

TypeScriptの初期化が終わったら、Express.jsの立ち上げを行なっていきます。
まずは、dockerを立ち上げにExpress.jsが動作するようにpackage.jsonを書き換えていきます。
以下の内容に修正を行って下さい。

 {
  "name": "app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "npx nodemon --exec ts-node src/server.ts",
    "build": "tsc",
    "start": "node dist/app.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.21.1"
  },
  "devDependencies": {
    "@types/express": "^5.0.0",
    "@types/node": "^22.8.1",
    "nodemon": "^3.1.7",
    "ts-node": "^10.9.2",
    "typescript": "^5.6.3"
  }
}

サーバーの作成

package.jsonへの記載変更が終了したら、実際にテスト用のサーバーを作成していきます。
以下のような記載を行って、Express.jsにてHello World!が表示されるようにしていきます。

import express from "express";
import { Request, Response } from "express";

const app = express();
const port = 8000;

app.get("/", (req: Request, res: Response) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
})

動作確認

以上の記載が終了すれば、localhost:8000上に表示が行えているはずです。
dockerのビルドを行ったのち、確認を行ってみて下さい。

docker compose build
dcoker compose up

正常に動作していれば、http://localhost:8000 にアクセスすると「Hello World!」が表示されるはずです。

終わりに

今回初めて技術記事の作成を行いました。
今後もアプリケーション作成時に行った実装についての記事を作成していこうと思っていますので、よければそちらも読んでいただけると嬉しいです!

Discussion