React + TS + Vite +Docker (+ Tailwind CSS ) で GitHub Pages にデプロイする

# はじめに
この記事では、React、TypeScript、Vite、Docker（+Tailwind CSS）の環境構築とGitHub Actionsを用いてGitHub Pagesにデプロイする方法を記載しています。

（Dockerをインストールしていることを前提としています。 → [Docker公式ホームページ](https://docs.docker.com/get-docker/) ）

# 開発環境
* Macbook Air（M2）
* Docker（version 25.0.3）

# 手順
## ディレクトリ構成
ディレクトリ構成は以下のようになっています。（一部省略）
```
.(root)
├ .github
|   └ workflows
|       └ deploy.yml
├ front
├ Dockerfile
└ docker-compose.yml
```
rootはGitHubのリモートリポジトリと紐付いているディレクトリです。

順番にファイルを作成していきます。

## Dockerfileの設定
ルートディレクトリにDockerfileを作成します。

以下がDockerfileの内容です。
```Dockerfile:Dockerfile
FROM node:16.17.1-bullseye

# ワーキングディレクトリを/srcに設定
WORKDIR /src

# 不必要なapt-getファイルを消去
RUN apt-get clean

# ポートを5173に設定
EXPOSE 5173
```
TypeScriptを使用するので、元のイメージは[node](https://hub.docker.com/_/node/)を使用します。

## docker-compose.ymlの設定
ルートディレクトリにdocker-compose.ymlを作成します。

以下がdocker-compose.ymlの内容です。

```yml:docker-compose.yml
# Docker Composeのバージョン
version: "3.7"

# サービスの定義
services:
  # "front"というサービスの設定
  front:
    # イメージのビルド情報
    container_name: front-app
    build:
      # Dockerイメージをビルドするためのコンテキスト
      context: .
      # Dockerfileの場所
      dockerfile: Dockerfile
    
    # ボリュームのマウント設定
    volumes:
      # ホストの"./front"ディレクトリをコンテナの"/front"にマウント
      - ./front:/front

    # 作業ディレクトリの設定
    working_dir: /front

    # コンテナ内で実行されるコマンド
    command: node

    # 公開用のポート指定。ホスト側:コンテナ側
    ports:
      - '5173:5173'

    # ttyを有効にする（コンテナと対話的なセッションを可能にする）
    tty: true
```

## アプリケーションの作成

ルートディレクトリにfrontディレクトリを作成します。
```bash:terminal
mkdir front
```

次にreactアプリケーションを作成します。

下記のコマンドでは、一時的にコンテナ内でviteのアプリケーションを作成して、作成後にコンテナを破棄します。
（frontというサービス内で`npm create vite@latest -y`を実行して、`--rm`オプションで実行後にコンテナを破棄する）

```bash:terminal
docker compose run --rm front sh -c "npm create vite@latest -y ."
```
Enterを押すとviteアプリケーションの設定を聞かれるので、今回はreactとtypescriptを選択します。
```bash:terminal
# Current directory is not empty. Remove existing files and continue?
y

## Press the down arrow key to move to the "react" item and press enter.
# Select a framework:
react

## Press the down arrow key to move to the "JavaScript" item and press enter.
# Select a variant:
typescript
```
処理が完了するとfrontディレクトリ内にreactとviteのサンプルが追加されます。

## viteの設定

`./front/vite.config.ts`を下記の内容に変更します。

```typescript:vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig({
  base:"./",
  plugins: [react()],
  server: {
    // External Publication
    host: '0.0.0.0',
    // You can change the port for starting up.
    port: 5173
  },
})
```

## コンテナの実行

Dockerとreactの設定が一通り終わったので、コンテナを起動します。

```bash:terminal
docker-compose up -d
```
コンテナ起動後、コンテナ内に入ります。

```bash:terminal
docker compose exec front sh
```

コンテナ内で、必要なパッケージをインストールします。

```sh:terminal in container
npm install
```
### Tailwind CSSを利用する場合

（Tailwind CSS を利用しない場合は飛ばして構いません。）

Tailwind CSS を利用する場合、Tailwind CSS のパッケージをインストールします。

```sh:terminal in container
npm install -D tailwindcss postcss autoprefixer && npx tailwindcss init -p
```

`./front/tailwind.config.ts`に`content`の内容を追加します。

```ts:tailwind.config.ts
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
```

`./front/index.css`を下記の内容に変更します。

```css:index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

## アプリケーションの実行

コンテナ内で下記のコマンドを実行し、サーバを立ち上げます。

```sh:terminal
npm run dev
```

ブラウザで http://localhost:5173/ を開いて、アプリケーションが動いていることを確認します。

## GitHub Actionsの設定
GitHubで使用するリポジトリを開きます。

Setting > Pages を押して、Sourceを「GitHub Actions」に変更します。

今回はStatic HTMLのワークフローを使用するので、Static HTMLのConfigureを選択します。

![GitHubActions設定画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2784580/dbb1efef-b5e1-36e2-570b-0e2890955886.png)

すると、ワークフローのテンプレートが表示されます。

ファイルの名前がデフォルトでは`static.yml`になっているので、`deploy.yml`に変更しておきます。

テンプレートの内容も下記のように変更します。

変更箇所は

* `defaults`の内容を追加（frontディレクトリの内容をデプロイするため）
* `Set up Node`の内容を追加（ビルドするため）
* `Upload artifact`の`path`を`'./front/dist'`に変更（ビルドしたファイル（distファイル）をデプロイするファイルに指定）

の３つです。

```yml:deploy.yml
# Simple workflow for deploying static content to GitHub Pages
name: Deploy static content to Pages

on:
  # Runs on pushes targeting the default branch
  push:
    branches: ["main"]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

defaults:
  run:
    shell: bash
    working-directory: ./front

# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
  group: "pages"
  cancel-in-progress: true

jobs:
  # Single deploy job since we're just deploying
  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'
          cache-dependency-path: ./front/package-lock.json
      - 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:
          # Upload entire repository
          path: './front/dist'
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2
```

環境変数などを使用している場合は、`run: npm run build`の下に下記のように追加します。
「アプリ内の環境変数名」と「GitHubで登録した環境変数名」は適宜変更してください。

```yml:deploy.yml
        run: npm run build
        env:
          アプリ内の環境変数名１: ${{ secrets.GitHubで登録した環境変数名１ }}
          アプリ内の環境変数名２: ${{ secrets.GitHubで登録した環境変数名２ }}
```

## デプロイ

ローカルで作成したアプリケーションをmainブランチにプッシュするとActionsで処理が始まります（GitHub内のActionsで処理状況が確認できます）。

処理が正常に終わるとGitHub Pagesでデプロイされたアプリを確認できます。

# まとめ
今回は、React、TypeScript、Vite、Docker（+Tailwind CSS）の環境構築とGithub Actionsを用いてGitHub Pagesにデプロイする方法を紹介しました。

今回デプロイに使用したリポジトリ：https://github.com/ayakakawabe/portfolio
デプロイ先URL：https://ayakakawabe.github.io/portfolio/

# 参考資料
* [Vite - 静的サイトのデプロイ](https://ja.vitejs.dev/guide/static-deploy.html)
* [Tailwind CSS - Install Tailwind CSS with Vite](https://tailwindcss.com/docs/guides/vite)
* [GitHub - react in docker](https://github.com/TatsuyaMaeta/react-in-docker)
* [Qiita - ReactをGitHub Pagesにデプロイしよう](https://qiita.com/tat_mae084/items/745761eee6cd1d42949d)