Azure Static WebAppsでnext.jsのdynamic rootingを使う

Azure Static WebAppsは、静的なサイトをホスティングするためのMicrosoft Azureのサービスで、つい先日2021年5月に正式リリースされたばかりのサービスです。

プレビューリリースの段階から個人的に使って色々と試していたのですが、正式リリースの直前にルーティングに関して重要なアップデートがありましたのでその辺りを、next.jsのdynamic rooting機能を使う形で解説してみようと思います。

## next.jsとは

Vercelが開発している、next.jsはフロントエンド開発用のフレームワークです。設定不要で初期状態でSSRを利用できることで注目されたフレームワークですが、v9.3(2020/3)でSSGへの対応が追加されました。

特徴的な機能として、ファイルベースのルーティングがあります。`pages` というディレクトリにファイルを配置することでとても簡単にルーティングの設定をすることができます。

### dynamic routing

next.jsはファイルベースでroutingをすることができることはすでに書きましたが、他に dynamic routing という機能があります。

例えば以下のようにファイルを配置すると、`[articleId].tsx`を記事詳細ページとして利用できます。

```
pages
├── _app.tsx
├── _document.tsx
├── article
│   └── [articleId].tsx
├── articles.tsx
└── index.tsx
```

イメージとしてはmod_rewriteでこんな感じの設定をイメージしてもらえるとわかりやすいかも?

```
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  
  RewriteRule ^article/([0-9A-Za-z]+)$ article/[articleId].html [L]
</IfModule>
```

dynamic routingを利用することで `/article/nextjs` / `/article/azure_static_webapps` のような複数のurlを `/article/[articleId].tsx` で表示することができます。

### Server Side Generation(SSG)とClient Side Rendering(CSR)

Server Side Rendering(SSR)や、Client Side Rendering(CSR)の場合に、dynamic routingなpageをビルドすると、以下のようなhtmlが生成されます。tsxファイルがhtmlに変わり、 `_next` ディレクトリ以下に生成されたjsファイルなどが配置されます。

```
out
├── 404.html
├── _next
├── article
│   └── [articleId].html
├── articles.html
└── index.html
```

対して、Server Side Generation(SSG)の場合は少し異なります。前出の`[articleId].tsx`をSSGに対応させてみます。今回は簡易的に `/article/nextjs` と `/article/azure_static_webapps` の2ページを固定で作成してみます。

```typescript
import React from 'react'
import { NextPage } from 'next'

interface Props {
  articleId: string
}

const ArticleDetailPage: NextPage<Props> = (props) => {
  return (
    <ArticleDetailView {...props} />
  )
}

export const getStaticPaths = async () => {
  return  {
    paths: [
      {params: {articleId: 'nextjs'}},
      {params: {articleId: 'azure_static_webapps'}},
    ],
    fallback: false,
  }
}

export const getStaticProps = async ({params} : any) => {
  return {
    props: {
      code: String(params.articleId),
    },
  }
}

export default ArticleDetailPage
```

これをビルドすると以下のようなファイルが生成されます。

```
out
├── 404.html
├── _next
├── article
│   ├── nextjs.html
│   └── azure_static_webapps.html
├── articles.html
└── index.html
```

さて、ビルドすると上記で説明したような静的なhtmlが吐き出されますが、nextjsの内部のurlは拡張子なしの `/article/nextjs` のような形式になります。

このまま何も設定せずにAzure Satatic WebAppsにデプロイすると、トップページから遷移すればdynamic rootingを使用したページも問題なく表示されますが、`/article/nextjs`のようなページが表示されている状態で再読み込みをしてしまうと、該当するファイルが存在しないため404になってしまいます。

## Azure Static WebAppsのルーティングを設定する

以前は、`routes.json` というファイルでの簡易的なルーティング設定しかできませんでしたが、正式リリース時に `staticwebapp.config.json` というファイルを利用したルーティング、認証、mimeタイプの設定など色々な設定が可能になりました。

この機能を利用し下記のようなファイルをビルドディレクトリのトップに配置することで、先ほどの問題を解決することができます。

- CSRの場合

	```json
	{
	    "routes": [
	        {
	            "route": "/article/*",
	            "rewrite": "/article/[articleId].html"
	        }
	    ]
	}
	```
	
- SSGの場合

	```json
	{
	    "routes": [
	        {
	            "route": "/article/nextjs",
	            "rewrite": "/article/nextjs.html"
	        }, {
	            "route": "/article/azure_static_webapps",
	            "rewrite": "/article/azure_static_webapps.html"
	        }
	    ]
	}
	```

CSRの場合は、staticwebapp.config.jsonは固定で用意すれば良いので `public` ディレクトリに入れておけばビルド時に自動でコピーされるので問題ないでしょう。

SSGの場合は少し手間がかかりますが、該当のページの `getStaticPaths` 内などで `staticwebapp.config.json` を動的に生成する処理を実装する必要があります。

## まとめ

以上、nextjsのdynamic routingを使用したサイトをAzure Static WebAppsで利用する方法を簡単に説明してみました。

プレビュー時代には個人的なサイトでのみ利用していましたが、現在構築中のサービスでは本格的に利用を進めています。

Azure Static WebAppsはフロントエンドアプリを配信するにはとても便利なサービスですので、ぜひ試してみてください。

## 参考リンク

- [next.js](https://nextjs.org/)
	- [Dynamic Routes](https://nextjs.org/docs/routing/dynamic-routes)
- [Azure Static Web Apps の構成 (routingなどの設定)](https://docs.microsoft.com/ja-jp/azure/static-web-apps/configuration)