pnpm + Astroの構成で、GitHub Pagesにデプロイする自前のGitHub Actionsを設定する

:::note info 
本記事では、GitHub Actionsの基本的な扱い方は知っているものとして進めています。GitHub Actionsの基本的な事項は他の記事などをご参照ください。
:::

## 要約
ルートディレクトリ直下の`/frontend`フォルダにソースがあるとして、以下のようなワークフローを設定しました。mainブランチにpushされた場合（マージされた場合）にデプロイが実行されます。

参考として、以下のリポジトリのサイトはこの記事の方法でデプロイしています。

https://github.com/mochi-yu/mochi-yu.com/tree/v1.0.0

<details>
<summary>ソースコード全文</summary>

```yaml:deploy.yaml
name: Deploy to GitHub Pages

on:
  push:
    branches: [ main ]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4.1.6

      - name: Install Node.js
        uses: actions/setup-node@v4.0.2
        with:
          node-version: 20

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          package_json_file: frontend/package.json

      - name: Install packages
        working-directory: frontend
        run: pnpm install

      - name: Build
        working-directory: frontend
        run: pnpm run build

      - name: Upload Pages Artifact
        uses: actions/upload-pages-artifact@v3.0.1
        with:
          path: "frontend/dist/"

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4.0.5
```

```json:/frontend/package.json
{
  "name": "hoge",
  "type": "module",
  "version": "0.0.1",
  "packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0",
  "scripts": {
    "dev": "astro dev",
    "start": "astro dev",
    "build": "astro check && astro build",
    "preview": "astro preview",
    "astro": "astro"
  },
  "dependencies": {
    "@astrojs/check": "^0.6.0",
    "astro": "^4.8.2",
    "typescript": "^5.4.5"
  },
  "devDependencies": {
    // （省略） //
  }
}
```

</details>

## 背景
Astroで作成したWebページを、GitHub Pagesでホスティングするために、GitHub Actionsのワークフローを作成しました。

