Bun+Honoは今日初めて触ったので備忘録を残します。
Reactはほとんど触ってないのでちょっとしたことに躓いて牛歩状態です。
この記事はチュートリアルなコードと、参照したドキュメントへのリンクを含めて後で辿れるように書きました。
試した環境
- MacOS Sonoma 14.3
- Bun 1.0.6
- Hono 4.0.4
Bun インストール
コマンドラインからインストールしました。
sudo
は使わないのでたぶん怖くない筈です。
$ curl -fsSL https://bun.sh/install | bash
削除したい時はホームフォルダの.bun
を削除すれば良いそうです。
$ rm -rf ~/.bun
Project作成
ドキュメントに習ってHonoのプロジェクトを作成
$ bunx create-hono my-app
何も知らずにコマンドを叩くと12からあるTemplateを選べと言われてドン引きしました。
今回はbun
を選択。
$ bunx create-hono my-app
create-hono version 0.4.0
✔ Using target directory … my-app
✔ Which template do you want to use? › bun
cloned honojs/starter#main to /Users/o2/work/tmp/my-app
✔ Copied project files
VSCodeでプロジェクトを開くとあちこちアンダーラインが引かれます。
最初にライブラリ導入しないとね。
無事Hello Hono!
と表示できました。👏
$ code my-app
$ cd my-app
$ bun i
$ bun run dev
$ bun run --hot src/index.ts
Started server http://localhost:3000
SSGを試す
ドキュメントにあるようにSSGを設定。
import app from "./src/index";
と設定。
(なお、この書き方だとindex.*, index/* と様々なファイルを参照するそうです。)
import { toSSG } from "hono/bun";
import app from "./src/index";
toSSG(app)
実行するとstaticフォルダにファイルが出力できました。
$ bun build.ts
$ tree --gitignore
.
├── README.md
├── build.ts
├── bun.lockb
├── package.json
├── src
│ └── index.ts
├── static
│ └── index.txt
└── tsconfig.json
3 directories, 7 files
ssgParamsで複数のページを出力する
同ページのドキュメントのssgParams
を試していきます。
ここでは静的ページの作成にはコードに直書きのコンテンツデータを利用します。
最初にjsxを利用しますので現在のindex.ts
のファイルの拡張子を変更します。
$ mv index.ts index.tsx
import { Hono } from 'hono'
import { ssgParams } from 'hono/ssg'
const app = new Hono()
const ShopsData = [
{ id: "1", name: "hoge",},
{ id: "2", name: "fuga" }
]
function getShop(id: string){
return ShopsData.filter(shop => id == shop.id)
}
app.get(
'/shops/:id',
ssgParams(async () => {
return ShopsData.map((shop) => ({ id: shop.id }))
}),
async (c) => {
const shops = await getShop(c.req.param('id'))
if (shops.length < 1) {
return c.notFound()
}
const shop = shops[0]
return c.render(
<div>
<h1>{shop.name}</h1>
</div>
)
}
)
export default app
package.json
の.ts
を.tsx
に修正して実行
{
"scripts": {
"dev": "bun run --hot src/index.ts"
↓
"dev": "bun run --hot src/index.tsx"
},
...
$ bun run dev
localhost:3000/shops/2
にアクセス
shops/[id]
にIDを指定してページにアクセスできることが確認できます。
再度SSGを出力しなおします。
$ bun build.ts
$ tree --gitignore
.
├── README.md
├── build.ts
├── bun.lockb
├── package.json
├── src
│ └── index.tsx
├── static
│ ├── index.txt
│ └── shops
│ ├── 1.html
│ └── 2.html
└── tsconfig.json
staticフォルダに設定した[id].html
のファイルが出力できていることが確認できました。
上記の出力まで見れば何を行う処理なのか解りやすいですね。
const ShopsData = [
{ id: "1", name: "hoge",},
{ id: "2", name: "fuga" }
]
app.get(
'/shops/:id',
ssgParams(async () => {
return ShopsData.map((shop) => ({ id: shop.id }))
}),
ここでの肝ですが、
-
/shops/:id
ではapp.get
にパラメータid
を取得するように指定 -
ssgParams
に生成するページのIDをShopsData
を展開して与えています
これによりstaticフォルダに出力するファイルを制御できます。
静的ファイルへのリンクに対応する
import { Hono } from 'hono'
import { ssgParams } from 'hono/ssg'
const app = new Hono()
const ShopsData = [
{ id: "1", name: "hoge",},
{ id: "2", name: "fuga" }
]
function getShop(id: string){
return ShopsData.filter(shop => id == shop.id)
}
app.get(
'/shops/:id',
ssgParams(async () => {
return ShopsData.map((ShopsData) => ({ id: ShopsData.id }))
}),
async (c) => {
const shops = getShop(c.req.param('id'))
if (shops.length < 1) {
return c.notFound()
}
const shop = shops[0]
const contents = (
<ul>
{ ShopsData.map( shop => (<li><a href={
Bun.env.NODE_ENV === "development" ? `/shops/${shop.id}` : `/shops/${shop.id}.html`
}>{shop.name}</a></li> )) }
</ul>
)
return c.html(`
<div>
<h1>${shop.name}</h1>
</div>
${contents}
`)
}
)
export default app
package.json
にbuild
コマンドを追記
{
"scripts": {
"dev": "bun run --hot src/index.tsx",
"build": "NODE_ENV='production' bun build.ts"
},
...
ここではコマンドをbuild.ts
ではなくpackage.json
に追記したbuild
コマンドを実行します。
この修正により出力するファイルとbun run dev
で実行時と静的ページを閲覧してもリンクが機能します。
$ bun run build
$ bun run dev
これでSSGマスター
まだまだ機能は沢山ありますが基本のループとIF文が書けるようになりました。
Bun+Honoを試した感想としては、随分簡単に静的ファイルの出力処理が書けるのだなと思いました。
これでとっかかりが出来たのであとはドキュメントを読み進めるだけです。
初学者ですのでもっと良い方法等あれば是非コメントを残していただければ幸いです。