【Astro × Hono】Cloudflare Pagesで、静的サイトに「認証付きプレビュー機能」を実装する

はじめに

Astroなどの静的サイトジェネレーター(SSG)は爆速ですが、唯一の弱点が 「下書き記事のプレビューができない(ビルドが必要)」 ことです。

これを解決するために、Cloudflare Pages Functions 上で Hono を動かし、特定のリクエストだけ動的にレンダリング(SSR)する仕組みを実装しました。

「普段は静的で速く、必要な時だけ動的」というハイブリッド構成のレシピを紹介します。


アーキテクチャ

  • 一般ユーザー: ビルド済みのHTMLを返す (SSG)
  • 編集者: /api/preview にアクセスした時だけ、Edge上のHonoがNotion APIを叩いてHTMLを生成して返す (SSR)

1. 準備 (パッケージ導入)

AstroでCloudflareとHonoを使うための準備をします。

bash
npm install hono @astrojs/cloudflare

astro.config.mjsserver (または hybrid) モードに変更します。

javascript
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server', // SSRを有効化
  adapter: cloudflare(),
});

2. HonoによるプレビューAPIの実装

src/pages/api/preview.ts を作成し、Honoのエンドポイントを定義します。

typescript
import { Hono } from 'hono';
import { Client } from '@notionhq/client';

const app = new Hono();

app.get('/api/preview', async (c) => {
  // 1. クエリパラメータの取得
  const slug = c.req.query('slug');
  const secret = c.req.query('secret');

  // 2. シークレットキーによる簡易認証
  // 環境変数 PREVIEW_SECRET と一致するかチェック
  if (secret !== c.env.PREVIEW_SECRET) {
    return c.text('Unauthorized', 401);
  }

  if (!slug) {
    return c.text('Missing slug', 400);
  }

  // 3. Notion APIから「Draft」状態の記事を取得
  const notion = new Client({ auth: c.env.NOTION_API_SECRET });
  const response = await notion.databases.query({
    database_id: c.env.NOTION_DATABASE_ID,
    filter: {
      and: [
        { property: 'Slug', rich_text: { equals: slug } },
        // ここではStatusがDraftでも取得できるようにする
      ],
    },
  });

  const page = response.results[0];
  if (!page) {
    return c.text('Post not found', 404);
  }

  // 4. HTMLのレンダリング (簡易的な例)
  // 本来はAstroのコンポーネントを再利用したいですが、
  // APIルート内では文字列として組み立てるか、リダイレクトで処理します。
  // ここではシンプルにタイトルを表示します。
  const title = page.properties.Name.title[0]?.plain_text;

  return c.html(`
    <!DOCTYPE html>
    <html>
      <head><title>Preview: ${title}</title></head>
      <body>
        <h1>[Preview] ${title}</h1>
        <p>これは下書きのプレビューです。</p>
      </body>
    </html>
  `);
});

export default app;

3. 環境変数の設定

Cloudflare Pagesの管理画面で、以下の環境変数を設定します。

  • PREVIEW_SECRET: 任意のパスワード(例: my-super-secret-key
  • NOTION_API_SECRET: Notionのインテグレーションキー

4. 使い方

ブラウザで以下のURLにアクセスします。

https://my-site.com/api/preview?slug=my-draft-post&secret=my-super-secret-key

認証が通れば、Notion上で「Draft」状態の記事でも、ビルドなしで即座に内容が表示されます!


まとめ

HonoをEdgeで動かすことで、静的サイトの中に「動的な裏口」を簡単に作ることができました。これぞハイブリッドアーキテクチャの醍醐味です。

宣伝

このプレビュー機能を標準搭載したNotionブログ構築キット 『Astro Notion Edge』 をOSSで公開しました。 Notionで記事を書いて、WordPressより速く配信したい方はぜひ使ってみてください! https://github.com/miya025/astro-notion-edge

#Astro #Hono #Cloudflare #Notion