:::: MENU ::::

ブログの静的html出力を microCMS+Astro+Cloudflare 構成を変えました

ローカルにDockerで動かしているWordPressを当ブログの執筆環境にしていたが、バージョンアップ等で動作がおかしくなっていたので構成をちょっとモダンにしました。

構成

  • 記事執筆環境
  • Webフレームワーク
  • ビルド&デプロイ
    • GitHub → Cloudflare


データのエクスポート&インポート

WordPressからのエクスポートは標準の機能を使ってXMLで出力。
wpparserを使ってパースして、microCMS API使ってインポート。

CSVインポートもできますが、現時点では空の状態じゃないとインポートできず再試行しにくいのでAPIで入れてます。

import json
import requests
import wpparser

data = wpparser.parse("./wordpress.2023-02-21-1.xml")
headers = {
  'Content-Type': 'application/json',
  'X-MICROCMS-API-KEY': MICROCMS_API_KEY
}

for post in data["posts"]:
  if post["post_type"] == "post":
    path = post['link'].split('/')[-2]
    payload = {
      "title": post['title'],
      "pubDate": post['pub_date'],
      "content": [
        {
          "fieldId": "html",
          "text": post['content'],
        }
      ],
      "categories": post['categories'],
      "tags": post['tags']
    }
    res = requests.put(f"{MICROCMS_API_ENDPOINT}/{path}", json=payload, headers=headers)
    print(res.json())


microCMSのAPI設計

microCMSのフリープランを使っているので使えるAPIは3つまで。
以下のようにWordPressの代替となるAPIを定義。

  • blog
    • WordPressの投稿
  • tag
    • WordPressのカテゴリー兼タグ
  • page
    • WordPressの個別ページ


レイアウトをガッツリ決めている記事はblogで、レイアウトを比較的緩く作れるのがpageという感じで使い分けてます。

Astroでの組み方

Astro Islands に則りコンポーネント単体で完結するように作るのがいいのだろうが、今回はWordPressからの移行なのでただのパーツ分けだけします。
WordPressテーマの時点でHeader/Footer/Aside/Navあたりは分かれていると思うので、コンポーネントは一旦それを踏襲。

記事部分の基礎的な実装はmicroCMSのブログにある通りやっていけば組めます。
AstroとmicroCMSでつくるブログサイト | microCMSブログ

あとブログに必要なものは公式ドキュメントにある通り実装していけばOK。


SSGの速度改善

microCMSのブログでは1ページずつmicroCMSからデータ取得する書き方をしているが、これだと遅いし通信に無駄が多いので改善します。
以下の対応をするだけで3倍くらいページ生成が速くなりました。

静的パス定義時のpropsに記事の中身も一緒に入れる

静的パスを定義するときにmicroCMSから取得した情報をpropsとして渡すことで、1ページごとに情報を取得する必要がなくなります。

export async function getStaticPaths() {
  const response = await cmsBlog.getBlogs({
    limit: import.meta.env.MICROCMS_DEFAULT_LIMIT,
  });
  return response.contents.map((content: any) => ({
    params: {
      contentId: content.id,
    },
    props: {
      post: content,
    },
  }));
}

microCMSから取得した情報をキャッシュする

ページビルド時にコンポーネントもページごとに再生成してしまうっぽくて、コンポーネント内でデータ取得していたら1ページごとにデータ取得が行われます。
さらにAstroにはFetchした情報をキャッシュする機構もまだありません。これらの機能はAstroのGitHubで機能提案はされてますが、まだRFC前でロードマップには載ってない状態です。

実装されるのを待ってもいられないので、モジュール追加してキャッシュ対応しました。

import { Cache, CacheContainer } from "node-ts-cache";
import { MemoryStorage } from "node-ts-cache-storage-memory";

const userCache = new CacheContainer(new MemoryStorage());

class CMSBlog {
  // ブログ記事一覧
  @Cache(userCache, { ttl: 300 })
  public async getBlogs(queries?: MicroCMSQueries) {
    return await client.get<BlogResponse>({ endpoint: "blog", queries });
  }
}
export const cmsBlog = new CMSBlog();


Cloudflareへのデプロイ

GitHubにpushするとCloudflare Pagesにデプロイされます。
もしくはmicroCMSの記事更新を行うとWebhookでCloudflare Pagesの再デプロイが行われます。
このあたりはCloudflareやmicroCMS側が用意してくれた仕組みを使うだけなので設定するだけでいいのは楽ですね。

Cloudflare側のドメイン設定とかは長くなりそうなので、また別の記事にでも書きます。

最後に

データ移行はWordPressのXMLを綺麗にパースしてくれるライブラリがあったので比較的簡単に移すことができましたし、microCMSやAstroの公式ドキュメントがかなり充実していて、ほとんどそこにある情報で組むことができました。
4年置きくらいにブログ執筆&ホスティング環境をまるっと変えてますが、毎回楽になったなぁと技術進歩を感じて勉強になりますね。

Astroはまだ2.0になったばかりのフレームワークなので足りない機能はまだありますが、主要な機能は揃っているので十分使えるレベルのものだと感じてます。
なによりNext.jsよりも気軽に使えていいですね。AstroだけじゃなくSvelteも良さそうなので、このあたりは今後の動向を追っていきたいところ。

Cloudflareはまだまだ使ったことのない機能が大量にありますが、Pagesだけ使うだけならNetlifyやVercelと同じくらい気軽に使えていい感じです。
今回Pages使い始めたことですし、気になってたD1やR2も使って遊んでみようと思います。