以下のドキュメントに、公式の用意したActionsの説明がありましたが、pnpmの使用＋サブディレクトリにソースがあるという少し特殊な環境ゆえか当時実装しようとしていた時にはうまく動作しませんでした。（※[こちらのPR](https://github.com/withastro/action/pull/54)で既に修正されているかもしれません）

https://docs.astro.build/en/guides/deploy/github/

そこで、`node.js`＋`pnpm`を使ってビルドしGitHub Pagesにデプロイする自前のワークフローを設定したので、それをこの記事にまとめます。

## 実装
ワークフローの流れは以下のようになっています。前半はNode.jsを使用したシンプルなビルドの手順となっていて、後半は[公式のドキュメント](https://docs.github.com/ja/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0-github-actions-%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AE%E4%BD%9C%E6%88%90)にも書かれている手順に準拠したものになっています。

1. Actionsのチェックアウト
2. Node.jsのセットアップ
3. pnpmのセットアップ
4. pnpmによる依存パッケージのダウンロード
5. `pnpm run build`によるビルド
6. GitHub Pagesへのアップロード

### `deploy.yaml`
ワークフローは以下のように定義しました。プロジェクトのソースは`/frontend`フォルダにあるものとしています。**mainブランチにPRがマージされた際**などにこの処理が実行されます。

```yaml:deploy.yaml
name: Deploy to GitHub Pages

on:
  push:
    branches: [ main ]
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4.1.6

      - name: Install Node.js
        uses: actions/setup-node@v4.0.2
        with:
          node-version: 20

      - name: Install pnpm
        uses: pnpm/action-setup@v4
        with:
          package_json_file: frontend/package.json

      - name: Install packages
        working-directory: frontend
        run: pnpm install

      - name: Build
        working-directory: frontend
        run: pnpm run build

      - name: Upload Pages Artifact
        uses: actions/upload-pages-artifact@v3.0.1
        with:
          path: "frontend/dist/"

  deploy:
    needs: build
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4.0.5
```

処理を順を追って説明します。

まず`actions/setup-node@v4.0.2`で**Node.jsのインストール**を、`pnpm/action-setup@v4`で**pnpmのインストール**をしています。

pnpmのインストールのActionでは、**pnpmのバージョンを指定する**必要があります。私の場合は後述の`package.json`内に`"packageManager"`のプロパティでバージョンを指定しています。それがない人は **`deploy.yaml`内に`version: 9`のような指定が必要**になります。詳細は以下をご確認ください。

https://github.com/pnpm/action-setup?tab=readme-ov-file#install-only-pnpm-without-packagemanager

続いて`/frontend`ディレクトリで実行することを **`working-directory: frontend`** の記述で指定し、**`pnpm install`および`pnpm build`を実行**しています。これによりデフォルトの設定では **`/frontend/dist/`以下にAstro.jsのビルド結果が出力**されます。

ビルド結果が生成されたら、それを[`actions/upload-pages-artifact`](https://github.com/actions/upload-pages-artifact)のActionを使って、アップロードします。公式の説明に従って **`path: "frontend/dist/"`で静的ファイルのパスを指定**しています。

:::note info
「どこにアップロードするの？」というのが気になって調べてみましたが、**ジョブの途中のデータをGitHub公式の提供する`Artifact`というデータ領域**にアップロードし永続化しているようでした。`actions/upload-pages-artifact`のソースコードを見ると、`actions/upload-artifact`という別のActionを実行してアップロードしています。（[参考](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts)）
:::

最後は、先ほどArtifactにアップロードした静的ファイルを実際にGitHub Pagesとしてデプロイします。これも**公式の提供している[actions/deploy-pages](https://github.com/actions/deploy-pages)のワークフローを、ドキュメントのまま実行**しています。ドキュメント曰く、アップロード時の**Artifactの名前を`artifact_name: "hoge"`のように任意に指定**することもできるようです。

### `package.json`
プロジェクトの`package.json`の中身についてもこちらに載せています。

特筆すべきなのは、Actions中の **`pnpm run build`で実行されるスクリプト**と、**`packageManager`のプロパティ**でしょうか。`pnpm run build`で実行されるスクリプトについてはデフォルトのもので、`"build": "astro check && astro build"`を設定しています。

`packageManager`のプロパティは、使用するpnpmのバージョンを指定しています。これは私が`corepack`という機能を使用しているために追加されているものです。もし`packageManager`のプロパティがない場合には、先述の通りActions中の`pnpm/action-setup`の時に**使用するpnpmのバージョンを明示しなくてはいけない**のでご注意ください。

```json:/frontend/package.json
{
  "name": "hoge",
  "type": "module",
  "version": "0.0.1",
  "packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0",
  "scripts": {
    "dev": "astro dev",
    "start": "astro dev",
    "build": "astro check && astro build",
    "preview": "astro preview",
    "astro": "astro"
  },
  "dependencies": {
    "@astrojs/check": "^0.6.0",
    "astro": "^4.8.2",
    "typescript": "^5.4.5"
  },
  "devDependencies": {
    // （省略） //
  }
}
```

## 備考
Node.jsのインストールや依存パッケージのインストールについて、**結果をキャッシュしておくことでデプロイにかかる時間が短縮できる**のかなと思います。私自身がまだActionsのキャッシュについてあまり理解できていないので、この記事では省いております。興味のある方は、ぜひ他の記事などを参考にしてください。

## 参考

https://docs.github.com/ja/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#%E3%82%B5%E3%82%A4%E3%83%88%E3%82%92%E5%85%AC%E9%96%8B%E3%81%99%E3%82%8B%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0-github-actions-%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AE%E4%BD%9C%E6%88%90

https://dev.classmethod.jp/articles/github-actions-artifacts-v4-now-generally-available/

https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts