React(Next.js)のStatic Exports設定で認証ロジックを実装する①

## はじめに
お久しぶりです、[株式会社 ONE WEDGE](https://onewedge.co.jp/)の[@Shankou](https://qiita.com/Shankou)です。
今回はReact(Next.js)のStatic Exports設定で認証ロジックを作って行きたいと思います。

弊社ではサーバーレス開発を行っております。
ざっくりと説明するとバックエンドの処理をAWSのLambdaを使ってAPIとして実装し、フロントはAWSのS3にアップロードしたものをこれまたAWSのCloudFrontを使って配信するという形です。

案件ではVue(Nuxt.js)を使ってビルドした静的ファイルをS3にあげていますが、個人的にReactを勉強中なので、同じことをReactでどうやるの？ということをまとめてみたいと思います。

ちなみにStatic Exportsとはサーバーサイドロジックを含まず、フロントでのみ動作するようにビルドを行うモードのことです。(サーバーレス開発なので当然ですね)

そのうえで、認証ロジック、未認証ページと認証済みページの切り分け、更に認証済みページへのアクセス時に、未認証状態であれば自動でグインページに飛ばすというのをできるだけスマートにやりたいなということで、その辺りを手探りで実装しました。

今回使用しているNodeのバージョンは以下の通りです。

```
> node --version
v22.7.0
```


## プロジェクトの作成
[Next.jsのインストール](https://nextjs.org/docs/getting-started/installation)をベースにプロジェクトを作成していきます。
各質問はプロジェクト名の入力以外は初期値のまま全部Enterキー押していくだけで大丈夫です。
ちなみにApp RouterというのはReactの新しいシステム構成方式になります。

```
> npx create-next-app@latest
Need to install the following packages:
create-next-app@14.2.7

# 続行してもいいですか？ (y)
Ok to proceed? (y) y

# プロジェクト名を入力 (static-exports-sample)
? What is your project named? > static-exports-sample

# TypeScriptの利用を選択 (Yes)
? Would you like to use TypeScript? › No / Yes

# ESLintの利用を選択 (Yes)
? Would you like to use ESLint? › No / Yes

# Tailwind CSSの利用を選択 (Yes)
? Would you like to use Tailwind CSS? › No / Yes

# srcディレクトリ配下にソースファイルをまとめるかを選択 (Yes)
? Would you like to use `src/` directory? … No / Yes

# App Routerの利用を選択 (Yes)
? Would you like to use App Router? (recommended) › No / Yes

# デフォルトのインポートエイリアス記号を変更するか (No)
? Would you like to customize the default import alias (@/*)? › No / Yes
```

プロジェクトの作成が完了したらVScode等で開いてみてください。


## Static Exportsの設定
続いてStatic Exportsの設定をしていきます。
プロジェクトディレクトリ直下にある`next.config.js`を編集します。

```next.config.js
const nextConfig = {
  // Static Exportsの指定
  output: 'export',
  // 静的ファイルの生成先を指定
  distDir: 'dist',
  // 静的ファイルでの起動なので、サーバーサイドでの画像の最適化をOFF
  images: {
    unoptimized: true,
  },
}

export default nextConfig
```

`next.config.js`の設定ができたらビルドをおこなってみましょう。

```
> npm run build
```

プロジェクト直下に**dist**ディレクトリが生成されていれば成功です。
`dist`ディレクトリは`.gitignore`に入れておくといいと思います。
サーバーレス開発では、このdistの中身をS3にアップロードしています。

## ちょっとした注意点

### 環境変数(env)ファイルについて
環境変数を設定する際は、envファイルに記載する必要があるのですが、フロント側で使う環境変数には`NEXT_PUBLIC_`をプレフィックスとして付与する必要があります。
例えば以下の通りです。

```
NEXT_PUBLIC_API_BASE_URL="https://static-exports-sample.net/v1"
```

環境変数を使用する際は以下の様になります。

```
import axios from 'axios'

const instance = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_BASE_URL,
  headers: {},
})

export default instance
```

### use client
この辺りすごく面倒に感じているのですが、App RouterではデフォルトでServer Componentとして動作しようとするので、ブラウザ上でしか使用することができない変数・機能を使用するClient Componentでは、`use client`宣言を1行目に入れる必要があります。
例えば以下の通りです。

```
'use client'

import { redirect } from 'next/navigation'

export default function Top() {
  const redirectPath = '/home'
  redirect(redirectPath)
}
```

上記コードでは`next/navigation`がClient Componentでしか利用することができないため、`use client`宣言が必須となります。
他にも`useState`等のイベントハンドラーが付与されるような機能も`use client`宣言が必須となっています。

`use client`については[公式ページ](https://ja.react.dev/reference/rsc/use-client#when-to-use-use-client)に解説がありますが、正直Static Exportsなので全てのComponentに付与しておけばいいやと思っています。
Static Exports時の脳死付与について、何か副作用があるようでしたら教えてくださると助かります。

##
今回はここまで。
次回はライブラリ関連のインストールを行い、実装を進めていきます。
また、サーバーレスの認証ロジックの実装にはいろいろ注意点もあるので、その辺りのお話もしていこうと思います。

[next > ②](https://qiita.com/Shankou/items/b4f8c365e7fa5fb28fbe)