HonoXでブログをつくってみたい
HonoというTypeScriptフレームワークをご存知でしょうか?
まだまだ知名度は低いですが、Web標準に準じていてとても優れたフレームワークです。
HonoXは便利な機能が追加されたHonoのメタフレームワークでJSXが使えたり、ファイルベースルーティングなのでReactのNext.jsに近いですね。
今回はそのHonoXを使ってサイトをWordPress製のコーポレートサイトにあるようなシンプルなブログ一覧・詳細ページを構築してみてみます。
HonoXとは
HonoXとはどんなものかを紹介させていただきました。ぜひご覧ください。
microCMSとHonoXでブログページをつくる
ブログページなので記事を投稿する機能が必要です。CMS(コンテンツ管理システム。記事の投稿、画像の管理などができる)はWordPressが知られています。
今回は国産のヘッドレスCMSサービスのmicroCMSを採用しました。
NotionをCMSとすることも検討しましたが、決めた理由は単純に使ってみたかった。相性が良さそうだったからです。
microCMSにコンテンツをアップして、それをAPIで取得し、投稿内容を表示させます。
デザインはAIにお任せします
基本的なデザインについてはAntigravityでGemini3.0を使って作ってもらいました。
フレームワークの機能などを試しながら学習したいときには、本筋ではないところで時間をかけるのはしんどいので本当に便利ですね。
ブログ機能をついたおしゃれなコーポレートサイトを作りたいと思います。
機能はブログ、会社概要、事業案内、プライバシーポリシーなど一般的なもの。
デザインはhttps://xxxxxx.com,https://xxxxxx.dev,https://xxxxxx.co.jp,https://xxxxxx.jpを参考にしてください。
グラデーションやシャドウは抑えめで。フォントはHelvetica、Noto Sans JPを使ってください。スタイリングはTailwindCSSでお願いします。
みたいな感じでお願いしました。
出来上がったサイトがこんな感じです。いい感じです。
HonoXとmicroCMS SDKのインストール
npm create hono@latest
でHonoをインストールし、テンプレートでx-basicを選択してします。これでHonoXの導入ができます。
続いて、microCMSでSDKが用意されているので、インストールしていきます。
npm install microcms-js-sdk
requireのエラー
microCMSのSDKをインストールすると、requiredに関するエラーが表示されました。
require is not defined
これはmicroCMSのSDKがCommonJSを使ったライブラリに依存していることが原因のようです。vite.config.tsのplugins[]の下に、
export default defineConfig({
plugins: [
honox({
devServer: { adapter },
client: { input: ["/app/client.ts", "/app/style.css"] }
}),
tailwindcss(),
build()
],
ssr: { external: ["microcms-js-sdk"] } // Viteでバンドルせず、Node.jsに任せる
});
を追記して回避しました。
microCMSでAPIを作成する
次にmicroCMSで投稿するためのAPIを作成していきます。
今回、項目としたのは
- タイトル
- スラッグ
- カテゴリー
- 公開日
- コンテンツ
- アイキャッチ
microCMSはスキーマの追加、並び替えも直感的でわかりやすいです。
スラッグとは?
URLの末尾に使われる「記事の名前」のようなものです。例えば https://example.com/news/my-first-post というURLがあった場合、最後の my-first-post の部分がスラッグです。WordPressではお馴染みで数字のIDよりも、中身がなんとなく分かる英数字にしておくと、見る人にも検索エンジンにも親切です。
記事を登録する
APIが作成できたので、記事を登録しましょう。
記事の内容とアイキャッチ画像はすべてGoogleのAI(Gemini3.0とNano Banana Pro)で作成しました。
microCMSではリクエストをシミュレーションができ、どのようなレスポンスが返ってくるかを見ることができます。
Postmanやアプリケーションから呼び出さなくても、リクエストがどのようにすればいいのか。レスポンスがどう返ってくるのかが事前にわかるので助かります。
環境変数の設定と取得
エディターに戻り、.envファイルを作成し、取得したAPIやエンドポイントを登録しましょう。
MICROCMS_SERVICE_DOMAIN=your-service-domain
MICROCMS_API_KEY=your-api-key
クライアント設定と型定義
APIを作成できたので、続いてmicroCMSからデータを取得するためのクライアント設定とTypeScriptの型定義を行います。
appの下にlibフォルダを作成し、microcms.tsを作成しました。
app/
├── lib/
│ └── microcms.ts ← ここに実装
Honoでは環境変数の取得をヘルパー関数env()でランタイムごとの差異を吸収して、Node.jsではない環境(Deno、AWS Lambdaなど)でもうまく変換してくれて正しく環境変数を取得することが可能になります。
型はSDKのtypes.tsを確認します。
import { createClient } from "microcms-js-sdk";
import { env } from "hono/adapter";
import type { Context } from "hono";
import type { MicroCMSImage, MicroCMSDate } from "microcms-js-sdk";
export const getMicroCMSClient = (c: Context) => {
// env()を使用して環境変数を取得(ランテイムに依存しない方法)
const { MICROCMS_SERVICE_DOMAIN, MICROCMS_API_KEY } = env<{
MICROCMS_SERVICE_DOMAIN: string;
MICROCMS_API_KEY: string;
}>(c);
return createClient({
serviceDomain: MICROCMS_SERVICE_DOMAIN,
apiKey: MICROCMS_API_KEY,
});
};
// ブログ記事の型定義
export type Blog = {
id: string;
title: string;
slug: string;
content: string;
eyecatch?: MicroCMSImage;
category: {
id: string;
name: string;
}[];
} & MicroCMSDate;
記事の一覧ページに記事一覧を表示する
それでは記事を実際に表示させていきます。
HonoXはファイルベースルーティングでroutesフォルダに.tsxファイルを作成することで簡単にルーティングできます。今回はブログ一覧ページとスラッグごとのページを作成するためblogsフォルダを作成。その中にindex.tsxと[slug].tsxを作成しました。
- index.tsx・・・ブログ一覧ページ
- [slug].tsx・・・記事詳細ページ
HonoXでは、ファイル名に [slug] のようなブラケット付きの名前を使うことで、動的なルートパラメータとして扱うことができます。
app/
├── routes/
│ ├── index.tsx
│ └── blogs/
│ ├── index.tsx
│ └── [slug].tsx
データの取得と表示
microCMS SDKではgetListで記事の一覧のデータが取得できます。
後は、それをmap()メソッドで展開すればOKです。
import { createRoute } from "honox/factory";
import { getMicroCMSClient } from "../../lib/microcms";
import type { Blog } from "../../lib/microcms";
export default createRoute(async (c) => {
const title = "ブログ";
// MicroCMSからデータを取得
const microcmsclient = getMicroCMSClient(c);
const blogsItems = await microcmsclient.getList<Blog>({
endpoint: "blogs",
});
~~中略~~
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-16">
<div class="space-y-8">
{blogsItems.contents.map((blog) => (
<a href={`/blogs/${blog.slug}`} class="block no-underline"> // 記事ごとのリンク
<article class="flex flex-col md:flex-row gap-6 p-6 rounded-xl hover:bg-gray-50 transition duration-300 border-b border-gray-100 last:border-0">
<div class="md:w-48 flex-shrink-0 flex flex-col items-start">
<time class="text-sm text-gray-500 font-medium mb-2">
{blog.publishedAt} // 公開日
</time>
<span
class={`inline-block px-3 py-1 text-xs font-semibold rounded-full
${
blog.category[0] === "リリース"
? "bg-blue-100 text-blue-800"
: blog.category[0] === "イベント"
? "bg-purple-100 text-purple-800"
: blog.category[0] === "採用"
? "bg-green-100 text-green-800"
: "bg-gray-100 text-gray-800"
}`}
>
{blog.category[0]} // ブログのカテゴリー
</span>
</div>
<div>
<h2 class="text-xl font-bold text-gray-900 mb-3 hover:text-orange-600 transition duration-200">
{blog.title} // ブログタイトル
</h2>
<p class="text-gray-600 leading-relaxed">
{(blog.content)
.replace(/<[^>]+>/g, "")
.slice(0, 100) + "..."} // ブログ本文を少しだけ表示させる
</p>
</div>
</article>
</a>
))}
</div>
~略~
記事詳細ページをつくる
記事の内容を表示するページにもコンテンツを反映させましょう。
詳細ページでは、URLのパスパラメータ(/blogs/article-slugの article-slug部分)を使ってmicroCMSから特定の一つの記事を取得して表示します。
import { createRoute } from "honox/factory";
import { getMicroCMSClient } from "../../lib/microcms";
import type { Blog } from "../../lib/microcms";
export default createRoute(async (c) => {
// URLのパスパラメータからslugを取得
const slug = c.req.param("slug");
// microCMSクライアントの初期化
const client = getMicroCMSClient(c);
// スラッグで記事を検索
const response = await client.getList<Blog>({
endpoint: "blogs",
queries: { filters: `slug[equals]${slug}` },
});
const blog = response.contents[0];
// 記事が見つからない場合は404ページを表示
if (!blog) {
return c.notFound();
}
const title = blog.title; // タイトルはブログのタイトル
return c.render(
<div class="bg-white">
<div class="relative h-96 bg-gray-900">
<img
src={blog.eyecatch?.url + "?fm=webp"} // 画像をWebpに変換して取得。microCMSは画像APIで加工も可能です。
alt={blog.title}
class="w-full h-full object-cover opacity-60"
/>
<div class="absolute inset-0 bg-gradient-to-t from-gray-900/80 to-transparent"></div>
</div>
{/* 記事コンテンツ */}
<article class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 -mt-32 relative z-10">
<div class="bg-white rounded-2xl shadow-xl p-8 md:p-12">
{/* メタ情報 */}
<div class="flex flex-wrap items-center gap-4 mb-8 pb-8 border-b border-gray-200">
<time class="text-sm text-gray-500 font-medium">
{new Date(blog.publishedAt!).toLocaleDateString()}
</time>
{blog.category && (
<span class="inline-block px-3 py-1 text-xs font-semibold rounded-full bg-blue-100 text-blue-800">
{blog.category[0]}
</span>
)}
</div>
{/* タイトル */}
<h1 class="text-3xl md:text-4xl font-bold text-gray-900 mb-8 leading-tight">
{blog.title}
</h1>
{/* 本文(HTMLをレンダリング) */}
<div
class="prose prose-lg max-w-none
prose-headings:font-bold prose-headings:text-gray-900 prose-headings:mt-8 prose-headings:mb-4"
dangerouslySetInnerHTML={{ __html: blog.content }} // HTMLとして解釈させる
/>
〜中略〜
</article>
</div>
, { title } // ページタイトルを設定できます
);
});
HonoXでブログページを作ってみて
HonoXとmicroCMSを組み合わせることで、高速でコンテンツ管理が簡単なブログサイトを構築することができました。
microCMSはSDKもあり、日本のサービスなので何か不明点あれば問い合わせもしやすいと思います。
ブログ投稿以外にも、トップページの画像やギャラリーサイトなどサイトのコンテンツをまとめて管理することもできます。無料でも十分使えるので、まずは使ってみてみるのをお勧めします。
HonoXを無料枠でCloudflare Workersにデプロイすれば、サイト運営費を削減できますね。
ぜひ皆さんも試してみてください!






