はじめに
この記事について
この記事はWeb開発初心者の私がアドベントカレンダーの力を借りて勉強を進めるために書いています。
そのため、ほぼ忘備録的に書いているので、記事の内容については保証できません。
あと、Next.jsのDockerfileなどの作成はClaude Codeを使いながら実施しているので、公式ドキュメントオンリーではないです。
動作環境
-
OS: Windows 11 Home 25H2 -
コードエディタ: VSCode ver1.105.1 -
Docker Desktop on Windows: 4.49.0 -
Node.js: v24.11.0(LTS) -
Next.js: v16.0.1
Docker Desktopのインストール
なぜDockerなのか
Node.jsのダウンロードをする際に、一番トップにDockerでのダウンロード方法が表示されたので、勝手にDockerを使うのが推奨なのだと判断しました。
Dockerの公式ドキュメントのインストール手順を実行
今回はDocker Desktop Installer.exe でインストールします。
インストール後に初回起動でログインする必要があります。今回は個人開発なので、personalタブ側でGithubアカウントを使ってログインしました。
Node.jsのインストール
Node.jsのパッケージマネージャーについて
公式でpnpmを推奨しているので、本記事内ではpnpmを使用していきます。
参考URL
Node.jsの公式ドキュメントのインストール手順を実行
Dockerがインストール出来ていたら、VSCode上でターミナルを起動して以下のPowerShellコマンドを実行
# Node.jsのDockerイメージを取得する:
docker pull node:24-alpine
# Node.jsのコンテナーを作成しシェルを起動する:
docker run -it --rm --entrypoint sh node:24-alpine
# Node.jsのバージョンを確認する:
node -v # "v24.11.0"が表示される。
# pnpmをダウンロードしてインストールする:
corepack enable pnpm
# pnpmのバージョンを確認する:
pnpm -v
Dockerコンテナ起動時の各コマンドの意味
docker run -it --rm --entrypoint sh node:24-alpine
意味:
-
docker run: コンテナを作成して起動 -
-it: 2つのオプションの組み合わせ-
-i(interactive): 標準入力を開いたままにする -
-t(tty): 疑似ターミナルを割り当てる - → この2つで対話的にコンテナ内でコマンド操作できる
-
-
--rm: コンテナ終了時に自動的にコンテナを削除(クリーンアップ) -
--entrypoint sh: デフォルトの起動コマンドを上書きしてsh(シェル)を起動- 通常Node.jsコンテナは
nodeコマンドで起動するが、これによりシェルで起動
- 通常Node.jsコンテナは
-
node:24-alpine: 使用するイメージ名
結果
このコマンドを実行すると、Node.js 24がインストールされたAlpine Linuxのシェルに入り、自由にコマンドを実行できる環境になります。コンテナから抜ける(exitまたはCtrl+D)と、コンテナは自動的に削除されます。
Next.js用のDockerfile,docker-compose.ymlを作成
Dockerfile
FROM node:24-alpine AS base
# pnpmをインストール
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && \
corepack prepare pnpm@latest --activate
# 依存関係インストール専用ステージ
FROM base AS deps
WORKDIR /app
# マウントキャッシュを使用してさらに高速化
COPY package.json pnpm-lock.yaml* ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile
# 開発環境用ステージ
FROM base AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["pnpm", "run", "dev"]
docker-compose.yml
name: my-nextjs-app
services:
nextjs:
container_name: nextjs-dev
build:
context: ..
dockerfile: docker/Dockerfile
target: dev
ports:
- "3000:3000"
volumes:
- ..:/app
- /app/node_modules
- /app/.next
# pnpm特有: pnpmのストアをキャッシュ
- pnpm-store:/pnpm/store
environment:
- NODE_ENV=development
- WATCHPACK_POLLING=true
stdin_open: true
tty: true
restart: unless-stopped
networks:
- nextjs-network
volumes:
pnpm-store:
networks:
nextjs-network:
driver: bridge
Dockerfileの解説
FROM node:24-alpine AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && \
corepack prepare pnpm@latest --activate
意味:
- ベースとなるイメージを定義
-
AS baseで「base」という名前をつけて、後で参照できるようにする -
corepack: Node.js 16以降に含まれるパッケージマネージャー管理ツール - pnpmを有効化
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml* ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
pnpm install --frozen-lockfile
意味:
-
FROM base AS deps: baseから新しいステージ「deps」を作成(依存関係インストール専用) -
WORKDIR /app: 作業ディレクトリを/appに設定 -
COPY package.json pnpm-lock.yaml* ./:package.jsonとpnpm-lock.yaml(無くてもよい)だけをコピー -
--mount=type=cache: Dockerのビルドキャッシュマウント機能 -
--frozen-lockfile: pnpm-lock.yamlを更新せずにインストール(npm ciと同等)
FROM base AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["pnpm", "run", "dev"]
意味:
-
FROM base AS dev: 開発環境用のステージを作成 -
COPY --from=deps /app/node_modules ./node_modules: depsステージからnode_modulesをコピー -
COPY . .: すべてのソースコードをコピー -
EXPOSE 3000: 3000番ポートを公開 -
CMD ["pnpm", "run", "dev"]: コンテナ起動時のデフォルトコマンド
docker-compose.ymlの解説
各セクションの意味
name: my-nextjs-app # プロジェクト全体の名前
services: # コンテナの定義
volumes: # 永続化データの定義
networks: # ネットワークの定義
servicesセクションの詳細
services:
nextjs: # docker compose run実行時のサービス名
container_name: nextjs-dev # コンテナに付ける名前
build:
context: .. # Dockerfileをdockerディレクトリに格納するので、親ディレクトリの場所
dockerfile: docker/Dockerfile # Dockerfileを指定
target: dev # Dockerfileの「dev」ステージを使用
ports:
- "3000:3000" # ポートのマッピング。Windowsの3000番ポートをコンテナの3000番に転送
volumes:
- ..:/app # 親ディレクトリ(Windows側)をコンテナの`/app`にマウント。Windows側でファイルを編集すると、リアルタイムでコンテナ内にも反映
- /app/node_modules # コンテナ内の/app/node_modulesを優先する
- /app/.next # Next.jsのビルドキャッシュをコンテナ内だけで管理
- pnpm-store:/pnpm/store # pnpmのパッケージストア(キャッシュ)を永続化。名前付きボリュームを使用
environment:
- NODE_ENV=development # Node.jsに「開発モード」であることを伝える。開発用の便利な機能やエラー表示が有効になる
- WATCHPACK_POLLING=true # ファイル変更の監視方法を「ポーリング」に変更。Windows特有の設定
stdin_open: true # docker run の -i に相当。標準入力を開いたまま
tty: true # docker run の -t に相当。疑似ターミナルを割り当て
restart: unless-stopped # コンテナの再起動ポリシー:手動停止しない限り常に再起動
networks:
- nextjs-network # このコンテナが接続するネットワークを指定。同じネットワークのコンテナ同士が通信できるようになる
volumesセクションの詳細
volumes:
pnpm-store: # 名前付きボリュームを定義。Dockerが管理する永続化ストレージ。複数のコンテナでデータを共有できる
networksセクションの詳細
networks:
nextjs-network: # カスタムネットワークを定義
driver: bridge # 最も一般的なネットワークドライバ。同じホスト内のコンテナ同士を接続
実際の開発フロー
# 1. Windows側でプロジェクト作成
C:\Users\YourName> mkdir my-nextjs-app
C:\Users\YourName> cd my-nextjs-app
C:\Users\YourName\my-nextjs-app> mkdir docker
C:\Users\YourName\my-nextjs-app> cd docker
# 2. Dockerfile, docker-compose.ymlを作成(Windows側)
# 3. Next.jsプロジェクトをpnpmで作成(注意!!)
docker compose run --rm nextjs pnpm create next-app . --typescript --tailwind --app
# 4.開発サーバー起動
docker compose up
# 5. Windows側でVS Codeなどを開く
# src/app/page.tsx を編集
# → 保存すると自動的にブラウザが更新される!
# 6.開発サーバー終了
docker compose down
躓いた箇所
# 3. Next.jsプロジェクトをpnpmで作成
docker compose run --rm nextjs pnpm create next-app . --typescript --tailwind --app
# エラー発生
failed to solve: failed to compute cache key: failed to calculate checksum of ref ~~~: "/pnpm-lock.yaml": not found
pnpm-lock.yamlが見つからずエラー発生した。
今回は初回作成用のDockerfile.initとdocker-compose.init.ymlを作成して、next.jsプロジェクトを作ることにした。(いい方法があればコメントお願いします。)
Dockerfile.init
FROM node:24-alpine
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && \
corepack prepare pnpm@latest --activate
WORKDIR /app
docker-compose.init.yml
name: my-nextjs-app
services:
nextjs:
build:
context: ..
dockerfile: docker/Dockerfile.init
volumes:
- ..:/app
- pnpm-store:/pnpm/store
volumes:
pnpm-store:
初回用コマンド
docker compose -f docker-compose.init.yml run --rm nextjs sh
pnpm create next-app ./temp-next --typescript --tailwind --app
✔ Which linter would you like to use? › ESLint
✔ Would you like to use React Compiler? … Yes
✔ Would you like your code inside a `src/` directory? … No
✔ Would you like to use Turbopack? (recommended) … Yes
✔ Would you like to customize the import alias (`@/*` by default)? … No
rsync -av temp-next/ .
rm -rf temp-next
開発時に使用するDockerコマンド
# ビルドだけ行う
docker compose up --build
# 開発サーバー起動中の別ターミナルで
docker compose exec nextjs pnpm add axios
# または一度だけ実行する場合
docker compose run --rm nextjs pnpm add axios
# 依存関係の更新
docker compose exec nextjs pnpm update
# パッケージの削除
docker compose exec nextjs pnpm remove axios
# scripts実行
docker compose exec nextjs pnpm run build
# コンテナ内に入って確認
docker compose run --rm nextjs sh
VSCode拡張機能のインストール
-
Dev Containers:コンテナ内で開発する(これが無いとts2307エラーが解決しない)
Dev Containersの実行手順
-
devcontainer.jsonを作成
my-nextjs-app/.devcontainer/devcontainer.json -
Ctrl+Shift+Pでコマンドパレットを開く -
Dev Containers: Reopen in Containerを選択
devcontainer.json
{
"name": "Next.js Development",
"dockerComposeFile": "../docker/docker-compose.yml",
"service": "nextjs",
"workspaceFolder": "/app",
"overrideCommand": true,
"initializeCommand": "docker volume create pnpm-store",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"formulahendry.auto-rename-tag",
"ms-azuretools.vscode-docker"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"typescript.tsdk": "node_modules/typescript/lib"
}
}
},
"forwardPorts": [3000],
"postCreateCommand": "pnpm install",
"remoteUser": "node"
}
躓いた箇所
VSCodeで開いていたフォルダが一階層上だったため、.devcontainer/devcontainer.jsonを正しく読み込めず、テンプレートコンテナを起動してしまった。
おわりに
Next.jsで開発を始めたいのに、環境を整える部分で知らないことが沢山出てきました。
今後もそういった知らない前提知識が出てくると思うので、ワクワクしています。
一応計9年くらい開発経験(車載系で7年/製造業オープン系で2年)があるはずなのに、WEB系になると初心者同然となってしまうのが、キャリアチェンジの難しさを感じました。
開発者人生で初めて記事を書いてみたので、色々拙い部分があると思いますが感想やご指摘お待ちしています。