はじめに
- AWS Amplifyはあまり触ってこなかったけど、Gen2で色々いい感じになったらしい
- 推しフレームワークSvelteKitをGen2で動かして使用感を試してみる
SvelteKitとわたし
- SvelteKitは、WebフロントエンドフレームワークSvelteをベースとしたフルスタックアプリケーションのためのフレームワークです
- 筆者はSvelteKitを、Cloudflare Pages、AWS Lambda、AWS Lambda + Web Adapterでそれぞれ運用していて、それぞれのうれしみ・つらみがなんとなくわかってきたところです
AmplifyにSvelteKitをデプロイする
公式ドキュメントがあり、amplify-adapter
を利用すると良さそうです。ただし、
SvelteKitは「Adapter」という仕組みを利用して、同一コードから複数の環境へデプロイすることを可能としています。オフィシャルにメンテナンスされているアダプターのほか、サードパーティによるアダプターもあります。amplify-adapter
は後者です。
手順
上記ページのとおりで良く、要約すると以下です。
- SvelteKitアプリケーションを作成する
-
amplify-adapter
をインストールし、デフォルトと差し替える - ソースコードをGitHubへアップロードする
- AWS Amplifyコンソールでプロジェクトを作成する
- 3のリポジトリを選択する
- ビルド設定で、ビルド先ディレクトリとして
build
を指定する
# コマンド例
npm create svelte@latest sveltekit-amplify
npm install -D amplify-adapter
# svelte.config.jsを修正
git init
git add .
git commit -m init
git push origin sample-repo
# 以降はAWS Amplifyコンソールでの操作
上記ページでは
In the amplify.yml file, locate the frontend build commands section. Enter - cd build/compute/default/ and - npm i --production.
と説明されています。しかしデフォルトの状態ではbuild/compute/default/package.json
にdependencies
が記述されているわけでもないので、この設定をせずとも動作しました。ビルド時にminify出来ない依存関係が含まれている場合は、この設定が必要となります(例:バイナリを含むライブラリなど)。
ここまででAmplifyによりSvelteKitアプリケーションがデプロイされ、正常に動作するはずです。
デプロイプレビュー
- プライベートリポジトリであり、かつPR先リポジトリのプレビューが、コンソール上で有効化されていれば、PR作成時にビルドが走り、プレビューページのURLを取得できる
API routes
import type { RequestHandler } from '@sveltejs/kit';
const getHandler: RequestHandler = async (request) => {
return new Response('Hello from the server!');
};
const postHandler: RequestHandler = async (request) => {
return new Response('Hello from the server! post');
};
export const GET = getHandler;
export const POST = postHandler;
SvelteKitのお作法でAPIエンドポイントを実装しておく
curl https://path/to/app/api/hello
Hello from the server!
curl -X POST https://path/to/app/api/hello
Hello from the server! post
問題なく動作する。
SSRとStreamingをテストする
SvelteKitはStreaming、ベースのHTMLを先にレスポンスし、動的コンテンツはサーバー内の読み込みが完了した段階で後から送るという機能に対応しています。+page.server.ts
でデータフェッチングを記述することでSSRを実装することができます。今回は下記のコードを利用してみます。
import type { PageServerLoad } from './$types';
type Todo = {
userId: number;
id: number;
title: string;
completed: boolean;
};
export const load: PageServerLoad<{
todos: Promise<Todo[]>;
}> = async ({ fetch }) => {
// fetch sample data
return {
todos: new Promise<Todo[]>((resolve) => {
setTimeout(() => {
fetch('https://jsonplaceholder.typicode.com/todos')
.then((response) => response.json())
.then((todos) => {
resolve(todos);
});
}, 2000);
}),
};
};
<script lang="ts">
import type { PageServerData } from './$types';
export let data: PageServerData;
</script>
<main>
<div>
{#await data.todos}
loading...
{:then todos}
<ul>
{#each todos as todo}
<li>{todo.title}</li>
{/each}
</ul>
{/await}
</div>
</main>
このrouteは下記の順序で処理されるよう、記述されています。
- loading...が表示される
- サーバー側は、2秒待機->fetch()->json()を実行した結果を返す
Promise
をload()
で返す - コンポーネント側は、#awaitブロックにより、Promiseが解決したタイミングで表示を切り替える(=2秒程度待ったらTODOリストが表示される)
この実装で、開発サーバーではストリーミングが動作しますが、結果としてはAmplify環境では動作しませんでした。エラーが出るとかではなく、ストリーミングしたい要素まで全てが読み込まれた状態で初めてページがレスポンスされる挙動となります(なのでSSR自体は動作している)。
Amplifyにストリーミングレスポンスを有効化するようなオプションはなく、下記の記事でも言及されているように、現状でストリーミングレスポンスは非対応のようです。SSR Streamingはパフォーマンス上、たいへん有用ですので対応が待たれます。
使用感
Cloudflare Pagesとの比較
- 同じくらいの手軽さでSSRできるSvelteKitをデプロイできる
- Pagesはアーティファクトサイズ制限がかなり厳しい・ランタイムが薄く利用出来ないAPIがあるので、その点でかなり優位
- AmplifyはもちろんエッジSSRではないことは割り引いて見る必要がある
- ビルドは遅い(Amplifyが)
AWS Lambdaとの比較
- LambdaでSvelteKitをデプロイするには、同じくサードパーティのアダプターが必要(jill64/sveltekit-adapter-aws)
-
- 静的アセットはS3から・それ以外はLambdaから返すなど、いくつかのアーキテクチャパターンを選択できる
- 自動でCDKをジェネレートするような作り
-
- Amplifyが利用出来るならこの手段を取る必要はないかもしれない
- ただしLambdaはストリーミングレスポンスをサポートしている
AWS Lambda(+ Lambda Web Adapter)との比較
- ローカルでもコンテナ開発が前提なら、Web Adapter利用のパターンの方がポータブルなコードを書けるので、Amplifyよりも便利かもしれない
- そこそこ厚いランタイムの上でSSRしたいけど、そのためだけにコンテナを利用するのはどうみても過剰、みたいなケースでAmplifyを利用すると幸せになれそう
- 静的ファイルまでもがLambdaを通じて配信される単には留意
まとめ
- SvelteKitもAmplifyでお手軽にデプロイできる
- SSRも当然に動作するがストリーミングは未対応
- AmplifyはAWSサービスとの統合にも強みがあるはず(別途検証)