ローカル環境での起動方法が分からない
2024年12月14日時点、Hono の公式ドキュメントを見ると、Cloudflare Workers には npm run dev
でローカル環境で起動する方法が記載してありますが、AWS Lambda には同等の記載がありません。
では、どうやってローカル環境で開発をすればよいのでしょうか?
この記事では、HonoをAWS Lambdaで動かす際の開発方法として、SAMを使う方法とNode.jsでのローカル実行方法の2つを紹介します!
試行錯誤中なので、コメントで教えていただけたら嬉しいです
解決策
一般的な解決策(SAM)
まず、一般的な解決策として AWS SAM (Serverless Application Model: 以下SAM)が挙げられます。
SAM はサーバーレスアプリケーションを簡単に作成・デプロイできるツールで、Lambda のデプロイだけではなく、API Gateway や IAM などのリソースも作成できて便利です。
反面、公式ドキュメントで紹介されている AWS Cloud Development Kit (AWS CDK) との併用は難しいかなと思いました。CDK は IaC であり、プロジェクト内のリソース管理の責務の線引きが難しいからです。
しかし、CDK にこだわらないのであれば、SAM の選択肢は良いと思います。
実際のサンプルは GitHub にアップロードしてありますので、実装はそちらのほうでご覧ください。
ローカル実行(SAM)
SAM を導入し、ビルド&ローカル実行すると下記のように表示されます。
# ビルド
$ sam build --manifest package.json
Build Succeeded
# ローカル実行
$ sam local invoke
Invoking index.handler (nodejs20.x)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/nodejs:20-rapid-x86_64.
Mounting /my-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: 7c085261-433a-4a36-8efb-b7136dbc507b Version: $LATEST
END RequestId: 5db9c937-7b3b-47ae-b690-14360868af70
REPORT RequestId: 5db9c937-7b3b-47ae-b690-14360868af70 Init Duration: 0.08 ms Duration: 150.66 ms Billed Duration: 151 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"body": "Hello Hono!", "headers": {"content-type": "text/plain;charset=UTF-8"}, "statusCode": 200, "isBase64Encoded": false}
ビルド時に public.ecr.aws/lambda/nodejs:20-rapid-x86_64
ベースの Docker Image が作られ、ローカル実行時に使われるので、実際のランタイム環境で動かすことができます。
アプリケーションでの解決策(Hono の Node.js Adapterで動かす)
ローカル開発では、先ほど紹介した SAM を使った方法が推奨されると思います。
一方で、ネイティブモジュールやバイナリ依存のライブラリを使用しないのであれば、同じ Node.js のバージョンで動かす方法もできそうです。
Hono はあらゆる環境で動かすことができます。公式ドキュメントには Node.js ランタイムがあり、そこには npm run dev
を使ったローカル環境での実行方法も紹介されています。
これを応用して、実際の Lambda でのエントリーポイントとは別に、Node.js からのエントリーポイントも用意することができます。
構築手順
実際のサンプルは GitHub にアップロードしてありますので、実装はそちらのほうでご覧ください。
まず、Node.js Adapter と TypeScript をビルドするために tsx をインストールし、package.json に npm スクリプトを追加します。
npm install -D @hono/node-server tsx
"scripts": {
+ "dev": "tsx watch lambda/local.ts",
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
次に、index.ts に含まれる Hono の設定を app.ts に切り出します。
import { Hono } from "hono";
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!おめでとうございます!')) // 確認用
export default app;
import { handle } from 'hono/aws-lambda'
import app from './app'
export const handler = handle(app)
そして、ローカル実行のエントリーポイントである local.ts を追加します。
import { serve } from '@hono/node-server'
import app from './app'
const port = 3000
console.log(`Server is running on http://localhost:${port}`)
serve({
fetch: app.fetch,
port
})
index.ts も local.ts も同じ app を参照していることが分かります。
この状態で npm run dev
コマンドを実行すると、何ということでしょう。Node サーバーが起動しました
$ npm run dev
> my-app@0.1.0 dev
> tsx watch lambda/local.ts
Server is running on http://localhost:3000
http://localhost:3000/
にアクセスしてみると、先程 app.ts に書いた出力結果が表示されていることが分かります。
Node サーバーは起動しているので、curl だけでなく、Postman などの GUI も使えますね!
Node サーバーで動かすことのメリットとデメリット
Hono のアダプターを切り替えるだけで、簡単に Node サーバーが手に入ることが分かりました。
個人的に下記のメリットとデメリットがあると思います。
一方、デメリットもあります。
これらはアプリケーションの特性にも左右されるので、チームで話し合ったほうが良さそうですね。
おわりに
Hono は素晴らしいフレームワークですが、みなさんどうやって開発されているのでしょうか?
開発から運用までノウハウが広まれば、もっと Hono の導入事例が増えると思います。
駆け出し Hono エンジニアの私に、みなさんのお知恵を何卒よろしくお願いします