Azure Static Web Appsで始めるNext.js静的サイト開発 with DevContainer

Next.jsで始める静的サイト on Azure Static Web Apps

ども!年末年始を抜けてぬるっと仕事に復帰を始めている龍ちゃんです。年末年始は、今まで溜まっていた検証+お部屋を片付けていたので、意外と充実していました。去年は、GitHub AcitonsとDevContainerでの環境構築作成をしっかりやっていた時期かなと振り返り、またブログにまとめていきます。

今回の内容は、以下の二つになります。

  • Azure Static Web Apps上でNext.jsの静的サイト配信を行う(GitHub Actionsを用いたデプロイ)
  • ローカルの開発環境をDevContainerで作成する(SWA CLIを活用してローカルでプレビュー)

ローカル環境でStatic Web Apps(以降:SWA)の挙動を確認することができる、SWA CLIを開発環境にインストールします。今回のゴールとしては、SWA CLI動作確認とSWAへのNext.js静的サイトを公開になります。

SWA CLIとは

Azureさん公式のエミュレーターになります。SWAの挙動をローカルで再現してくれます。開発時に特にうれしい機能として以下の二つかなと思います。

  • SWA上に構築済みの認証をモックで試すことができる
  • APIエンドポイントへのプロキシ

SWA上に構築済みの認証をモックで試すことができる

SWAでは、コンフィグファイルに追記するだけで色々な認証プロバイダー(Google / X / Apple / etc…)から認証を受けることができます。SWA上で構築済みのサービスになるので、ローカルで認証を試すことができません。そこで、ダミーのモックで認証を通った状況を作ることができます。認証後の情報取得方法もローカルで動作確認できるので、非常に助かります。

APIエンドポイントへのプロキシ

SWAでは、Azure Function(Freeプランでも可)やWeb Apps(Standardプランのみ可)で作成したAPIを/apiルートと接続することができます。こちらも、SWA上で構築済みのサービスなのでローカルの開発では、SWAのプロキシを再現する必要があります(まぁ無理よな)。SWA CLIを使うことで、そのあたりの挙動も模倣して提供してもらえます。

開発環境構築

環境構築の内容に入っていきます。前提条件としては、DockerとDocker Composeコマンドが使えれば大丈夫です。最終的なファイルとしては、こちらのリポジトリに上がっています。

ディレクトリ構成としては、以下のようになります。

.
├── .devcontainer
│   └── devcontainer.json     # DevContainer環境設定
├── .dockerignore
├── .env            # local用環境ファイル
├── .github
│   └── workflows
├── Dockerfile
├── docker-compose.yml
├── my-app                    # Next.jsアプリディレクトリ
└── swa-cli.config.json       # SWA CLIコンフィグファイル
  1. Next.jsの環境づくり
  2. node_modulesをvolumeマウント化
  3. SWA CLIのセットアップ (SWA CLI Config)
  4. 静的サイト用対応( staticwebapp.config / Next.js config)

Next.jsの環境づくり

まずは、Next.jsの環境を作っていこうと思います。ここでは、Nodeの環境を作成してDevContainerでいきなりアクセスしてしまいます。三つのファイルを作成してください。

Dockerfile

ARG NODE_VER
FROM node:${NODE_VER}
RUN npm install -g npm@11.0.0
RUN npm install -g @azure/static-web-apps-cli

USER node

WORKDIR /home/node/app

docker-compose.yml

version: "3.7"
services:
  next:
    build:
      args:
        - NODE_VER=22.12.0
      context: .
      dockerfile: Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./
        target: /home/node/app

.devcontainer/.devcontainer.json

{
  "name": "procject-dev",
  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "next",
  "workspaceFolder": "/home/node/app",
  "customizations": {
    "vscode": {
      "extensions": [],
      "settings": {}
    }
  },
  "remoteUser": "node",
}

DevContainer内に入ったら、Next.jsのプロジェクトを作成します。今回は、create-next-appから提案されるmy-appで話を進めていきます。ここは任意に変更してください。

npx create-next-app@latest

これで、Next.jsの環境が作成することができました。

node_modulesをvolumeマウント化

node_modulesをvolumeマウントにすることで、コンテナ内に収めてしまいます。こちらの対応をしておくことで、元ファイル側のサイズを小さくすることができます。また、bindマウントしないことによりビルド速度を上昇させることができます。

こちらでやっていることは、「.dockerignoreでビルド時にnode_modulesをなかったことにして、Dockerfileでnode_modulesを作成してビルド、dokcer-compose.ymlでnode_modulesをボリュームマウントする」となります。Dockerファイルで作成している理由としては、dokcer-compose.ymlファイル経由で作成させるとroot権限で作成されて涙を呑むからですね。

追加で、.dockerignoreファイルを作成してください。

.dockerignore

my-app/node_modules

Dockerfile

ARG NODE_VER
FROM node:${NODE_VER}

RUN npm install -g npm@11.0.0
RUN npm install -g @azure/static-web-apps-cli

USER node

WORKDIR /home/node/app

RUN mkdir my-app
COPY --chown=node:node my-app my-app

WORKDIR /home/node/app/my-app
RUN mkdir node_modules
RUN chown node:node -R node_modules

RUN npm install

docker-compose.yml

version: "3.7"
services:
  next:
    build:
      args:
        - NODE_VER=22.12.0
      context: .
      dockerfile: Dockerfile
    tty: true
    volumes:
      - type: bind
        source: ./
        target: /home/node/app
      - type: volume
        source: node_modules
        target: /home/node/app/my-app/node_modules
