今週は、AWS Startup Loft Osaka Pop-Upにお邪魔してきました。
コワーキングスペースを提供してくれたり、日替わりでさまざまなイベントが開催されていました。(火曜日から木曜日まで、3日間もお邪魔しました。暖かく迎えていただいて大変感謝しております)
木曜日にはAmplifyに関するイベントがあり、GAされたばかりのGen2に関して学ぶことができました。なんと AmplifyのプロダクトマネージャのMattさんからのDeep dive もあり、 裏側までちら見せ してもらうという贅沢な場でした。(現地はAM 6:00ぐらいと言ってた気がします。Mattさんありがとうございました!!)
Amplify Gen2を始めるなら今です!!
Amplifyとは
Amplifyは、「AWSを意識しないでAWSを使える」という一見不思議なサービスです。
ただ、その威力は偉大です。Amplifyを使うことで、 フロントエンド(=ユーザーへ届ける価値)に開発リソースを集中させて、バックエンドは、AWSさんがよしなにやってくれる というありがたいサービスです。
イベントのLTでもAmplifyを活用して、スピード感のある開発をされている事例の発表がありました。
Amplify Gen2とは
イベントの発表で、Amplify Gen1に対して以下のようなフィードバックがあったと紹介されていました。
- 魔法の理解
- Amplifyが抽象化してインチキしているような感覚が気に入っているが、抽象化されすぎていてAmplifyが未対応の機能を実装しようとすると難しくなる
- ローカル開発の高速化
- ローカルでの変更を素早く確認したい。また、複数開発者で干渉することなく開発を行いたい
- より安全な本番ロールアウト
- 本番ロールアウトを安全にしたい
- 柔軟なデプロイオプションがほしい
これらを解決するためにGen2では以下のように改善されました。(これは私の理解です。もっと他に色々あると思います)
- AWSリソースの構築はCDKで行う
- SandBox機能の追加
- Gitとの統合
とりあえず始めたい方向け
Amplify Gen2のドキュメントにクイックスタートが用意されています。とりあえず触ってみようという方はこちらから入門するのが良いと思います。
私も実際に試したところすんなり動作しました。ただ、中身の理解ができなかったので、Amplify未導入環境から導入して理解を深めました。
前置きが長くなりましたが、私が手を動かして理解を進めた際の内容を共有させていただきます。
開発環境
VSCodeのdevcontainerで以下の開発環境を整えました。
- node: v22.1.0
- npm: 10.7.0
- AWS CLI: 2.15.52
AWSの認証情報はdefault
プロファイルに設定済みとして説明をすすめます。
Amplifyは大阪リージョンで使えるので、ぜひ大阪リージョン(ap-northeast-3)で使ってみてください。
Reactプロジェクトを作成
Vite(ヴィートと発音するようです)を使って、ReactとTypeScriptのプロジェクトを作成します。
npm create vite@latest gen2-app -- --template react-ts
gen2-app
ディレクトリが作成され、以下のファイルが生成されます。
.
├── index.html
├── package.json
├── public
│ └── vite.svg
├── README.md
├── src
│ ├── App.css
│ ├── App.tsx
│ ├── assets
│ │ └── react.svg
│ ├── index.css
│ ├── main.tsx
│ └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
4 directories, 13 files
package.jsonはこんな感じです。
package.json
{
"name": "gen2-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.66",
"@types/react-dom": "^18.2.22",
"@typescript-eslint/eslint-plugin": "^7.2.0",
"@typescript-eslint/parser": "^7.2.0",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"typescript": "^5.2.2",
"vite": "^5.2.0"
}
}
まずはこの状態で画面を確認します。
cd gen2-app
npm install
npm run dev
http://localhost:5173/
にアクセスするとトップページが確認できます。
プロジェクトにAmplifyを追加
Amplifyを追加します。必要なライブラリをインストールします。
npm add --save-dev @aws-amplify/backend@latest @aws-amplify/backend-cli@latest
amplify/backend.ts
を作成します。
import { defineBackend } from '@aws-amplify/backend';
defineBackend({});
最低限これで完了です。(この先で、いくつか編集していきます)
サンドボックスの起動
Gen2の目玉機能である サンドボックス を起動してみましょう。
サンドボックス機能の詳細はこちらに記載があります。
npm run dev
を実行中のターミナルと別のターミナルを開き、以下のコマンドを実行します。
npx ampx sandbox
サンドボックスをはじめて使用する際には、以下のエラーが表示されます。
The given region has not been bootstrapped. Sign in to console as a Root user or Admin to complete the bootstrap process, then restart the sandbox.
この場合は、URLへアクセスを促すダイアログが表示されると思うので、指示に従ってブートストラップを行ってください。
https://ap-northeast-3.console.aws.amazon.com/amplify/create/bootstrap?region=ap-northeast-3
かっこいい!!!(裏側ではおそらくcdk bootstrap
を実行しているものと思われます)
ブートストラップ完了後、再度npx ampx sandbox
を実行してください。
途中、以下のような黄色や赤、緑とカラフルな文字が表示されますが、正常ですのでお待ち下さい。
以下のメッセージが表示されたらサンドボックスは作成完了です。
[Sandbox] Watching for file changes...
File written: amplify_outputs.json
Gen2ではこのターミナルを起動しっぱなしで作業をします。ローカルのファイルを更新するとそれを検知し、AWSのリソースに変更が必要な場合は随時反映されます。
自動生成されるamplify_outputs.json
は以下のような内容です。まだAWSのリソースをひとつも作成していないため、バージョン番号のみです。
{
"version": "1"
}
AWSが提供しているテンプレートの.gitignore
には以下の記述があるので、以下のファイルはバージョン管理不要です
# amplify
.amplify
amplify_outputs*
amplifyconfiguration*
認証機能(Cognito)を追加
バックエンド側
それではAWSのリソースを追加しましょう。
まずは、Cognitoによる認証を追加します。
amplify/auth/resource.ts
を作成します。
import { defineAuth } from '@aws-amplify/backend';
export const auth = defineAuth({
loginWith: {
email: true
}
});
次にamplify/backend.ts
にauth
を追記します。
import { defineBackend } from '@aws-amplify/backend';
+ import { auth } from './auth/resource';
- defineBackend({});
+ defineBackend({
+ auth,
+ });
amplify/backend.ts
を保存すると、バックエンド(=AWS)にCognitoが必要と判断され、自動でデプロイが行われます。
言葉では伝わりづらいかもと思い、動画にしました。
CloudFormationを確認すると、Cognitoが作成されていることがわかります。
このように、 「AWSのリソースを変えたからデプロイして確認」 ではなく、 「コードを変更したら即座に反映」 という動きをするのがAmplify Gen2の特徴です。
フロントエンド側のソースを修正して保存したら即座に反映されますよね。それと同等のことがAWSのリソースでもできる感覚です!!
この時点のamplify_outputs.json
Cognitoの設定が追加されています。
{
"auth": {
"user_pool_id": "ap-northeast-3_ULpRA2YO9",
"aws_region": "ap-northeast-3",
"user_pool_client_id": "19ep8arft18kequmngk0495cgf",
"identity_pool_id": "ap-northeast-3:b01cbcaa-5bf3-47f2-8bc3-2b534c3d39ca",
"standard_required_attributes": [
"email"
],
"username_attributes": [
"email"
],
"user_verification_types": [
"email"
],
"password_policy": {
"min_length": 8,
"require_numbers": true,
"require_lowercase": true,
"require_uppercase": true,
"require_symbols": true
},
"unauthenticated_identities_enabled": true
},
"version": "1"
}
フロントエンド側
認証のバックエンドは完成しましたのでフロントエンド側を修正します。
フロントエンド側は、Gen2になってもこれまでと変わりません。
Amplify UI Libraryを追加します。
npm add @aws-amplify/ui-react
フロントエンドのソースは2ヵ所修正します。
-
src/main.tsx
: Amplifyの設定を読み込む記述を追加 -
src/App.tsx
:Authenticator
コンポーネントを追加
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
+ import '@aws-amplify/ui-react/styles.css'
+ import { Amplify } from 'aws-amplify'
+ import outputs from '../amplify_outputs.json'
+ Amplify.configure(outputs)
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
+ import { Authenticator } from '@aws-amplify/ui-react'
function App() {
const [count, setCount] = useState(0)
return (
+ <Authenticator>
+ {({ signOut, user }) => (
<>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
+ )}
+ </Authenticator>
)
}
export default App
はい、完成です。
バックエンド側のリソース(Cognito)はすでに存在するので、UIでCreate Account
タブからサインアップできます。
関数(Lambda)を追加
バックエンドの作り方がわかってきたと思います。
次はサインインした後に呼び出すhello-world
という名前のLambda関数を作ります。
バックエンド側
amplify/function/hello-world/resource.ts
を作成します。authと違い、複数リソースになるため、functionの下に個々のディレクトリがある形式です。
import { defineFunction } from '@aws-amplify/backend';
export const helloWorld = defineFunction({
name: 'hello-world',
entry: './handler.ts',
})
Lambda関数のコードを作成します。LambdaでTypeScriptを使用する際のドキュメント(こちら)を参考に、@types/aws-lambda
ライブラリを導入します。
npm add --save-dev @types/aws-lambda
amplify/function/hello-world/handler.ts
を作成します。
import { Handler } from 'aws-lambda';
export const handler: Handler = async (event, context) => {
return { message: 'Hello, World!!' }
}
フロントエンドのコードもCDKもLambdaも全部TypeScriptで記述できるのはいいですね!
最後に、amplify/backend.ts
に追加します。
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';
+ import { helloWorld } from './function/hello-world/resource'
defineBackend({
auth,
+ helloWorld,
});
amplify/backend.ts
を保存したタイミングでAWSにLambda作成が開始されます。
もう少し続きます。
Lambdaを呼び出すための権限を付与
Cognitoで認証したユーザーに、このLambdaの実行権限を付与します。
amplify/backend.ts
を修正し、まずCognitoで認証した際に付与されるIAMロールを取得します。
そして、「helloWorld
関数をInvokeする権限
をauthenticatedUserIamRole
に付与する」という記述を行います。
- defineBackend({
+ const backend = defineBackend({
auth,
helloWorld,
invokeBedrock,
});
+ const authenticatedUserIamRole = backend.auth.resources.authenticatedUserIamRole;
+ backend.helloWorld.resources.lambda.grantInvoke(authenticatedUserIamRole);
フロントエンドへの連携
最後に 「amplify_outputs.jsonにLambda関数名(物理名)を出力する」 処理を追加します。
こうすることで、フロントエンド側から、Lambda関数の物理名を参照することができます。
+ backend.addOutput({
+ custom: {
+ helloWorldFunctionName: backend.helloWorld.resources.lambda.functionName,
+ },
+ });
amplify_outputs.jsonの出力に以下の項目が追加されます。
{
...
"custom": {
"helloWorldFunctionName": "amplify-gen2app-node-sand-helloworldlambda89B27E55-2un3X5SixeeW"
}
}
フロントエンド側
フロントエンド側にLambdaを呼び出す処理を追加します。
まずは必要なimportを追加します。
import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda'
import { fetchAuthSession } from 'aws-amplify/auth'
import outputs from "../amplify_outputs.json"
fetchAuthSession
関数でcredentials (アクセスキー、シークレットアクセス、セッショントークン)を取得します。
const { credentials } = await fetchAuthSession()
amplify_outputs.json
からリージョンとLambda関数名を取得します。
const awsRegion = outputs.auth.aws_region
const functionName = outputs.custom.helloWorldFunctionName
Lambda関数名は先程backend.addOutput
で出力した値です
これでLambdaを呼び出す準備が整いました。SDKを使ってLambdaを呼び出します。
const labmda = new LambdaClient({ credentials: credentials, region: awsRegion })
const command = new InvokeCommand({
FunctionName: functionName,
});
const apiResponse = await labmda.send(command);
if (apiResponse.Payload) {
const payload = JSON.parse(new TextDecoder().decode(apiResponse.Payload))
setText(payload.message)
}
この時点のApp.tsx
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { Authenticator } from '@aws-amplify/ui-react'
+ import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda'
+ import { fetchAuthSession } from 'aws-amplify/auth'
+ import outputs from "../amplify_outputs.json"
function App() {
const [count, setCount] = useState(0)
+ const [text, setText] = useState("")
+ async function invokeHelloWorld() {
+
+ const { credentials } = await fetchAuthSession()
+ const awsRegion = outputs.auth.aws_region
+ const functionName = outputs.custom.helloWorldFunctionName
+
+ const labmda = new LambdaClient({ credentials: credentials, region: awsRegion })
+ const command = new InvokeCommand({
+ FunctionName: functionName,
+ });
+ const apiResponse = await labmda.send(command);
+
+ if (apiResponse.Payload) {
+ const payload = JSON.parse(new TextDecoder().decode(apiResponse.Payload))
+ setText(payload.message)
+ }
+ }
return (
<Authenticator>
{({ signOut, user }) => (
<>
<div>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
+ <p>
+ <button onClick={invokeHelloWorld}>invokeHelloWorld</button>
+ <div>{text}</div>
+ </p>
</>
)}
</Authenticator>
)
}
export default App
ボタンをクリックすると、このようにLambdaのレスポンスを画面表示できました。
関数(Lambda)を追加(発展編)
先程のLambda関数は固定文字を返すだけでしたので、Bedrockを呼び出してその結果を返すLambdaを作成します。
バックエンド側
Lambda関数のコードを作成する前に、Bedrock RuntimeのSDKをインストールします。
npm add --save-dev @aws-sdk/client-bedrock-runtime
amplify/function/invoke-bedrock/resource.ts
を作成します。
import { defineFunction } from '@aws-amplify/backend';
export const invokeBedrock = defineFunction({
name: 'invoke-bedrock',
entry: './handler.ts',
})
ストリーミングレスポンス
Lambdaは、ストリーミングでレスポンスを返却することができるので、Bedrockから受けたストリーミングのレスポンスをLambdaの結果として返却する方法で実装します。
以下のドキュメントを参考にしました。
import { Context, Handler } from 'aws-lambda';
import { Writable } from 'stream';
import {
BedrockRuntimeClient,
InvokeModelWithResponseStreamCommand,
} from "@aws-sdk/client-bedrock-runtime";
type eventType = {
prompt: string
}
const modelId = "anthropic.claude-3-haiku-20240307-v1:0"
export const handler: Handler = awslambda.streamifyResponse(
async (event: eventType, responseStream: Writable, _context: Context) => {
const client = new BedrockRuntimeClient({ region: "us-east-1" });
const payload = {
anthropic_version: "bedrock-2023-05-31",
max_tokens: 1000,
messages: [
{
role: "user",
content: [{ type: "text", text: event.prompt }],
},
],
};
const command = new InvokeModelWithResponseStreamCommand({
contentType: "application/json",
body: JSON.stringify(payload),
modelId,
});
const apiResponse = await client.send(command);
if (apiResponse.body) {
for await (const item of apiResponse.body) {
if (item.chunk) {
const chunk = JSON.parse(new TextDecoder().decode(item.chunk.bytes));
const chunk_type = chunk.type;
if (chunk_type === "content_block_delta") {
const text = chunk.delta.text;
responseStream.write(text);
}
} else if (item.internalServerException) {
throw item.internalServerException
} else if (item.modelStreamErrorException) {
throw item.modelStreamErrorException
} else if (item.throttlingException) {
throw item.throttlingException
} else if (item.validationException) {
throw item.validationException
}
}
}
responseStream.end()
}
)
Bedrockは大阪リージョンにまだ提供されていのないので、バージニア北部のBedrockを呼び出します。
amplify/backend.ts
にinvoke-bedrock
Lambda関数を追加します。
+ import { invokeBedrock } from './function/invoke-bedrock/resource'
defineBackend({
auth,
helloWorld,
+ invokeBedrock,
});
Cognitoで認証したユーザーがこのLambda関数を呼べるように追加します。
+ backend.invokeBedrock.resources.lambda.grantInvoke(authenticatedUserIamRole);
フロントエンド側が、Lambda関数名を取得できるようにOutputに追加します。
backend.addOutput({
custom: {
helloWorldFunctionName: backend.helloWorld.resources.lambda.functionName,
+ invokeBedrockFunctionName: backend.invokeBedrock.resources.lambda.functionName,
},
});
最後に、Lambda関数がBedrockを呼び出すための権限を設定します。
+ import * as iam from 'aws-cdk-lib/aws-iam';
+ const bedrockStatement = new iam.PolicyStatement({
+ actions: ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
+ resources: ["arn:aws:bedrock:us-east-1::foundation-model/*"]
+ })
+ backend.invokeBedrock.resources.lambda.addToRolePolicy(bedrockStatement)
このあたりの書き方は、CDKですね。
この時点のamplify/backend.ts
import { defineBackend } from '@aws-amplify/backend';
+ import * as iam from 'aws-cdk-lib/aws-iam';
import { auth } from './auth/resource';
import { helloWorld } from './function/hello-world/resource'
+ import { invokeBedrock } from './function/invoke-bedrock/resource'
const backend = defineBackend({
auth,
helloWorld,
+ invokeBedrock,
});
const authenticatedUserIamRole = backend.auth.resources.authenticatedUserIamRole;
backend.helloWorld.resources.lambda.grantInvoke(authenticatedUserIamRole);
+ backend.invokeBedrock.resources.lambda.grantInvoke(authenticatedUserIamRole);
+ const bedrockStatement = new iam.PolicyStatement({
+ actions: ["bedrock:InvokeModel", "bedrock:InvokeModelWithResponseStream"],
+ resources: ["arn:aws:bedrock:us-east-1::foundation-model/*"]
+ })
+ backend.invokeBedrock.resources.lambda.addToRolePolicy(bedrockStatement)
backend.addOutput({
custom: {
helloWorldFunctionName: backend.helloWorld.resources.lambda.functionName,
+ invokeBedrockFunctionName: backend.invokeBedrock.resources.lambda.functionName,
},
});
フロントエンド側
フロントエンド側にLambdaを呼び出す処理を追加します。
先程のHello Worldとは異なり、パラメータを渡してレスポンスを受け取ります。
レスポンスはストリーミング形式です。
もう殆どAmplify関係なく、通常のReact開発という感じです。
const [prompt, setPrompt] = useState("")
const [aiMessage, setAiMessage] = useState("")
async function invokeBedrock() {
const { credentials } = await fetchAuthSession()
const awsRegion = outputs.auth.aws_region
const functionName = outputs.custom.invokeBedrockFunctionName
const labmda = new LambdaClient({ credentials: credentials, region: awsRegion })
const command = new InvokeWithResponseStreamCommand({
FunctionName: functionName,
Payload: new TextEncoder().encode(JSON.stringify({ prompt: prompt }))
})
const apiResponse = await labmda.send(command);
let completeMessage = ''
if (apiResponse.EventStream) {
for await (const item of apiResponse.EventStream) {
if (item.PayloadChunk) {
const payload = new TextDecoder().decode(item.PayloadChunk.Payload)
completeMessage = completeMessage + payload
setAiMessage(completeMessage)
}
}
}
}
src/App.tsxの最終形
少し整形したり、undefinedのチェックを追加しています。
import { useState } from 'react'
import './App.css'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import { Authenticator } from '@aws-amplify/ui-react'
import { InvokeCommand, InvokeWithResponseStreamCommand, LambdaClient } from '@aws-sdk/client-lambda'
import { fetchAuthSession } from 'aws-amplify/auth'
import outputs from "../amplify_outputs.json"
function App() {
const [text, setText] = useState("")
const [prompt, setPrompt] = useState("")
const [aiMessage, setAiMessage] = useState("")
async function invokeHelloWorld() {
const { credentials } = await fetchAuthSession()
const awsRegion = outputs.auth.aws_region
const functionName = outputs.custom.helloWorldFunctionName
const labmda = new LambdaClient({ credentials: credentials, region: awsRegion })
const command = new InvokeCommand({
FunctionName: functionName,
});
const apiResponse = await labmda.send(command);
if (apiResponse.Payload) {
const payload = JSON.parse(new TextDecoder().decode(apiResponse.Payload))
setText(payload.message)
}
}
async function invokeBedrock() {
const { credentials } = await fetchAuthSession()
const awsRegion = outputs.auth.aws_region
const functionName = outputs.custom.invokeBedrockFunctionName
const labmda = new LambdaClient({ credentials: credentials, region: awsRegion })
const command = new InvokeWithResponseStreamCommand({
FunctionName: functionName,
Payload: new TextEncoder().encode(JSON.stringify({ prompt: prompt }))
})
const apiResponse = await labmda.send(command);
let completeMessage = ''
if (apiResponse.EventStream) {
for await (const item of apiResponse.EventStream) {
if (item.PayloadChunk) {
const payload = new TextDecoder().decode(item.PayloadChunk.Payload)
completeMessage = completeMessage + payload
setAiMessage(completeMessage)
}
}
}
}
return (
<Authenticator>
{({ signOut, user }) => (
<>
<div>
<a href="https://docs.amplify.aws" target="_blank">
<img src="https://docs.amplify.aws/assets/icon/favicon-purple-96x96.png" className="logo amplify" alt="Amplify logo" />
</a>
<a href="https://vitejs.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Amplify + Vite + React</h1>
<p>
Hello, {user?.signInDetails?.loginId}
<br />
<button onClick={signOut}>Sign Out</button>
</p>
<p>
<button onClick={invokeHelloWorld}>invokeHelloWorld</button>
<div>{text}</div>
</p>
<p>
<textarea
onChange={(e) => setPrompt(e.target.value)}
value={prompt}
style={{ width: '50vw', textAlign: 'left' }}
></textarea>
<br />
<button onClick={invokeBedrock}>invokeBedrock</button>
<div style={{ width: '50vw', textAlign: 'left' }}>{aiMessage}</div>
</p>
</>
)}
</Authenticator>
)
}
export default App
これでバックエンド、フロントエンド含めて一通り完成しました。
Gen2のその他の機能
認証と関数以外の機能もあります。
- Data(AppSync)
- Storage(S3)
- Server Side Rendering
本番環境にデプロイ
ローカルでの開発がいい感じに終わったので、本番環境としてデプロイしましょう。
まず、これまでのソースをGitHubにプッシュします。プライベートリポジトリで構いません。
AWSのマネジメントコンソールにて、Amplifyの画面を表示します。新しいアプリ
ボタンをクリックします。
GitHub
を選択し、次へ
ボタンをクリックします。
アクセスを許可するウィンドウが表示されるので、対象のリポジトリを選び、Install & Authorize
ボタンをクリックします。
Amplifyの画面に戻るので、リポジトリ、ブランチを選択して次へ
ボタンをクリックします。
プロジェクトの自動検出が行われます。このまま次へ
ボタンをクリックします。
確認画面が表示されます。保存してデプロイ
をクリックします。
しばらくするとデプロイが完了します。
ソースコードがビルドエラーになり、一度デプロイに失敗しましたが、ソースを修正してプッシュすると、自動でビルドが実行されました。
Amplifyが自動でドメインを発行してくれます。発行されたURLにアクセスすると、アプリが確認できます。
また、Amplifyの画面で認証や関数などの管理ができます。
これは結構便利な気がします。
今回は試せてませんがデプロイに関しても色々機能が提供されているようです。
- Git flow、GitHub/プルリクエストフロー
- モノレポとマルチリポジトリ
最後まで読んでいただいてありがとうございます。Amplify Gen2に興味を持っていただけたら幸いです。