ViteアプリをS3とCloudFrontを使ってホストする

# はじめに
Viteを用いて作成したReact×TypeScript環境をAWSのS3とCloudFrontを用いて静的ウェブサイトを公開します。説明にReactを使うだけでS3に置くのは静的ファイルなので他の環境でも同様の方法で再現可能です(記事ではReactのコードにほとんど触れません)。
何を行っているかが分かりやすいという観点から、awsコンソール上からの操作で設定していきます。また、今回最小限の設定で構築しました。お好みで設定を加えてお使いください。

# 開発環境のセットアップ
Viteの環境はワンラインで作ることが出来ます。
```shell
npm create vite@latest
```
コマンドラインに従って入力を進めると環境を作成できます。
作成した環境に入って`npm install`、`npm run dev`を行って動作を確認してください。
ブラウザで以下のような画面を確認できたら完了です。
![スクリーンショット 2022-12-17 18.47.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/04dc2be6-0894-4cd6-1f28-3d0d1ce6168f.png)
`npm run build`を行うと、`dist`配下にバンドルされたファイルが出力されます。このファイルたちが今回公開するファイルとなります。

# S3にファイルを設置する
awsのコンソールにログインして、s3バケットを作成します。バケット名には適当な名前、リージョンは住んでいるところから近い東京にします。
![スクリーンショット 2022-12-17 19.11.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/bb4edb9c-a655-5565-a41a-2e4607cf90f5.png)
作成後はテストのためにbuild配下のファイルをアップロードしておきます。アップロード後は以下のようになります。
![スクリーンショット 2022-12-17 19.25.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/3865f36e-c8a3-4365-b2c2-64c60a981cd5.png)

# Cloud Frontで配信する
Cloud Frontの画面を開いてディストリビューションを作成します。オリジンドメインに先ほど作成したs3バケットを選択してください。
![スクリーンショット 2022-12-17 19.27.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/108fbb4d-1773-c075-8bc7-16c381b5d6a0.png)
次にS3バケットアクセスの設定を行います。この記事ではOACを用いて設定します。
![スクリーンショット 2022-12-17 21.01.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/ffe21e9e-c4a0-d44c-860f-2179e2efcf0a.png)
Origin access control settingsを選択後、コントロール設定を作成を押してOACを作成します。基本的には何も手を加えず作成で問題ないです(Cloud Frontの設定後にS3バケットポリシーを更新します)。
![スクリーンショット 2022-12-17 21.02.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/f981d7d3-44d5-e24c-759a-f346c324b498.png)
最後にデフォルトルートオブジェクトをindex.htmlに設定すれば完了です。
![スクリーンショット 2022-12-17 19.31.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/96dfcb44-c56e-fd96-15a9-87adf14d4bcd.png)
一番簡単な構成を目指したので今回は行いませんでしたが、カスタムドメインを使用したい場合やCloud Frontのログ、HTTPSなどの設定を行えます。

ディストリビューションの作成後に設定するS3バケットポリシーをコピーできるのでコピーしてください。
![スクリーンショット 2022-12-17 21.07.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/f7dd7616-dd54-50ad-feaf-fd46f441b8e4.png)
見逃してしまった場合はオリジンタブを開いて作成したオリジンを編集するページに移ると表示されるところから参照できます。
![スクリーンショット 2022-12-17 21.08.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/24a48e39-65a6-da90-97b1-86d123eb9ca0.png)
コピーしたポリシーはS3の設定で適応します。対象のバケットのページにアクセスして、アクセス許可を開きます。そこでバケットポリシーを編集できるのでペーストしてください。変更の保存ができたら完了です。


これでs3とCloud Frontを使ったホストを行う設定の完了です。Cloud Frontのページにディストリビューションドメイン名が表示されているのでそこにアクセスしてください。
![スクリーンショット 2022-12-17 21.11.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/bf4f0455-2d2b-01ee-2575-5382bee1dd0b.png)

アクセスすると、最初に`npm run dev`で見たページが見れるはずです。
![スクリーンショット 2022-12-17 21.11.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/4e7e9d2e-186f-7d49-d10d-9c62fa687d59.png)

