HonoXでブログを作り直した。そしてテンプレートも作った
目次
Intro
今回自分のブログをNext.jsからHonoXに書き換えをしました。あんまりまだ使ってる人いないと思うので、今後使ってみたい向けにブログとして残しておきます。
honox-blog-templeteを作った
最初に今後HonoXを使っていきたい方向けにhonox-blog-templeteというテンプレートリポジトリを作りました。
基本的にはyusukebeさんのhonox mdx exmapleで事足りるのですが、技術ブログを書きたい人はシンタックスハイライトの設定をしたり、フォーマッターの設定など色々することもあるかと思うので、その辺りを設定しておきました! サクッとブログを作りたい方は使ってみてください!
$ npm run create:post
を実行すると対話形式でブログのテンプレートを作れます!あとはブログを書いて、Cloudflare pagesなりにデプロイをすると完成です!UIはお好みでどうぞ!
感想
1. mdxがそのまま使えるのありがたい
https://github.com/honojs/honox?tab=readme-ov-file#mdxに書いてある内容です。
自分の場合は/app/posts
配下にmdxファイルをおいているんですが、ビルドするとhtmlファイルに変換されるので、そのままブラウザに表示させることができます。追加の設定もほぼいらないので、びっくりするほど簡単でした。
2. Hooksが使えるのありがたい
hono/jsxがReactと互換性があるため、Hooksを使うことができます。(https://hono.dev/guides/jsx-dom#hooks-compatible-with-react)
そのため、今回隠れた追加機能としていいね機能を追加したんですが、これにdebounce機能を用いる際にzennにあった参考のhooksをそのまま使うことができ、とても楽でした。
import { useEffect, useState } from "hono/jsx";
export function useDebounce(value: number, delay: number) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(timer);
};
}, [value, delay]);
return debouncedValue;
}
3. CI組んでprごとにpreviewにも出せるようにできた
自分は書いたブログごとにPRを出すようにしています。そうするとVercelだとpreview環境を用意してくれるためです。書いたブログのチェックで、最終確認を行いたい時にみます。
この体験は損ねたくなかったので、Cloudflare pagesでも同じことしたいと思い調べたところ、cloudflare/pages-action@v1を使うことでとても簡単に実現できました。
GitHub ActionsでビルドしてCloudflare Pagesにデプロイする ← このブログがとても参考になりました!pull_request.ymlにコードがあるので参考にしてみてくださいー!
3. Islandコンポーネントが_renderer.tsxで使うとscriptが読み込まれない
今回いいね機能とXへのシェアとフォローのボタンはisland配下に置いて、全てのブログページ下部で表示させるために_renderer.tsx
配下に置いています。
この場合表示はされるんですが、honox/serverのScirptコンポーネントでは使用上HasIsland
がtrueになった場合に本番環境でscirptが読み込まれるようになる仕様になっているみたいでした。
export const Script: FC<Options> = async (options) => {
const src = options.src
if (options.prod ?? import.meta.env.PROD) {
let manifest: Manifest | undefined = options.manifest
if (!manifest) {
const MANIFEST = import.meta.glob<{ default: Manifest }>('/dist/.vite/manifest.json', {
eager: true,
})
for (const [, manifestFile] of Object.entries(MANIFEST)) {
if (manifestFile['default']) {
manifest = manifestFile['default']
break
}
}
}
if (manifest) {
const scriptInManifest = manifest[src.replace(/^\//, '')]
if (scriptInManifest) {
return (
<HasIslands>
<script
type='module'
async={!!options.async}
src={`/${scriptInManifest.file}`}
></script>
</HasIslands>
)
}
}
return <></>
} else {
return <script type='module' async={!!options.async} src={src}></script>
}
}
scriptが読み込まれないので、インタクションが発生しても何も起きない状態が発生しません。
そのため、<HasIslands>
で囲まないようにしたScriptコンポーネントを自分の方で用意することにしました。
ただ絶対この方法良くないと思うので、なんかいい方法あれば教えていただきたいです🙇♂️
https://twitter.com/yusukebe/status/1765727221526983014 ← Xでyusukebeさんにお聞きしたところ直していいとのことなので、今頑張って開発しています。また進捗があれば共有します。
まとめ
個人的には開発体験良くて、Cloudflare pagesへのデプロイも爆速だったので流行って欲しいなと思います! あと今回npm使ったけどbunにしてみたいし、もうちょっとislandの恩恵を感じられるようなインタラクション多めのアプリでも採用してみたいです!
ぜひ皆さんもHonoX使ってみてくださいー!!🔥
0