1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

microCMSとHonoXでブログページを作ってみる

Last updated at Posted at 2025-12-08

HonoXでブログをつくってみたい :fireworks:

HonoというTypeScriptフレームワークをご存知でしょうか?
まだまだ知名度は低いですが、Web標準に準じていてとても優れたフレームワークです。
HonoXは便利な機能が追加されたHonoのメタフレームワークでJSXが使えたり、ファイルベースルーティングなのでReactのNext.jsに近いですね。

今回はそのHonoXを使ってサイトをWordPress製のコーポレートサイトにあるようなシンプルなブログ一覧・詳細ページを構築してみてみます。

HonoXとは

HonoXとはどんなものかを紹介させていただきました。ぜひご覧ください。

microCMSとHonoXでブログページをつくる :fire:

ブログページなので記事を投稿する機能が必要です。CMS(コンテンツ管理システム。記事の投稿、画像の管理などができる)はWordPressが知られています。

今回は国産のヘッドレスCMSサービスのmicroCMSを採用しました。
NotionをCMSとすることも検討しましたが、決めた理由は単純に使ってみたかった。相性が良さそうだったからです。
microCMSにコンテンツをアップして、それをAPIで取得し、投稿内容を表示させます。

デザインはAIにお任せします :flag_ai:

基本的なデザインについてはAntigravityでGemini3.0を使って作ってもらいました。
フレームワークの機能などを試しながら学習したいときには、本筋ではないところで時間をかけるのはしんどいので本当に便利ですね。

ブログ機能をついたおしゃれなコーポレートサイトを作りたいと思います。
機能はブログ、会社概要、事業案内、プライバシーポリシーなど一般的なもの。

デザインはhttps://xxxxxx.com,https://xxxxxx.dev,https://xxxxxx.co.jp,https://xxxxxx.jpを参考にしてください。
グラデーションやシャドウは抑えめで。フォントはHelvetica、Noto Sans JPを使ってください。スタイリングはTailwindCSSでお願いします。

みたいな感じでお願いしました。
出来上がったサイトがこんな感じです。いい感じです。

2025-12-09 0.00の画像.jpeg

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[]の下に、

vite.config.ts
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はスキーマの追加、並び替えも直感的でわかりやすいです。

スクリーンショット 2025-12-08 23.04.00.png

スラッグとは?
URLの末尾に使われる「記事の名前」のようなものです。例えば https://example.com/news/my-first-post というURLがあった場合、最後の my-first-post の部分がスラッグです。WordPressではお馴染みで数字のIDよりも、中身がなんとなく分かる英数字にしておくと、見る人にも検索エンジンにも親切です。

記事を登録する

APIが作成できたので、記事を登録しましょう。
記事の内容とアイキャッチ画像はすべてGoogleのAI(Gemini3.0とNano Banana Pro)で作成しました。

スクリーンショット 2025-12-08 23.06.47.png

microCMSではリクエストをシミュレーションができ、どのようなレスポンスが返ってくるかを見ることができます。
Postmanやアプリケーションから呼び出さなくても、リクエストがどのようにすればいいのか。レスポンスがどう返ってくるのかが事前にわかるので助かります。

スクリーンショット 2025-12-08 23.09.13.png

環境変数の設定と取得

エディターに戻り、.envファイルを作成し、取得したAPIやエンドポイントを登録しましょう。

.env
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を確認します。

microcms.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;

記事の一覧ページに記事一覧を表示する :page_facing_up:

それでは記事を実際に表示させていきます。
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です。

index.tsx(記事一覧ページ)
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>

 

スクリーンショット 2025-12-09 0.21.44.png

記事詳細ページをつくる

記事の内容を表示するページにもコンテンツを反映させましょう。
詳細ページでは、URLのパスパラメータ(/blogs/article-slugarticle-slug部分)を使ってmicroCMSから特定の一つの記事を取得して表示します。

[slug].tsx(記事詳細ページ)
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 } // ページタイトルを設定できます
  );
});

スクリーンショット 2025-12-09 0.20.52.png

HonoXでブログページを作ってみて

HonoXとmicroCMSを組み合わせることで、高速でコンテンツ管理が簡単なブログサイトを構築することができました。

image.png
特に対策はしていませんが、スコアは高かったです。さすが!

 
microCMSはSDKもあり、日本のサービスなので何か不明点あれば問い合わせもしやすいと思います。
ブログ投稿以外にも、トップページの画像やギャラリーサイトなどサイトのコンテンツをまとめて管理することもできます。無料でも十分使えるので、まずは使ってみてみるのをお勧めします。

HonoXを無料枠でCloudflare Workersにデプロイすれば、サイト運営費を削減できますね。

ぜひ皆さんも試してみてください!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?