GitHub Actions × AWS S3：フロントエンド CI/CD の実装と .env のベストプラクティスをもとに自分なりにまとめてみた

## はじめに

この GitHub Actions のワークフローは、`develop` ブランチにプッシュされた際に実行され、フロントエンドアプリケーションを S3 にデプロイする流れになっています。

現在、ITスクールのハッカソンで、フロントエンドの CI/CD を実装しようとしています。

## **ITスクールのハッカソンでの CI/CD 構築と .env の取り扱い**  

ITスクールのハッカソンで **CI/CD を構築** する際、`.env` の取り扱いに苦戦しました。  
GitHub Secrets を活用して **環境変数を管理する方法** を模索しながら、ワークフローを組み立てました。  

特に、  
- `ENV_FILE_CONTENT` を `.env` に展開する部分  
- S3 へのアップロードの必要性  

に気付き、適切な管理方法を検討しました。  

この経験を踏まえて、**GitHub Actions のワークフロー** を整理し、共有します。

## **全体の動作**
1. リポジトリのコードを取得
2. Node.js 18 をセットアップ
3. 依存関係をインストール
4. GitHub Secrets から `.env` を作成
5. プロジェクトをビルド
6. AWS の認証情報を設定
7. ビルド成果物を S3 にアップロード
8. `.env` ファイルを S3 にアップロード
9. CloudFront のキャッシュを無効化 (オプション)

## **各ステップの動作詳細**

### **1. リポジトリのコードを取得**
```yaml
- name: Checkout repository
  uses: actions/checkout@v4
```
GitHub リポジトリの最新のコードを取得します。

### **2. Node.js 18 をセットアップ**
```yaml
- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: 18
```
Node.js 18 をセットアップし、以降の `npm` コマンドを使用できるようにします。

---

### **3. 依存関係をインストール**
```yaml
- name: Install dependencies
  run: |
    cd skill-typing-front
    npm install
```
`skill-typing-front` ディレクトリへ移動し、
`npm install` を実行し、プロジェクトの依存関係をインストール します。

---

### **4. `.env` ファイルを作成**
```yaml
- name: Create .env file
  run: |
    echo "${{ secrets.ENV_FILE_CONTENT }}" > skill-typing-front/.env
```
GitHub のシークレット (`ENV_FILE_CONTENT`) の内容を `.env` ファイルとして作成 します。
これにより、環境変数を必要とする設定ファイルが正しく動作するようになります。

---

### **5. プロジェクトをビルド**
```yaml
- name: Build project
  run: |
    cd skill-typing-front
    npm run build
```
フロントエンドのビルドを実行 (`npm run build`)
`build` ディレクトリに 本番環境用の静的ファイル (HTML, CSS, JS) が生成 されます。

---

### **6. AWS 認証情報を設定**
```yaml
- name: Configure AWS credentials
  uses: aws-actions/configure-aws-credentials@v2
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: ap-northeast-1
```
AWS の認証情報を設定し、以降の AWS CLI コマンドが実行可能になります。
`aws s3 sync` や `aws cloudfront create-invalidation` を実行するための準備です。

---

### **7. S3 にビルド成果物をデプロイ**
```yaml
- name: Deploy to S3
  run: aws s3 sync skill-typing-front/build s3://${{ secrets.S3_BUCKET_NAME }} --delete
```
S3 バケット (`S3_BUCKET_NAME`) に `build` フォルダ内のファイルをアップロード
`--delete` オプションにより、S3 上で不要になったファイルは削除される

---

### **8. `.env` ファイルを S3 にアップロード**
```yaml
- name: Upload .env file to S3
  run: aws s3 cp skill-typing-front/.env s3://${{ secrets.S3_BUCKET_NAME }}/.env
```
`.env` を S3 バケットにアップロードし、別の環境でも使用できるようにします。
S3 に `.env` を配置することで、Lambda や EC2 など他のサービスで利用可能にできます。

---

### **9. CloudFront キャッシュを無効化 (オプション)**
```yaml
- name: Invalidate CloudFront cache (Optional)
  run: |
    aws cloudfront create-invalidation --distribution-id E36GMT84PRUJQO --paths "/*"
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
  if: success()
```
S3 に新しいビルドがデプロイされた後、CloudFront のキャッシュを無効化
`--paths "/*"` により、全ファイルを最新の状態に更新
`if: success()` により、前のステップが成功した場合のみ実行

## 実際のコード

```.github/workflows/deploy.yml
name: Build and Deploy to S3

on:
  push:
    branches:
      - develop
    # paths:
    #   - 'app/**/*.js'
    #   - 'app/**/*.tsx'
    #   - 'app/**/*.css

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 18

      - name: Install dependencies
        run: |
          cd skill-typing-front
          npm install

      - name: Build project
        run: |
          cd skill-typing-front
          npm run build

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v2
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Deploy to S3
        run: aws s3 sync skill-typing-front/build s3://${{ secrets.S3_BUCKET_NAME }} --delete

      - name: Invalidate CloudFront cache (Optional)
        run: |
          aws cloudfront create-invalidation --distribution-id E36GMT84PRUJQO --paths "/*"
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        if: success()
```

## **まとめ**
この GitHub Actions のワークフローでは：
- **`develop` ブランチにプッシュされると自動実行**
- **フロントエンドをビルドし、S3 にデプロイ**
- **`.env` ファイルを S3 にアップロード**
- **CloudFront キャッシュを無効化し、最新のコンテンツを配信**

**開発者は `git push` するだけで、自動的に S3 にデプロイ & CloudFront に反映される仕組みになっています！**