SSTでVite+ReactアプリをAWSにデプロイする
前回はSSTでサーバーレスなAPIを開発・デプロイする方法を紹介しました.SSTってなに?って方はそちらを先に読んでください.
本記事ではSSTでReactアプリ(&簡単なAPI)をデプロイする流れを説明します.
今回のコードはGitHubにあります.
SST&Viteセットアップ
まずSSTのプロジェクトを作成します.
npx create-sst@latest sst-vite-app
cd sst-vite-app
npm install
sst.config.ts
を開き,このプロジェクトデプロイするリージョンを設定します.
config(_input) {
return {
name: "sst-vite-app",
- region: "us-east-1",
+ region: "ap-northeast-1",
};
},
続いてViteをセットアップします.packages/frontend/
にViteプロジェクトを作成します.ここではReact+TypeScriptを選択しました.
cd packages
npm create vite@latest frontend
cd frontend
npm install
この時点でプロジェクトの構造は次のようになっています.
.
├── package-lock.json
├── package.json
├── packages
│ ├── core
│ ├── frontend // ここにViteのプロジェクトが入っている
│ └── functions
├── pnpm-workspace.yaml
├── sst.config.ts
├── stacks
│ └── MyStack.ts // AWSリソースを定義
└── tsconfig.json
Viteプロジェクトのpackage.json
を次のように変更します.
"scripts": {
- "dev": "vite",
+ "dev": "sst bind vite",
"build": "tsc && vite build",
AWSリソースの定義
SSTプロジェクトにViteを含めるために,フロントエンドをSSTのスタック(≒AWSのリソース)として定義します.また単にフロントエンドをデプロイするだけでは面白くないので,フロントエンドから利用するためのAPIも定義します.
stacks/MyStack.ts
を開き,次のコードで置き換えます.
import { Api, StackContext, StaticSite } from "sst/constructs";
export function MyApp({ stack }: StackContext) {
const api = new Api(stack, "api", {
routes: {
"GET /": "packages/functions/src/lambda.handler",
},
});
const web = new StaticSite(stack, "web", {
path: "packages/frontend",
buildOutput: "dist",
buildCommand: "npm run build",
environment: {
VITE_API_ENDPOINT: api.url,
}
});
stack.addOutputs({
ApiEndpoint: api.url,
WebUrl: web.url,
});
}
sst.config.ts
を次のように変更します.
import { SSTConfig } from "sst";
- import { API } from "./stacks/MyStack";
+ import { MyApp } from "./stacks/MyStack";
export default {
config(_input) {
return {
name: "sst-vite-app",
region: "ap-northeast-1",
profile: "be4rr",
};
},
stacks(app) {
- app.stack(API);
+ app.stack(MyApp);
},
} satisfies SSTConfig;
APIを利用するためにApp.tsx
のコードを次のコードで置き換えます.ボタンをクリックするとAPIにリクエストを送信するだけのシンプルなプログラムです.
import { useState } from "react";
function App() {
const [data, setData] = useState<string>();
return (
<>
<div>API Endpoint: {import.meta.env.VITE_API_ENDPOINT}</div>
<button
onClick={async () => {
const res = await fetch(import.meta.env.VITE_API_ENDPOINT);
const data = await res.text();
setData(data);
}}
>
Fetch
</button>
{data && <div>{data}</div>}
</>
);
}
export default App;
開発環境を実行
開発環境を実行します.
まずSSTプロジェクトのルートディレクトリsst-vite-app/
でnpm run dev
を実行します.その後,別のターミナルでViteプロジェクトのルートディレクトリsst-vite-app/packages/frontend/
でnpm run dev
を実行します.
するとSSTの開発環境がデプロイ・実行され,Viteの開発サーバーがローカルで起動します.
Reactのアプリを開いて表示されているボタンを押すと,APIにリクエストが送信されてそのレスポンスがUIに表示されます.
本番環境にデプロイ
このまま本番環境にデプロイします.先ほど起動したSSTとViteの開発環境は停止しておきます.
SSTプロジェクトのルートディレクトリsst-vite-app/
で次のコマンドを実行します.
npx sst deploy --stage prod
このコマンドを実行することで,本番環境用にAPI GatewayやLambda関数が作成され,フロントエンドがビルドされてS3+CloudFrontにデプロイされます.
❯ npx sst deploy --stage prod
SST v2.38.7
➜ App: sst-vite-app
Stage: prod
Region: ap-northeast-1
Account: xxxxxxxxxxxx
Building static site packages/frontend
> frontend@0.0.0 build
> tsc && vite build
vite v5.0.10 building for production...
✓ 31 modules transformed.
dist/index.html 0.46 kB │ gzip: 0.30 kB
dist/assets/index-T74ItOsL.css 0.92 kB │ gzip: 0.50 kB
dist/assets/index-WRPBg0DR.js 142.94 kB │ gzip: 45.95 kB
✓ built in 399ms
✔ Building...
| MyApp PUBLISH_ASSETS_COMPLETE
| MyApp web/Distribution/Origin1/S3Origin AWS::CloudFront::CloudFrontOriginAccessIdentity CREATE_COMPLETE
(略)
| MyApp AWS::CloudFormation::Stack CREATE_COMPLETE
✔ Deployed:
MyApp
ApiEndpoint: https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com
WebUrl: https://xxxxxxxx.cloudfront.net
最後に出力されるWebUrlがデプロイされたCloudFrontのURLです.アクセスすると先ほど作成したReactアプリが表示され,APIからのデータ取得も同じ用にできるはずです.
カスタムドメインを設定する
フロントエンドにカスタムのドメインを設定します.以下ではRoute53にドメインを登録している前提で進めます.
私はbe4rr.click
というドメインを持っているので,フロントエンドに対してapp.be4rr.click
というサブドメインを設定したいと思います.
const web = new StaticSite(stack, "web", {
path: "packages/frontend",
buildOutput: "dist",
buildCommand: "npm run build",
environment: {
VITE_API_ENDPOINT: api.url,
},
+ customDomain: {
+ domainName: "app.be4rr.click",
+ hostedZone: "be4rr.click",
+ },
});
再び本番環境にデプロイします.証明書の発行やCloudFrontの設定で数分かかると思います.
npx sst deploy --stage prod
完了すると設定したドメイン名(私の場合はhttps://app.be4rr.click/
)でフロントエンドにアクセスできるようになっているはずです.
後片付け
AWSにデプロイした開発環境と本番環境を削除します.
開発環境を削除
npx sst remove
本番環境を削除
npx sst remove --stage prod
Discussion