Honoxで、サーバーサイドとクライアントサイドのfetchを試してみた
HonoでWebサイトを作る「honox」の実装方法を紹介。クライアント・サーバーサイドでのデータ取得やAPI呼び出しを説明。外部APIを用意し、クライアントでfetchやサーバーでfetch、レスポンス表示する手順を示す。Reactライクな使い勝手とHono/Cloudflare Workersっぽい特徴がある。honoxは個人的に興味深く、SSGの場合はAstroを、サーバー側処理が多い場合はhonoxを推奨。
目次
HonoでWebサイトを作れる「honox」が登場しました。サイト構築となると、外部のAPIからデータを取得する処理を書くことが少なくないですが、honoxでクライアントサイド・サーバーサイドそれぞれどのように実装することになるかを試してみた覚書です。
プロジェクトのセットアップ
テストに使うプロジェクトを、create-hono
で作りましょう。
% npm create hono
Need to install the following packages:
[email protected]
Ok to proceed? (y)
honoxを使うには、テンプレートでx-basic
を指定します。
? Which template do you want to use? › - Use arrow-keys. Return to submit.
↑ cloudflare-pages
cloudflare-workers
deno
fastly
lambda-edge
netlify
nextjs
nodejs
vercel
❯ x-basic
そのほかの設定は好みに任せて行いましょう。最後に次のような生成完了メッセージが出ればOKです。
cloned honojs/starter#main to /Users/sandbox
✔ Copied project files
呼び出すAPIを用意する
外部APIを呼び出すテストですので、APIをまずは用意しましょう。honoxはhonoをベースにしていますので、APIの作成も簡単です。app/server.ts
に次のようなコードを追加します。
import { showRoutes } from 'hono/dev'
import { createApp } from 'honox/server'
const app = createApp()
app.get('/api', async c => {
return c.json({
message: 'hello'
})
})
showRoutes(app)
export default app
これで/api
に対するGET
リクエストを処理できるようになりました。
クライアント側でのfetchを試みる
まずはクライアント側での呼び出しを試してみましょう。テンプレートにあるapp/islands/counter.tsx
を次のように変更します。
import { useState } from 'hono/jsx'
export default function Counter() {
const [message, setMessage] = useState("")
return (
<div>
<p>{message}</p>
<button onClick={async () => {
const result = await fetch('/api')
const data = await result.json<{message: string}>()
setMessage(data.message)
}}>Fetch</button>
</div>
)
}
ボタンクリック時のイベントでfetch
を行い、useState
で値をコンポーネントに渡しています。
Reactライクにかけるのが便利ですね。
サーバー側でのfetchにトライする
続いてサーバー側の処理も試してみましょう。今度はapp/routes/index.tsx
を編集します。
import { css } from 'hono/css'
import { createRoute } from 'honox/factory'
import Counter from '../islands/counter'
const className = css`
font-family: sans-serif;
`
export default createRoute(async (c) => {
const name = c.req.query('name') ?? 'Hono'
const result = await fetch(`${c.req.url}api`)
const {message} = await result.json<{message: string}>()
return c.render(
<div class={className}>
<h1>Hello, {name}!</h1>
<h2>{message}</h2>
<Counter />
</div>,
{ title: name }
)
})
c.render
に渡す値を、await fetch
で取得しています。「Hello, 」の後ろ部分がAPIレスポンスになっていますので、次のような表示になるはずです。
やってみての感想
Reactっぽさもありつつ、Hono / Cloudflare Workersっぽい書き方もできるので、個人的にはhonoxはなかなか面白いなと思っています。Astroとかも使い勝手がよいなと思いますが、サーバー側の処理(コンポーネント・API)が多めのサイトやアプリについてはこちらで、どちらかというとSSG的な用途で使いたい場合はAstroかなぁというイメージですね。