Next.js + firebaseでSSR、SSG、ISRがサポートされたので試してみる

# 概要

2022年10月18日に発表されたこの機能を試してみました

https://www.publickey1.jp/blog/22/googlefirebase_hostingnextjsangular_universalwebfirebase_summit_2022.html

結論としては、firebase hosting へデプロイするだけで、SSR用のcloud functionsが作成され、SSGやISRも問題なく利用できました。

## 注意事項

注意点としては、ガイドにもあるように、まだプレビュー版というところで本番に導入するのは時期尚早なのかなというところです。個人開発のようなライトなサービスで、試してみるには価値があると思います。

:::note warn
注:フレームワーク対応のホスティングは、初期のパブリック プレビューです。これは、下位互換性のない方法で機能が変更される可能性があることを意味します。プレビュー リリースは、SLA または非推奨ポリシーの対象ではなく、限定的なサポートまたはサポートを受けられない場合があります。
:::

## 前提事項

以下が前提になるため注意してください。

- firebase のバージョンは、11.16.1を利用しました。11.14以上で利用可能とありましたが、どっかで11.16以上がいいみたいな記事を見ました（うろ覚え）。
- firebaseのプロジェクトは、Blazeにアップグレードしておく必要があります。

# 方法

これを参考にやってみました

https://firebase.google.com/docs/hosting/nextjs

プロジェクト作る(プロジェクト名は、nextjs-firebaseという名前で作りました)

```
% npx create-next-app@latest
```

移動する

```
% cd nextjs-firebase 
```

コード書く

**付録参照**

firebaes を初期化する

```
% firebase init hosting
```

firebaseにデプロイする

```
% yarn build && firebase deploy
```

# 結果

デプロイ時のログで、SSR/SSG/ISRが有効になっていることがわかる

```
λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)
●  (SSG)     automatically generated as static HTML + JSON (uses getStaticProps)
   (ISR)     incremental static regeneration (uses revalidate in getStaticProps)
```

ローカルの .firebase ディレクトリにも functions が自動で作成されている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38174/a247702d-5697-8233-b510-1cabc04ecb4a.png)

firebase コンソールからも functions が自動生成されていることがわかる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38174/d14c540a-03a3-a638-a513-205af1374e88.png)

# 付録

## サンプルコード

### SSR

`getInitialProps` or `getServerSideProps`が利用されているとfirebaseが自動的にSSR用のcloud functions(ssr)を生成するようです。

```
import {GetServerSideProps} from 'next';

const SSR = (props: { now: string; }) => {
    return (
        <>
            <p>SSR: {props.now}</p>
        </>
    );
};

export default SSR;

export const getServerSideProps: GetServerSideProps = async () => {
    return {
        props: {
            now: new Date().toISOString(),
        },
    };
};
```

### SSG

`getStaticProps`が利用されていると、SSGとして処理されるようです。

```
import {GetStaticProps} from 'next';

const SSG = (props: { now: string; }) => {
    return (
        <>
            <p>SSG: {props.now}</p>
        </>
    );
};

export default SSG;

export const getStaticProps: GetStaticProps = async () => {
    return {
        props: {
            now: new Date().toISOString(),
        },
    };
};
```

### ISR

`getStaticProps` + `revalidate`が利用されていると、ISRとして処理されるようです。
`revalidate`は、秒数なので単位に注意する。

```
import {GetStaticProps} from 'next';

const ISR = (props: { now: string; }) => {
    return (
        <>
            <p>ISR: {props.now}</p>
        </>
    );
};

export default ISR;

export const getStaticProps: GetStaticProps = async () => {
    return {
        props: {
            now: new Date().toISOString(),
        },
        revalidate: 120,
    };
};
```

### SWR (おまけ)

関係ないところですが、SWRが動くかも検証しました。結論としては、動きますが今回の件に関係ないのと、以前から動いていたとおもわれるためおまけとしました。

:::note warn
`refreshInterval`は、ms(ミリ秒)指定なので、ISRと単位が異なることに注意
:::

パッケージの導入も必要です

```
yarn add swr
```

```
import useSWR from "swr"

const fetcher = (url: string) => fetch(url).then((res) => res.json())

const SWR = () => {
    const {data, error} = useSWR(
        "/api/hello",
        fetcher,
        {
            refreshInterval: 20000,
        }
    );
    console.log(data)
    if (error) return <>An error has occurred.</>;
    if (!data) return <>Loading...</>;

    // @ts-ignore
    return (
        <>
            <p>{data.now} (API)</p>
        </>
    );
};

export default SWR
```


## 参考資料

https://zenn.dev/gladevise/articles/nextjs-firebase-hosting