# Github ActionsでCDを組む
Github Actionでmain branchにマージされたらマージした内容がサイトに反映されるようにします。
まずGithubのリポジトリを作りましょう。入力する必要があるのは名前だけです。
![スクリーンショット 2022-12-17 21.16.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/bccc7c5b-bd52-1720-fa74-219eb0820d1b.png)
完了したらこの部分をコピーして最初に作ったVite環境にペーストしてください。`git add README.md`は`git add .`に変更すると楽です。変更しなかった場合はvite-project全体をGithub Repositoryにpushしてください(.gitignoreされているものは除く)。
![スクリーンショット 2022-12-17 21.16.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/fea0ebf0-5cc0-2a6b-0a0f-073e9d18c393.png)
リロードしてファイルがこうなっていたら準備完了です。
![スクリーンショット 2022-12-17 21.20.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/4f0a613b-50ed-3b71-d11b-de5a44c54df7.png)

Github Actionsを組んでいきます。node環境の準備、`npm ci`でパッケージのインストール、`npm run build`でファイルのビルド、ビルドしたファイルをS3アップロードの順番で行うようにします。ファイルをS3に上げるには権限が必要なのでまずGithub Actionsで使うIAMユーザーを作成します。IAMのページからユーザーを追加で行えます。
![スクリーンショット 2022-12-17 21.37.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/d197516e-71e4-06c7-6ea9-af1044f89e3b.png)

ユーザー名を適当に入力して、CLIから使用したいのでアクセスキー・プログラムによるアクセスを選択します。
![スクリーンショット 2022-12-17 21.33.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/f7fff471-a40e-fb99-933a-597d284915a8.png)
次に権限の追加です。本来もっと絞る必要がありますが、ここではS3に対するフルアクセスの権限を与えます。
![スクリーンショット 2022-12-17 21.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/df914aa8-91e8-d8e5-afca-2e86a2a17e4b.png)
他の項目もそのまま進めていくとIAMユーザーの作成が完了します。ここで表示されるアクセスキーIDとシークレットアクセスキーをGithubに登録します。
![スクリーンショット 2022-12-17 21.34.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/0d53cbd6-e25c-af27-cf06-f2045d1a5308.png)
これらのキーをGithub Actionsで安全に使うためにActions Secretというところに保存します。
![スクリーンショット 2022-12-17 21.38.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/3e524928-8d98-f715-edab-1579ed561335.png)
New Secretを押して、NameをAWS_ACCESS_KEY_IDとしてSecretにアクセスキーID、NameをAWS_SECRET_ACCESS_KEYとしてSecretにシークレットアクセスキーを登録します。Repository Secretに下のように表示されたら完了です。
![スクリーンショット 2022-12-17 21.41.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/9b5e497f-803d-e5a7-ccbd-9de6ac7862bd.png)

権限関連の設定が終わったのでactionsのファイルを記述します。`.github/workflow`フォルダを作成して、`deploy.yml`ファイルを作成してください。先ほど記述した一連のタスクを記述したファイルがこちらです。
```yml:deploy.yml
name: "Deploy"

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: npm
      - run: npm ci
      - run: npm run build
      - env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: aws s3 cp --recursive --region ap-northeast-1 dist/ s3://vite-project
```
このファイルをmainに加えた瞬間から、mainに変更が加わるたびにビルドされたファイルがs3に反映されます。試しに`App.tsx`の記述を変更してみます。地味ですが`useState(0)`を`useState(1000)`に変更してpushしてみましょう。
push後にdeploy(先ほど追加したactions)が動くことを確認できたら完了するまで待ちます。完了後に先ほど作成したページにアクセスしたところ、カウンターの初期値が1000になっていました。
![スクリーンショット 2022-12-17 21.53.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/3739e2ca-6269-b2d6-82dc-efa121488933.png)
加えた変更が自動で反映されるようになりましたね。これで完了です。

# まとめ
最近ではVercel、AmplifyなどでGithubのリポジトリを読み取るだけでホストすることが可能ですが、あえてS3とCloudFrontを用いてホストしてみました。これによるメリットとしてLambda@edge、CloudFront Functionsが使えるなど詳細な部分の設定をできるところに利点があると考えています。難易度が高いわけではないので、詳細まで設定を組み込みたい方は是非この方法でご利用してみてはいかがでしょうか。