HonoをVercelで動かしてみた(API / SSR HTML編)
HonoはVercelで動作すると聞いていたが、実際に試したことはなかった。Vercel向けにHonoをセットアップする方法と、Vercelでホストするためのファイルの生成方法が説明されている。Vercelにデプロイすると、Honoからのレスポンスが返ってくることが確認できた。さらに、静的HTMLの配信やHonoでSSRした結果の配信も試した。ただし、ワイルドカード(’*’)を利用する場合は注意が必要で、設定の順番によって動作が変わることがある。
目次
HonoがVercelで動くらしいという認識はあったのですが、実際に動かしたことがなかったので試してみました。
Vercel向けにHonoをセットアップする
create hono
でvercel
を指定すればOKです。
$ npm create hono@latest vercel-hono
create-hono version 0.3.2
✔ Using target directory … vercel-hono
? Which template do you want to use? › - Use arrow-keys. Return to submit.
↑ cloudflare-pages
cloudflare-workers
deno
fastly
lagon
lambda-edge
netlify
nextjs
nodejs
❯ vercel
vecel.json
など、Vercelでホストするためのファイルが含まれた状態で生成されてきます。
drwxrwxr-x 8 hideokamoto staff 256 12 21 14:21 .
drwxr-xr-x 7 hideokamoto staff 224 12 21 14:21 ..
-rw-r--r-- 1 hideokamoto staff 8 12 20 19:31 .gitignore
-rw-r--r-- 1 hideokamoto staff 34 12 20 19:31 README.md
drwxrwxr-x 3 hideokamoto staff 96 12 21 14:21 api
-rw-r--r-- 1 hideokamoto staff 172 12 20 19:31 package.json
-rw-r--r-- 1 hideokamoto staff 186 12 20 19:31 tsconfig.json
-rw-r--r-- 1 hideokamoto staff 92 12 20 19:31 vercel.json
vercel.json
には、Honoのアプリケーションコードが配置されているディレクトリへのrewriteルールが設定されています。
{
"rewrites": [
{
"source": "/api/(.*)",
"destination": "/api"
}
]
}
そのままVercelにデプロイしてみる
GitHubにコードをpushした後、Vercelにデプロイしてみましょう。Framework Preset
はOther
で、特にビルド設定などは変更せずに接続します。
デプロイすると、/api
パスでちゃんとHonoからのレスポンスが返ってきます。
$ curl https://YOUR-SPACE.vercel.app/api | jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 25 0 25 0 0 189 0 --:--:-- --:--:-- --:--:-- 196
{
"message": "Hello Hono!"
}
HTMLの配信も試してみる
どうせならHTMLも配信してHono + Vercelでウェブサイトやアプリを出せるようにしてみましょう。
静的HTMLだけなら、public
ディレクトリに配置するだけ
SPAのランディング用かSSGなどで生成したものを配置したい場合は、public
ディレクトリにHTMLを置くだけで良さそうです。public/index.html
を追加してみました。
<!DOCTYPE html>
<html>
<body>
<h1>Hell static page on Vercel</h1>
</body>
</html>
これをVercelにデプロイすると、https://YOUR-SPACE.vercel.app/
にこのページが表示されます。
HonoでSSRした結果を返す
HonoでHTMLを作って配信したい場合は、vercel.json
を少し変更します。source
からapi
を除外することで、ルートへのアクセスも/api
ディレクトリにあるHonoが動くようにしました。
{
"rewrites": [
{
"source": "/(.*)",
"destination": "/api"
},
]
}
あとはapi/index.ts
にHTMLを返すパスを追加するだけです。
import { Hono } from 'hono'
import { handle } from 'hono/vercel'
export const config = {
runtime: 'edge',
}
const app = new Hono()
app.get('/*', async c => {
return c.html(`
<!DOCTYPE html>
<html>
<body>
<h1>Hell hono on Vercel</h1>
<p>We're in the <code>${c.req.path}</code></p>
</body>
</html>
`)
})
export default handle(app)
これをデプロイすると、Honoで生成したHTMLが表示されます。
public
ディレクトリに配置した HTMLが優先される様子ですので、併用する場合はご注意ください。
Hono (HTML and API)を使う時の注意点
これはVercelに限った話ではなさそうですが、ワイルドカード(*
)を利用する場合は、追加するタイミングを最後にしましょう。
import { Hono } from 'hono'
import { handle } from 'hono/vercel'
export const config = {
runtime: 'edge',
}
const app = new Hono()
const apiApp = new Hono()
apiApp.get('/test', (c) => c.json({ message: 'Hello Hono!!!' }))
app.route('/api', apiApp)
app.get('/*', async c => {
return c.html(`
<!DOCTYPE html>
<html>
<body>
<h1>Hell hono on Vercel</h1>
<p>We're in the <code>${c.req.path}</code></p>
</body>
</html>
`)
})
export default handle(app)
/*
のパスを指定する前に、/api
パスを指定しています。逆にすると、/api
へのリクエストもapp.get('/*')
側が動いてしまいます。
HonoにはRouteのパスマッチパターンが何種類かあったはずなので、そちらを使うことで調整できるかもしれません。が、少なくともデフォルトではこのような挙動をしますのでご注意ください。