HonoXで爆速LPを作成する

こんにちは。

テックリードのTerukiです。

今日はかなりテクニカルな記事です。

今回はOh my teethのLPシステムで使用しているHonoXについて書いていこうと思います。

# HonoX

引用：https://github.com/honojs/honox
>HonoX is a simple and fast meta-framework for creating full-stack websites or Web APIs - (formerly Sonik). It stands on the shoulders of giants; built on Hono, Vite, and UI libraries.
>Note: HonoX is currently in the "alpha stage". Breaking changes are introduced without following semantic versioning.

HonoXはシンプルで高速なフルスタックなメタフレームワークです。

どういうこっちゃという感じですが、とりあえずHonoXを入れたらそれだけでWebサイトやWeb APIを作るために必要なものが揃うよという理解です。めっちゃ便利。

この記事を書いている時点では上記の引用の通りAlphaステージで破壊的変更がいつでもありうるExperimentalなフレームワークですが、開発体験があまりに良いのでOh my teethでは<font color="orange">私の責任の元</font>でプロダクション投入しています。

# 前置き
大前提として、いくら開発体験が良いからといってAlphaステージのフレームワークを本番投入することは控えめに言っても<font color="orange">常軌を逸している</font>ので全くオススメしません。

私は不具合などがあった場合はHonoXにContributeして一緒に改善していくぜ！という気概でいるのと、今回のLPシステムはさほど複雑なものではないのでリスクは低いという判断で行っています。

（実際[プルリクエスト](https://github.com/honojs/honox/pull/116)を作成したりもしてました）

# 本題
Honoを触ったことがある方なら分かると思うのですが、TypeScriptで補完を効かせながらゴリゴリコーディングできるので非常に早く開発を進めることができます。

今回はサンプルとして、下記の要素を詰め込んだものを作ってみました。
- TailwindCSS
- mdx
- islandコンポーネントあり

ZeroJSで行けるならそれにこしたことはないですが、作りたいLPがZeroJSで行けることはデザイン的にほぼない、けどパフォーマンスは妥協したくないというのでislandコンポーネントのような仕組みは非常に良いです。


というわけでいろいろ過程はすっ飛ばしてサンプルリポジトリです。

https://github.com/ohmyteeth/honox-cloudflare-pages-lp-sample


islandコンポーネントのスタイルをTailwindでやっています。

```tsx
import { useState } from 'hono/jsx';

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <div class="text-center">
      <p class="text-red-500">{count}</p>
      <button class="h-10 outline-none border rounded-md px-6 hover:bg-neutral-50" onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  )
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/f4115434-86c9-cee1-19fe-50da257bab71.png)

LPを作成する時は基本的に画像を縦に並べることが多いので、mdxでひたすら画像を並べるような構成にすると爆速でLPを作ることができます。

```md
---
title: Hello World
---

import Counter from '../islands/Counter';

![Hello World](/static/no_image.png)

<Counter />

```

画像の間にインタラクティブなコンテンツがある場合にislandコンポーネントを挟んだりします。

これがすごく開発体験が良い。

そんなこんなで完成した実際のLPはこちら。

[https://lp.oh-my-teeth.com/lp105/](https://lp.oh-my-teeth.com/lp105/?tags=qiita_honox)
(もし興味がある場合はそのまま予約していただいても大丈夫です:pray:)

ボタンによる要素の切り替えやIntersectionObserverによるCTAボタンの表示切り替えもislandコンポーネントを活用することでうまく実現できています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/d57f9268-eac9-17cd-62db-c8a788b0207b.png)


今までLP開発は歴史的経緯もあり、レガシーなhtmlを直接編集のようなことをやっていたのですが、この仕組みを導入したことで飛躍的に開発スピードを上げることができました。

なにより、レガシーhtmlを編集する時の精神的な辛さから解放されたのが一番大きいです。

これ以外にもLPは大量に作成するためmdxをコピペするだけで増やせるのも良い点ですね。

パラメータ類はmdxのfrontmatterで出し分けたりもできるので、レガシーhtml手書き時代ではパラメータの変更漏れみたいなこともちょこちょこ発生していましたが、仕組みで解決することができました。

# 終わりに

長々と書いてしまいましたが、HonoとHonoXはめっちゃ良いぞというのを伝えたい記事でした。

mdxでislandコンポーネントを使う場合、プロダクションビルド時にスクリプトが動かない問題があるので、下記の記事にあるライブラリを使用しています。感謝:pray:

https://tech.natsuneko.blog/entry/2024/10/26/203645

これらをCloudflare Pagesにデプロイすれば簡単に本番として利用できるのでこれもまためちゃくちゃ便利ですが、その話は別の記事で書こうかなと思います。

Honoはいいぞ。

サンプルリポジトリ：

https://github.com/ohmyteeth/honox-cloudflare-pages-lp-sample


# Oh my teethについて
Oh my teethでは未来の歯科体験を創るために日々活動しています。

Techチームではより良いユーザー体験を提供するべく、Webフロントエンドからバックエンド、スマホアプリに機械学習モデルなど、さまざまなプロダクトを開発しています。

一緒に未来の歯科体験を創りませんか？興味がある方は是非こちらを確認してください。

https://oh.careers/

カジュアル面談も可能なので気軽に応募してみてください！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3192685/0138b492-e02b-852e-61fa-fc065b53d285.png" width="450" />