Skip to content
ik-fib's page
Go back

このブログをWordPressからAstroに移行した話

14年間WordPressで運用してきたこのブログを、Astro + Cloudflare Workers による静的サイトに移行しました。その作業ログを記録に残しておく意味で、記事にまとめました。

はじめに

このブログは2012年にWordPressで開設し、2019年にはサーバをGoogle Cloud Platformに移行して運用を続けてきました。

しかし、記事を書く頻度に対して、WordPress本体・プラグイン・PHP・サーバOSの更新といったメンテナンス作業の負担が大きく、「書くより維持の方が大変」な状態が続いていました。正直ここ数年は最低限のメンテナンスはしていましたが、記事を書きたくなったときにもサーバ側の更新やWordPressの更新を先にやらないとな…という状態になっており、逆に記事を書くハードルになっていました。さらに、移行作業中に調べてみると、コードブロック内のXMLがプラグインの劣化で一部表示されなくなっていたり、ダウンロードリンクのプラグインが動かなくなって生のショートコードが表示されていたりと、気づかないうちに壊れている箇所がいくつも見つかりました。

そこで、以下を目標に静的サイトへの移行を決めました。

移行先の構成

移行前移行後
CMS/SSGWordPress (Bitnami)Astro + AstroPaper テーマ
ホスティングGoogle Compute EngineCloudflare Workers (static assets)
コンテンツ管理MySQLmarkdown + GitHub
デプロイ-push → Cloudflare Workers Builds で自動ビルド
全文検索プラグインPagefind(AstroPaper標準装備)
サーバ費用GCE インスタンス代(ほぼ0円)0円

SSGはHugoとも比較しましたが、記事数が100件程度でビルド速度の差が問題にならないこと、TypeScriptとの親和性から Astro にしました。

移行の方針

一番こだわったのは旧URLの保全です。2012年からのURL資産(検索インデックス・外部リンク)を無駄にしないため、以下をすべて301リダイレクトで新URLに接続しました。

リダイレクトは Cloudflare の _redirects ファイル(400ルール超)で、WordPressのエクスポートデータから自動生成しています。

移行手順

大まかなパイプラインは以下のとおりです。

  1. WordPressの管理画面から WXR (XML) をエクスポート
  2. 前処理: <pre> 内の生タグをエスケープするサニタイザを通す(後述のハマりポイント対策)
  3. wordpress-export-to-markdown で markdown に一括変換
  4. 後処理スクリプト(自作)で以下を修正
    • slug・投稿日時をWXRの値で上書き(変換ツールのタイムゾーンずれ対策)
    • 画像URLをルート相対に書き換え(wp-content/uploads を同一パスのまま public/ に配置)
    • gist埋め込み・数式・各種ショートコードの残骸を修復
    • _redirects の自動生成
  5. 全記事 draft: true で投入し、新旧のレンダリング結果を突き合わせてから順次公開

ハマったポイント

変換ツールの日付がUTCで月がずれる

wordpress-export-to-markdown の出力する日付はUTC基準のため、月初深夜に公開した記事(元日の挨拶記事など)が前月扱いになり、/2015/01/... のURLの記事が 2014-12-31 になっていました。日付はWXR側の値(JST)を正として上書きすることで解決しました。

コードブロック内の生XMLがHTMLとして解釈されて消える

昔の記事は <pre> 内にXMLをエスケープせずに書いており、ブラウザにも変換ツールにもタグとして解釈されてコードが部分的に消えていました。移行前のWordPress上でもすでに欠けて表示されていたので、これは移行を機にWXRの原文から復元できた改善点です。

gist埋め込み・Twitter埋め込みが裸のURLになる

WordPressのoEmbed(URLを貼るだけで埋め込みになる機能)はmarkdown変換で単なるURL文字列になってしまうため、gistは <script> 埋め込みに、ツイートは埋め込みblockquoteに、後処理で自動変換しました。汎用のURLは remark-link-card-plus でリンクカード化しています。

Cloudflareの _redirects は「splat以降が全部動的扱い」

/author/* のようなワイルドカード(splat)ルールをファイル前方に置いたところ、それ以降の全ルールが動的リダイレクト扱いになり、動的100件制限を超えてデプロイが失敗しました。splatは必ずファイル末尾に置く必要があります。エラーメッセージからは原因が分かりにくく、一番ハマったポイントです。

wranglerの自動設定がSSRアダプタを入れようとする

wrangler deploy は設定ファイルがないとフレームワークを自動検出して astro add cloudflare(SSRアダプタ)を実行し、Workersで動かない sharp(Node.js の画像処理ライブラリ)の読み込みでビルドが失敗しました。静的サイトなら wrangler.jsoncassets 設定を書いておけば回避できます。

AIエージェントと一緒に移行した

今回の移行作業は、Claude(AIエージェント)とペアで進めました。特に効いたのが新旧レンダリングの差分チェックです。

移行記事は101記事なので、最悪すべて目視確認できないことはないですが、非常に時間がかかってしまいます。そのため、移行した101記事すべてについて、稼働中の旧サイトのHTMLと新サイトのビルド結果から本文を抽出して突き合わせ、記事ごとに差分スコアを算出。スコアが高い(差分が小さい)91記事は一括公開し、残り10記事だけを人間が目視レビューする、という進め方をしました。前述のハマりポイントの多く(コードブロックの欠損、gistの裸URL化など)は、この差分チェックが機械的に検出したものです。

結果

Lighthouse(トップページ・デスクトップ、シークレットウィンドウで計測)のビフォーアフターも取りました。スコアだけでなく、Largest Contentful Paint・Speed Index・Cumulative Layout Shift の改善がそのまま体感差になっています。

指標WordPressAstro
Performance8499
Accessibility84100
Best Practices73100
SEO83100
First Contentful Paint0.9 s0.6 s
Largest Contentful Paint1.7 s0.8 s
Cumulative Layout Shift0.1260
Speed Index2.2 s0.6 s

なお公平のための補足として、旧サイトにはGoogle AdSenseが入っていましたが、新サイトにはまだ入れていません。スコア差にはその影響も含まれています。

WordPress時代のLighthouseスコア

移行前(WordPress)

移行後(Astro)のLighthouseスコア

移行後(Astro)

最後に

2012年から14年間、同じ静的IPで動き続けてくれたWordPressサーバともうすぐお別れです。長い間ありがとうございました。

移行の詳しい設計判断(なぜAstroか、コメント機能をどうしたか等)や各スクリプトについて、気になる方がいればX等で聞いてください。


Share this post:

Next Post
オープンソースのAMS「BMCU」を試してみたけど、素人にはおすすめできない4つの理由

Related Posts