【Github Actions】Vite+Reactのプロジェクトを自動デプロイしてみた【github Pages】

## はじめに
viteでReactの環境を整えるところまでは順調にできたものの、いざgithub Pagesにデプロイしようとしたところでbuildしたものをどう扱えばいいか戸惑い、手が止まってしまいました。buildしたdistファイルをそのままコミットするわけにもいかず...。
そう思って少し調べたら、vite公式がgithub Actionsを使ってデプロイする方法をまとめてくれていました。優秀ですね。
せっかくなので、自分なりに行ったみちすじを残しておこうと思います。

## どうしてうまくデプロイできないのか
どうして簡単にデプロイできないのかの理由は主にこの2つです。

### 問題1：distファイルをコミットしたくない
gitで管理しているものは、できれば開発に関係ないものはcommitしたくありません。
そのため、buildしたときに生成されるdistフォルダなどはcommitしたくありません。
同じような理由でnode_modulesフォルダなどは`.gitignore`でcommitしないように管理しています。
ですが、Reactのようなbuildを前提としたものはbuildで生成されたものでなければ、github Pagesは正しく表示してくれません。

### 問題2：github PagesのURLにリポジトリ名が含まれる
gitHub PagesのURLは `https://<ユーザー名>.github.io/<リポジトリ名>/` となっており、buildしたものをそのままデプロイしてもリポジトリ名の部分のbasepathがない`https://<ユーザー名>.github.io/**.js`のURLを読み込むため正しくファイルが読み込めません。

では、どのように解決すればいいのでしょうか。
1. github Actionsでpushしたときにdistファイルをデプロイしてもらう
1. viteにbuildの生成物のパスを書き換えてもらう

この方法で簡単に、むしろ以前より楽にデプロイできました。
ここから解説します。

## 設定方法
### 1. vite.config.jsを設定する
viteでプロジェクトを作成したとき、できていた`vite.config.js`ですが、調べてみるとできることがいろいろあるようで超優秀でした。
今回はbasepathの設定のみ記載しますが、生成されるファイル名の設定やpublicディレクトリなどの細かい設定もでき自分好みにカスタマイズできたので、気になる方はご自身で調べてみてください。

修正前の`vite.config.js`はこちら。

```vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
})
```

`defineConfig`の中身を書き換えていきます。

```diff_javascript:defineConfig
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

// https://vitejs.dev/config/
export default defineConfig({
+ base: process.env.GITHUB_PAGES ? 'REPOSITORY_NAME' : './',
  plugins: [react()],
})
```

basepathをgithubのときにリポジトリ名を設定するように修正しました。

### 2. github Actionsの設定
github Actionsの設定をしていきます。
githubのActionsページを開き、「New Workflow」ボタンを押下します。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355772/e8302f62-4345-afbe-4f28-58584f22e203.png)

次に「set up a workflow yourself」を押下すると設定用のファイルが作成されます。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3355772/ace1308f-e1c7-12e7-fd84-129121f01882.png)

設定ファイルの内容は[vite公式ドキュメント](https://ja.vitejs.dev/guide/static-deploy.html#github-pages)の例を参考に記載していきます。
ファイル名は変更してもかまいません。私は`actions.yml`で作成します。

```actions.yml
# 静的コンテンツを GitHub Pages にデプロイするためのシンプルなワークフロー
name: Deploy static content to Pages

on:
  # デフォルトブランチを対象としたプッシュ時にで実行されます
  push:
    branches: ['main']

  # Actions タブから手動でワークフローを実行できるようにします
  workflow_dispatch:

# GITHUB_TOKEN のパーミッションを設定し、GitHub Pages へのデプロイを許可します
permissions:
  contents: read
  pages: write
  id-token: write

# 1 つの同時デプロイメントを可能にする
concurrency:
  group: 'pages'
  cancel-in-progress: true

jobs:
  # デプロイするだけなので、単一のデプロイジョブ
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Set up Node
        uses: actions/setup-node@v3
        with:
          node-version: 18
          cache: 'npm'
      - name: Install dependencies
        run: npm install
      - name: Build
        run: npm run build
      - name: Setup Pages
        uses: actions/configure-pages@v3
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v2
        with:
          # dist リポジトリーのアップロード
          path: './dist'
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2
```

できたらファイルをcommitして完成です。

## 最後に
今回はじめてgitHub Actionsとvite.configを修正して運用してみましたが想像以上に楽でした。
私はdemoブランチを作成してmergeしたらデプロイするようにしたり、vite.config.jsのカスタムを自分好みに修正してみたり。
私のvite.config.jsをのせておくので、改善点やおすすめの設定などあったら教えてくれると私の開発がはかどります。

<details><summary>vite.config.js</summary>

```vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';

// https://vitejs.dev/config/
export default defineConfig({
  base: process.env.GITHUB_PAGES ? 'REPOSITORY_NAME' : './',
  root: 'src',
  publicDir: '../public',
  build: {
    outDir: '../dist',
    emptyOutDir: true,
    rollupOptions: {
      output: {
        entryFileNames: `[name].js`,
        chunkFileNames: `modules/[name].js`,
        assetFileNames: (assetInfo) => {
          if (/\.( gif|jpeg|jpg|png|svg|webp| )$/.test(assetInfo.name)) {
            return 'assets/images/[name].[ext]';
          }

          if (/\.css$/.test(assetInfo.name)) {
            return 'assets/css/[name].[ext]';
          }

          return 'assets/[name].[ext]';
        }
      }
    }
  },
  plugins: [react({ jsxImportSource: '@emotion/react' })]
});
```

</details>

最後まで見ていただき、ありがとうございました。