volumes:
  node_modules:

ファイルの適応が完了したら、**DevContainerを必ずRebuildしてください。**以上で、node_modulesのボリュームマウント化完了です。

Next.jsのアプリを作成した際に発生したnpm installで持ってきたnode_modulesが元ファイルに残っていると思います。気になる方は、コンテナから抜け出して、元ファイルのnode_modulesを削除してください。

SWA CLIのセットアップ

SWA CLI自体は、Dockerfileのnpm globalインストールですでに導入済みです。コンテナ内で以下のコマンドで確認してください。

swa --version

バージョン情報が返ってくれば、インストール自体は完了しています。また、以下のコマンドで対話的にコンフィグファイルを作成することができます。

swa init

フレームワーク等も自動で判断して作成してもらえるので非常に便利なコマンドです。

対話的に作成しなくても、以下のファイルをコピペしてもらえれば起動することができます。

swa-cli.config.json

{
  "$schema": "<https://aka.ms/azure/static-web-apps-cli/schema>",
  "configurations": {
    "app": {
      "appLocation": "my-app",
      "run": "npm run dev",
      "appDevserverUrl": "<http://localhost:3000>"
    }
  }
}

上記のファイルを作成したディレクトリで、以下のコマンド一つでエミュレーター起動までやってもらえます。

swa start

特に設定していなければ、http://localhost:4280で起動しているかと思います。

静的サイト用対応

最後に、Next.jsとSWAそれぞれで静的サイト用の設定を追加していきます。Next.jsのコンフィグファイルを編集して静的エクスポートを有効にします。

my-app/next-config.ts

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  output: "export",
  trailingSlash: true,
};

export default nextConfig;

こちらの設定を有効にするだけで、npm run buildoutファイル内に静的ファイルが生成されます。trailingSlash: true では、静的ファイルのエクスポート時にディレクトリ/index.htmlという形式でファイルを読み込んでくれます。

次に、SWA側の設定ファイルです。こちらは、ローカル用と本番用の二つのファイルを用意します。ローカルでは、コンフィグファイルを指定して起動します。本番用のファイルはnpm run buildで静的ファイルにそのまま書き込まれるように、Next.jsのpublicディレクトリに作成します。今回は、Next.jsの設定に併せてtrailingSlashの設定のみ追加します。

ローカル:.env/local/staticwebapp.config.json

本番用:my-app/public/staticwebapp.config.json

{
    "trailingSlash": "auto"
}

最後に、SWA CLIのコンフィグファイルにローカルのstaticwebapp.config.jsonの位置を教えます。

{
  "$schema": "<https://aka.ms/azure/static-web-apps-cli/schema>",
  "configurations": {
    "app": {
      "appLocation": "my-app",
      "run": "npm run dev",
      "appDevserverUrl": "<http://localhost:3000>",
      "swaConfigLocation": ".env/local"
    }
  }
}

これでswa startでは、.env/local内のコンフィグファイルが読み込まれて実行します。

SWA deploy with GitHub Actions

事前準備としては、Azure Static Web AppsのデプロイトークンをGitHubのSecretとして保存しておく必要があります。今回は、環境 deploy内にAZURE_TOKEN として保存しているとして進めていきます。開発環境はDockerで作成しましたが、デプロイ自体はActions内でビルドしてデプロイをしています。

on:
  push:
    branches: ["main"]
  workflow_dispatch:

env:
  NODE_VERSION: "22.x" 

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: "npm"
          cache-dependency-path: my-app/package-lock.json

      - name: npm install, build, and test
        run: |
          npm install
          npm run build
        working-directory: my-app

      - name: Upload Cache app
        uses: actions/cache/save@v4
        with:
          path: my-app/out/
          key: ${{ runner.os }}-app-${{ github.sha }}

  deploy:
    runs-on: ubuntu-24.04
    needs: build
    environment: deploy
    steps:
      - uses: actions/checkout@v4

      - name: Download Cache app
        uses: actions/cache/restore@v4
        with:
          path: my-app/out/
          key: ${{ runner.os }}-app-${{ github.sha }}

      - name: Build And Deploy
        uses: Azure/static-web-apps-deploy@1a947af9992250f3bc2e68ad0754c0b0c11566c9
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          action: "upload"
          output_location: "my-app/out/"
          app_location: "my-app/out/"
          skip_app_build: true

内容としてはシンプルで、以下の順序で実行されます。

  1. ビルド
    • アプリケーションのビルド
    • 静的ファイルoutをキャッシュ
  2. デプロイ
    • キャッシュからアプリを復元
    • 静的ファイルをSWAに配信

Azure/static-web-apps-deployはビルドもアクションの中で実行してくれる優れものです。ですが、今回はCI上でビルドを実行して、デプロイのためだけに使用しています。

終わり

今回の開発環境構築で特に詰まった点としては、Next.jsで静的ファイルを配信するための設定周りですね。Next.jsとSWAでそれぞれ設定が必要な点は盲点でした。

最近は、フロントエンドの開発環境構築はCI/CDパイプラインを組むところまでやるべきなのかもしれないと思ってきましたね。次回は、バックエンドの環境構築について記載を進めておきます。Azure上で公開するための開発環境構築なんて必要そうですね。三日間ぐらいDockerと戯れすぎて、yamlファイルアレルギーになりそうです。

では2025年もよろしくお願いします。これは1月中に毎回言っておきます。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です