GitHub PagesにNext.js をデプロイする

Github PagesをNext.jsで作りたく思い検索したところ次の記事が大変参考になった。

[React Next アプリを GitHub Actions で GitHub Pages にデプロイ](https://qiita.com/peaceiris/items/9c569125b25fc090c515)

この記事を中心にググりながら完成させた際の手順を以下に記す。


## まずは通常のNext.jsアプリを作る
Node.jsインストール済みの環境で下記コマンドを実行する。
ディレクトリ名はのちに作るGitHubリポジトリ名と合わせるためユーザー名.github.ioとしたがなんでもいい。

```shell:shell
mkdir ユーザー名.github.io
cd ユーザー名.github.io
npm init -y
npm install --save react react-dom next
mkdir pages
```

リンクでページ遷移をするだけのNext.jsアプリを作る。

``` jsx:pages/index.js
import Link from 'next/link'

const Index = () => {
  return (
    <>
      <div>Welcome to Next.js!</div>
      <Link href="/linkSample">
        <a>link Sample Page</a>
      </Link>
    </>
  )
}

export default Index
```

```jsx:pages/linkSample.js
export default () => (
  <div>
    <p>This is the sample page</p>
  </div>
)
```

Next.jsアプリを実行するためのスクリプトをpackage.jsonに追記する。

```json:package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
  }
```

`npm run build`コマンドでビルドしたのち、`npm run start`コマンドでNext.jsアプリを実行する。

ブラウザで`http://localhost:3000`にアクセスすると動作を確認できる。

![localhost3000.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/7450831d-d688-d079-5625-cc45ee4d3cdf.png)

![localhost3000linkSample.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/eec80424-12d7-f538-d4d5-312c72f23947.png)


## 静的なHTMLとしてNext.jsアプリを生成する

package.jsonのscriptsにexportを追記する。

```json:package.json
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "export": "next export"
  }
```



`npm run export`コマンドを実行することで、静的なHTMLとしてNext.jsアプリを生成する。

なお事前に`npm run build`コマンドでビルドしておくことが必須である。

このとき作られるoutディレクトリにHTMLファイル群があり、これらをローカルサーバーで実行することで動作を確認できる。


## ローカルサーバーで動作を確認する(省略可)

ローカルサーバーを立てるにはnpmパッケージのserveが便利。
[serveのGitHubリポジトリ](https://github.com/vercel/serve)

```shell:shell
npm install --save-dev serve
```

serveをインストールしたのち、outディレクトリ指定してを実行する。

```shell:shell
npx serve out
```

`http://localhost:5000`にアクセスすると動作を確認できる。

## .gitignore



ここまでローカルでの動作確認のため2つのコマンド`npm run build`と`npm run export`を実行した。

しかしNext.jsアプリをGitHub Pagesにデプロイする際、これらのコマンドはGitHub Actionsで実行する。

そのため、2つのコマンドによりプロジェクトルート直下に作られる`.next`ディレクトリと`out`ディレクトリはGitHubにpushする必要がない。

下のように`.gitignore`に記述しpushされないようにする。


```:.gitignore
node_modules
.next
out
```

## GitHub Actions でデプロイするための準備

GitHub Actions とはGitHubにおけるCI/CDツール。

アプリケーションルート直下に`.github/workflows/gh-pages.yml`を用意しておきGitHubにpushするだけで、GitHub Actionsが開始し、gh-pages.ymlに記述した操作が自動的に行われる。

```yml:.github/wokflows/gh-pages.yml
name: github pages

# masterブランチにプッシュしたときjobsに記述した操作を行う
on:
  push:
    branches:
    - master

jobs:
  build-deploy:
    # ubuntu OS を仮想マシン上に用意する
    runs-on: ubuntu-18.04
    steps:
    - uses: actions/checkout@v2

    # Node.js環境のセットアップを行う
    - name: setup node
      uses: actions/setup-node@v1
      with:
        node-version: '12.x'
    
    # npm install の際にキャッシュを使うよう設定
    - name: Cache dependencies
      uses: actions/cache@v1
      with:
        path: ~/.npm
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-

    # package.jsonに基づき依存パッケージをインストールする
    - name: install
      run: npm install --frozen-lockfile

    # Next.jsアプリをビルドする
    # プロジェクトルート直下に.nextディレクトリができる
    - name: build
      run: npm run build

    # 静的なHTMLとしてNext.jsアプリを生成する
    # プロジェクトルート直下にoutディレクトリができる
    # そのなかに、HTMLファイル群と、それらが読み込むJSファイル群を収めた_nextディレクトリがある
    - name: export
      run: npm run export

    # しかしGitHub Pagesの仕様として_から始まるディレクトリが見えず404となる
    # つまりHTMLからJSを読み込めない
    # これを回避するために.nojekyllファイルをoutディレクトリに作る
    - name: add nojekyll
      run: touch ./out/.nojekyll

    # gh-pagesブランチにoutディレクトリの中身をプッシュする
    # gh-pagesブランチは自動的に作成される
    - name: deploy
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./out
```


## GitHubリポジトリを作りプッシュする
`ユーザー名.github.io`リポジトリを作る。

他のリポジトリ名でもよいが、その場合GitHub PagesのURLが`https://ユーザー名.github.io/リポジトリ名`となる。

`https://ユーザー名.github.io` をURLにするならリポジトリ名を`ユーザー名.github.io`とする。

このリポジトリのmasterブランチにこれまで作ったものをpushすると、GitHub Actionsが開始され、上記`gh-pages.yml`に記述した操作が自動的に開始されるので、終了するまで待つ。

## GitHub Pages のSourceを変更する

`ユーザー名.github.io`リポジトリのSettingsページに移動する。

下へスクロールすると、GitHub PageのSourceを設定する項目があるので、`Branch:gh-pages` `/(root)`に変更する。
![gh-pages.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/d5537a0c-67a7-5ee2-e611-dfae050799c3.png)

## 完成
`https://ユーザー名.github.io`にアクセスすると、GitHub Pagesにデプロイした
Next.jsアプリを見れる。

静的なHTMLファイルとしてデプロイしたが、動的ルート、プリフェッチ、プリロード、動的インポートなど、Next.jsのほぼすべての機能をサポートしているとのこと。

[Static HTML Export | Next.js](https://nextjs.org/docs/advanced-features/static-html-export)

クライアントサイドのページ遷移ができるか、次の方法で簡単に検証できる。

>・ブラウザの開発者ツールを使って、<html> の background CSS プロパティを yellow に変更します。
>・リンクをクリックして、2 つのページ間を進んだり戻ったりしてください。
>・黄色の背景が、ページ遷移の間にも持続していることがわかります。
>
>これは、ブラウザがページ全体をロードしているのではなく、クライアントサイドでのナビゲーション（ページ遷移）が機能していることを示しています。

> 出典: [大幅にリニューアルされた Next.js のチュートリアルをどこよりも早く全編和訳しました](https://qiita.com/thesugar/items/01896c1faa8241e6b1bc)

上記の検証を完成したGitHub Pagesで行うと

![yellow1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/534fb3d4-558e-7315-c694-1752a9305be0.png)

![yellow2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596144/0ce1ed4d-dfa5-f25c-a6d7-263c50ec2b7b.png)

Next.jsのクライアントサイドでのページ遷移が行われていることがわかる。



 
## 参考
[React Next アプリを GitHub Actions で GitHub Pages にデプロイ]
(https://qiita.com/peaceiris/items/9c569125b25fc090c515)
[Next.jsで作ったアプリをGitHub Pagesにデプロイする](https://qiita.com/ozaki25/items/fe9912fc41c3a5c5bfea)
[大幅にリニューアルされた Next.js のチュートリアルをどこよりも早く全編和訳しました](https://qiita.com/thesugar/items/01896c1faa8241e6b1bc)
[Next.jsチュートリアル翻訳](https://qiita.com/tetsutaroendo/items/31300a5e475688a2f4ec)
[GitHubの新機能「GitHub Actions」で試すCI/CD]
(https://knowledge.sakura.ad.jp/23478/)
[GitHub Actionsのドキュメント](https://docs.github.com/ja/actions)
[GitHub Actions でキャッシュを使った高速化](https://www.kaizenprogrammer.com/entry/2019/12/15/220137)
[Static HTML Export | Next.js](https://nextjs.org/docs/advanced-features/static-html-export)
[Deployment | Next.js](https://nextjs.org/docs/deployment)