NextjsでSSGをしてSWA CLIを使って、Azure Static Web Appsに簡単デプロイ（ローカル上でSSG確認する方法付き）

# 目次
- [概要](#概要)
- [環境](#環境)
- [手順](#手順)
  - Nextjsプロジェクトの立ち上げ
  - フロントのコード修正
  - SWAのCLIのインストールと設定
  - ローカル上でビルドし挙動を確認
  - デプロイ
- [まとめ](#まとめ)

# 概要
- Azure Static Web Appsは[SWA CLI](https://azure.github.io/static-web-apps-cli/)を提供しており、SWA CLIを使用すると簡単に静的サイトをデプロイできます。
- 今回はNextjsでSSGをしたものをデプロイする手順を説明します。
    - SSGは画面を表示してからデータを取得するのではなく、buildのタイミングでデータを取得し、実際のページではデータを取得された状態で表示するような機能となります。
- 今回実装の[Githubリポジトリ](https://github.com/kazuya-takada/swa-cli-nextjs-ssg)はこちらになります。

# 環境
```bash
"node": "16.20.0" # node18系だと、PowerShellでSWA CLIが上手く動作しないため、16系にしています。なお、WSL2ではnode18系でも問題なく動作します
"next": "13.2.4"
"static-web-apps-cli": "1.1.1"
```
# 手順
## 1. Nextjsプロジェクトの立ち上げ
- Nextjsプロジェクトを立ち上げます。対話形式になるので、今回はnameを`swa-nextjs-ssg`にするほか、以下の設定とします。
    ```bash
    $ npx create-next-app --typescript ♯ 実行コマンド
    ✔ What is your project named? … swa-nextjs-ssg # swa-nextjs-ssg
    ✔ Would you like to use ESLint with this project? … No / Yes # Yes
    ✔ Would you like to use `src/` directory with this project? … No / Yes # Yes
    ✔ Would you like to use experimental `app/` directory with this project? … No / Yes # No
    ✔ What import alias would you like configured? … @/* # そのまま
    ```

- 今回は余計なスタイルを省きたいので、`src/styles/globals.css`の中身を空にします。
- また、`src/pages/api`については使用しないため、削除します。
- 以下実行し、localhost:3000で立ち上がることを確認しましょう。
    ```bash
    $ cd swa-nextjs-ssg
    $ npm run dev
    ```
- 問題なく立ち上げることを確認したら、Ctrl+Cで閉じます。

## 2. フロントのコード修正
- 今回は[JSONPlaceholder](https://jsonplaceholder.typicode.com/)からユーザー情報を取得し、表示させる簡単なページを実装します（SSGで）。
- `src/pages/index.tsx`を以下のように書き換えます。
    ```tsx
    // src/pages/index.tsx
    import { GetStaticProps, NextPage } from "next";
    
    type User = {
      id: number;
      name: string;
      username: string;
      email: string;
      address: {
        street: string;
        suite: string;
        city: string;
        zipcode: string;
        geo: {
          lat: string;
          lng: string;
        };
      };
      phone: string;
      website: string;
      company: {
        name: string;
        catchPhrase: string;
        bs: string;
      };
    };
    
    type HomeProps = {
      users: User[];
    };
    
    export const getStaticProps: GetStaticProps<{ users: User[] }> = async () => {
      const res = await fetch("https://jsonplaceholder.typicode.com/users");
      const users: User[] = await res.json();
    
      console.log("SGで取得したusers(1人目)", users[0]); // build時にデータ取得されることを確認するため、記述しておく
    
      return {
        props: {
          users,
        },
      };
    };
    
    const Home: NextPage<HomeProps> = ({ users }) => {
      return (
        <div>
          {users.map((user) => (
            <li key={user.id}>
              {user.id} - {user.name} - {user.email} - {user.address.city}
            </li>
          ))}
        </div>
      );
    };
    
    export default Home;
    ```

## 3. SWAのCLIのインストールと設定
- 以下コマンドでSWA CLIをインストールします。
    ```bash
    $ npm install -D @azure/static-web-apps-cli
    ```
- 設定を行うのにinitコマンドが用意されているため実行します。また、対話形式となるので、設定をおこないます。

    ```bash
    $ swa init # 実行するコマンド
    
    Welcome to Azure Static Web Apps CLI (1.1.1)
    
    ✔ Choose a configuration name: … swa-nextjs-ssg　
    
    # フォルダ構成から、Nextjsプロジェクトであること検知してくれる。
    Detected configuration for your app:
    - Framework(s): React, Next.js
    - App location: .
    - Output location: .next
    - API location:
    - App build command: npm run build
    - API build command:
    - App dev server command: npm run dev
    - App dev server URL: http://localhost:3000
    
    - API dev server URL:
    
    # ただし、修正箇所があるので、下記でnoを選択
    ✔ Are these settings correct? … no
    
    # build location以外はそのままでOK
    ✔ What's your app location? … .
    ✔ What's your build output location? … out # build出力先だけ、.nextではなくoutに変更する
    ✔ What's your API location? (optional) …
    ✔ What command do you use to build your app? (optional) … npm run build
    ✔ What command do you use to build your API? (optional) …
    ✔ What command do you use to run your app for development? (optional) … npm run dev
    ✔ What's your app development server URL (optional) … http://localhost:3000
    ✔ What's your API development server URL (optional) …
    
    Configuration successfully saved to swa-cli.config.json.
    
    Get started with the following commands:
    - Use swa start to run your app locally.
    - Use swa build to build your app.
    - Use swa deploy to deploy your app to Azure.
    ```
- すると、以下のような設定用の`swa-cli.config.json`ファイルが自動で出来上がります。
    ```json
    {
      "$schema": "https://aka.ms/azure/static-web-apps-cli/schema",
      "configurations": {
        "swa-nextjs-ssg": {
          "appLocation": ".",
          "outputLocation": "out",
          "appBuildCommand": "npm run build",
          "run": "npm run dev",
          "appDevserverUrl": "http://localhost:3000"
        }
      }
    }
    ```
- Nextjsのbuildコマンド変更するため、`package.json`を修正します。また、このタイミングでdependenciesなども修正します。
    - NextjsではSSRという機能があるのですが、Azure Static Web AppsでSSRを使用できないため、buildコマンドを修正します。
    - なお、[プレビュー版](https://learn.microsoft.com/ja-jp/azure/static-web-apps/deploy-nextjs-hybrid)ではSSRが使用できるようです。
    ```bash
    // package.json
    {
      "name": "swa-nextjs-ssg",
      "version": "0.1.0",
      "private": true,
      "scripts": {
        "dev": "next dev",
        "build": "next build && next export",　// 変更
        "start": "next start",
        "lint": "next lint"
      },
    　// typescriptなどをdependenciesから、devDependenciesに移動
      "dependencies": {
        "next": "13.2.4",
        "react": "18.2.0",
        "react-dom": "18.2.0"
      },
      "devDependencies": {
        "@azure/static-web-apps-cli": "^1.1.1",
        "typescript": "5.0.3",
        "@types/node": "18.15.11",
        "@types/react": "18.0.31",
        "@types/react-dom": "18.0.11",
        "eslint": "8.37.0",
        "eslint-config-next": "13.2.4"
      }
    }
    ```
- `npm install`を行います。

## 4. ローカル上でビルドし、挙動を確認
- ローカル上でSWA CLIのbiludコマンドを行い、挙動を確認します。
    ```bash
    swa build # 実行するbuildコマンド
    
    Welcome to Azure Static Web Apps CLI (1.1.1)
    
    Using configuration "swa-nextjs-ssg" from file:
      swa-nextjs-ssg/swa-cli.config.json
    
    Build configuration:
    - App location: .
    - API location:
    - Output location: out
    - App build command: npm run build
    - API build command:
    Building app with npm run build in . ...
    
    > swa-nextjs-ssg@0.1.0 build
    > next build && next export
    
    info  - Linting and checking validity of types
    info  - Compiled successfully
    info  - Collecting page data
    # 下記のようにsrc/pages/index.tsxに記載したconsole.logで値が確認できて、buildのタイミングでデータ取得していることを確認できる。
    info  - Creating an optimized production build ...SGで取得したusers(1人目) [
      id: 1,
      name: 'Leanne Graham',
      username: 'Bret',
      email: 'Sincere@april.biz',
      address: {
        street: 'Kulas Light',
        suite: 'Apt. 556',
        city: 'Gwenborough',
        zipcode: '92998-3874',
        geo: { lat: '-37.3159', lng: '81.1496' }
      },
      phone: '1-770-736-8031 x56442',
      website: 'hildegard.org',
      company: {
        name: 'Romaguera-Crona',
        catchPhrase: 'Multi-layered client-server neural-net',
        bs: 'harness real-time e-markets'
      }
    }
    info  - Generating static pages (3/3)
    info  - Finalizing page optimization
    
    Route (pages)                              Size     First Load JS
    ┌ ● /                                      327 B          73.6 kB
    ├   /_app                                  0 B            73.3 kB
    └ ○ /404                                   182 B          73.5 kB
    + First Load JS shared by all              73.3 kB
      ├ chunks/framework-cda2f1305c3d9424.js   45.2 kB
      ├ chunks/main-0ecb9ccfcb6c9b24.js        27 kB
      ├ chunks/pages/_app-5fbdfbcdfb555d2f.js  296 B
      ├ chunks/webpack-8fa1640cc84ba8fe.js     750 B
      └ css/ef46db3751d8e999.css               20 B
    
    ○  (Static)  automatically rendered as static HTML (uses no initial props)
    ●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
    
    info  - Creating an optimized production build ..info  - using build directory: /swa-nextjs-ssg/.next
    info  - Copying "static build" directory
    info  - No "exportPathMap" found in "/swa-nextjs-ssg/next.config.js". Generating map from "./pages"
    info  - Launching 11 workers
    info  - Copying "public" directory
    info  - Exporting (3/3)
    # buildが成功し、outフォルダに格納される
    Export successful. Files written to swa-nextjs-ssg/out
    ```

- buildで生成されたoutフォルダを実行し、表示を確認します。
    ```bash
    $ swa start out # 実行するコマンド
    
    Welcome to Azure Static Web Apps CLI (1.1.1)
    
    ***********************************************************************
    * WARNING: This emulator may not match the cloud environment exactly. *
    * Always deploy and test your app in Azure.                           *
    ***********************************************************************
    
    [swa]
    [swa] Serving static content:
    [swa]   /swa-nextjs-ssg/out
    [swa]
    [swa] Azure Static Web Apps emulator started at http://localhost:4280. Press CTRL+C to exit. # localhost:4280で起動する
    [swa]
    [swa]
    ```
- ここであくまで、`localhost:3000`ではなく、`localhost:4280`で立ち上がります。（以下説明は読み飛ばしてもOKです。）
    - 今回は意識しませんが、Azure Static Web AppsはAzure Functionsと統合することもでき、両方とも同じドメインで実行することができます。
        - イメージ：`https://hoge.com`、バックエンド：`https://hoge.com/api/users`
        - そのため、SWA CLIでは本番と同じ構成にするため、例えばNextjsでは`localhost:3000`立ち上がり、Azure Functionsでは`localhost:7071`で立ち上がるものを統合し、イメージとしてはフロント`localhost:4280`、バックエンド：`localhost:4280/api/users`の構成となります。
        - 今回はAzure Functionsは実装せず、フロントのみの実装ですが、本番と同じ状況をローカルでも再現したうえでNextjsのSSGの動作を確認したいため、`swa build`、`swa start`のコマンドを実行し、挙動を確認しています。
- `localhost:4280`を確認します。下記の画像のように、JSONPlaceholderから取得した値が表示されていること。buil時にデータを取得しているため、あらためてデータ取得処理が走っていないことを確認できました。これでローカル上でSSGの挙動を確認にすることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883992/83f7e35b-2020-066a-13b5-c59cc52b53a6.png)

## 5. デプロイ
- 上記まででローカル上でSSGの挙動を確認することができたので、実際にデプロイを行います。
- `.env`ファイルを作成し、デプロイ用の設定を書き込みます。
    ```bash
    SWA_CLI_APP_NAME=swa-nextjs-ssg 
    AZURE_TENANT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # Azureのテナントid
    AZURE_SUBSCRIPTION_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # サブスクリプションid
    AZURE_RESOURCE_GROUP=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # デプロイするリソースグループを指定
    AZURE_REGION_LOCATION=eastasia # リージョンの指定。今回はeastasiaをしています。
    SWA_CLI_DEPLOY_ENV=Production # デプロイ環境。デフォルトではPreview環境となりますが、今回は本番環境に直接デプロイするため、Productionに変更します。
    ```
- それでは以下コマンドでデプロイを行います。
    ```bash
    $ swa deploy --no-use-keychain # 実行するコマンド
    
    Welcome to Azure Static Web Apps CLI (1.1.1)
    
    Using configuration "swa-nextjs-ssg" from file:
      /swa-nextjs-ssg/swa-cli.config.json
    
    Deploying front-end files from folder:
      /swa-nextjs-ssg/out
    
    Checking Azure session...
    ✔ Successfully logged into Azure!
    
    Checking project "swa-nextjs-ssg" settings...
    ✔ Successfully setup project!
    
    Deploying to environment: Production
    
    Deploying project to Azure Static Web Apps...
    ✔ Project deployed to https://lemon-wave-0e131ed00.2.azurestaticapps.net 🚀　# デプロイに成功するとURLが発行される。
    ```
- デプロイされたURLにアクセスし確認し、デプロイされたことを確認できました♪
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883992/458198ed-7a73-ef33-298f-fdfa0a21e73d.png)

# まとめ
- 以上がNextjsでSSGをしたものをSWA CLIをつかってローカル上で確認する方法。そして、実際にAzure Static Web Appsにデプロイするまでの流れとなります。
- 上記手順については簡単にできる＆Freeプランで行えますので、ぜひお試しください！
- 補足と注意点
    - SWA CLIを使用してデプロイする場合は自分が確認する限り、現状Standardプランでデプロイするオプションがありません。
    - そのため、ファイルのサイズ制限を超えてしまう場合やStandardプランの機能を使いたい場合はSWA CLI以外のデプロイ方法をとる必要があると思われますのでご注意ください。