CMSを削除してビルド時間を1/3に短縮した話

Article by:

 
 

Sentryでは、ものが壊れないことに執念を燃やし、それこそが私たちの存在意義だと考えています。しかしかつて、自社のマーケティングサイトがその信念を揺るがしてしまう時期がありました。

sentry.io 上で皆さんが目にするもの(マーケティングサイト、ブログ、オープンソースのマイクロサイトなど)の多くは、従来のヘッドレスCMSを基盤とした古いGatsbyサイト群で動いていました。理論上は機能していましたが、実際には壊れやすいプラグインの寄せ集め、制限の多いスキーマ、そして肝心な出荷タイミングに限って失敗する外部API依存に振り回されていました。

そこで私たちは、まともなエンジニアリングチームなら当然そうするように、それをすっぱり捨てて、Astro、Markdown、AI駆動の自動化で置き換えました。

 

 

問題:「ヘッドレス」という頭痛の種

旧スタックは、不必要に複雑な代物になりつつありました。

  • ビルドのボトルネック:Gatsbyの統合データレイヤーは便利でしたが、コンテンツが増えるにつれてビルド時間は1回あたり約14分に膨らんでいました。1日平均95回のビルドを行っていたため、毎日約22時間分のビルド時間を消費していました。

  • CMSのコスト:約2,500ページのコンテンツを1つのCMSインスタンスで管理していました。ページスキーマとコンポーネントスキーマが並立しており、条件付きフィールドが使えなかったため、スキーマの上限に達しないよう条件付きフィールドのプラグインを別途購入する羽目になりました。月額サブスクリプションに加えて年間サブスクリプションのコストも重なり、それでもスケーラビリティは限られたままでした。

  • 外部依存の脆さ:すべてのビルドがGatsbyプラグイン経由で外部のCMSとマーケティングオートメーションシステムのAPIに依存していました。リビルド開始前の最後の1か月で、CMSのGatsbyプラグインが1日に3〜5回失敗し(サポートチケットを提出しても解決策はなし)、マーケティングオートメーションAPIもレート制限で1日に複数回失敗していました(詳しくは後述)。

 

 

 

解決策:Astroと「ただのファイル」の力

フレームワークをAstroに移行しました。モダンなWeb向けに設計されており、デフォルトで高速、そして驚くほど柔軟性が高いことを選定理由としました。

  • Viteによる高速化:Viteへの移行により、ローカル開発と本番ビルドがようやく2026年らしい速度になりました。ビルド時間は約14分から4分未満に短縮され、1日あたり約15.8時間分のビルド時間を節約できています。

  • フレームワーク非依存:Astroは目的に最適なツールを使う自由を与えてくれます。コンポーネントにReactが適していればReactを使い、シンプルな静的コンテンツであればHTML/CSSで済みます。

  • Vercelに重い処理を任せる:画像処理をVercelにオフロードすることで、ビルドプロセスを遅らせることなくアセットを最適化できています。

 

しかし最大の変化はフレームワークではなく、コンテンツの管理方法でした。ヘッドレスCMSのUIをMarkdownとFrontmatterに置き換えたのです。

 

 

AIネイティブなコンテンツ管理(SaaSの肥大化なし)

CMSプロバイダーの「AIアドオン」にお金を払う代わりに、Claude Skillsとの直接連携を自前で構築しました。

今ではサイトを更新する際、肥大化したダッシュボードにログインする必要はありません。スキルを使ったワークフローで作業します。


1. ユーザーをガイドしながら、MarkdownファイルとFrontmatterを正確に更新するプロセスを進めます。

2. ライブプレビューを生成します。

3. レビュー用のPull Requestの下書きを作成します。

CMS統合AIを使わず、なぜカスタム構築にしたのか。

  • 依存ゼロ:コンテンツはリポジトリに置かれます。APIの障害がなければビルドの失敗もありません。
  • スキーマの制限なし:Frontmatterで構造を自分たちで定義します。新しいフィールドやスキーマタイプが必要になれば、追加するだけです。サブスクリプションの制限も、プランの縛りもありません。
  • 「Sentryらしい」やり方:深い技術志向を持つデベロッパーファーストの企業として、コンテンツをコードとして管理することは自然な選択です。バージョン管理され、ピアレビューされ、レンダリングするコンポーネントのすぐそばに置かれます。

 

 

 

実施プロセス

マーケティングサイトとブログ合わせて約2,500ページのサイトを移行するのは、大規模なプロジェクトです。チームは2.5人の開発者で、期間は2か月でした。

チームが小さく、サイトの規模が大きかったため、コーディングの多くをClaude Codeに頼りました。開発者たちは計画立案、スコープ定義、要件整理に時間の大半を費やし、コードのレビュー、変更の指示、アウトプットの調整を行いました。

 

スコープ定義

このプロジェクトでは、次の2つの理由からスコープ定義が比較的容易でした。

  • これらのWebサイトにはモノレポを使用しているため、ボットがビルド・移行対象の全体像を把握できていた。
  • 新規のデザインを実装しなかった。

 

既存のコードベースで数年間作業してきたこともあり、コードの肥大化を除去できそうな箇所についてのアイデアはありました。特定のディレクトリ内のページを詳しく調べてそれを検証し、コンテンツの内容に基づいて独自ページをテンプレートに統合して削減しました。その結果、約200ページを3つのテンプレートに集約でき、サイトがDRYになり、保守がはるかに容易になりました。

 

ボットを使ったビルド

まずデータから着手しました。ヘッドレスCMSはGatsbyサイトとAstroサイトの既存部分の両方に接続されており、CMSは各スキーマのJSONファイルを提供していました。そこで計画エージェントに既存のCMSスキーマを渡し、Frontmatterとして複製させました。すでにCMSのAPIに接続していたため、エージェントスウォームにデータを取得させ、Frontmatterファイルにマッピングし、画像をローカルに保存させました。画像最適化が必要な非メタ画像はすべて asset として、SEO画像は public ディレクトリに保存しています。

データが揃った後、計画エージェントにGatsby内の既存テンプレートファイルの場所、新フレームワーク内での配置先、使用するデータを伝え、不明な点があればインタビューするよう依頼しました。計画エージェントはビルドテストを汎用エージェントに渡し、そのエージェントがテスト用の汎用エージェントへと引き継ぎました。

そのラウンドの後、チームがリグレッションをレビューして修正し、SentryのSeer AIコードレビューツールとCursorのBugbot(シークレットスキャンや標準自動テストを含むリポジトリの品質チェックと合わせて)によるAI PRレビューが続きました。

 

ボットを使ったテスト

開発プロセスの一環として、Playwrightによるビジュアルリグレッションテストとチームが自作したMCPをClaude Codeで動かし、GatsbyサイトとAstroの新サイトのビジュアル要素を比較する実験を行いました。

 

DOM InspectorのMCP

チームのDylan Cootsが構築したDOM Inspector MCPは、Puppeteer(ヘッドレスChrome)を使ってローカルの開発サーバーに接続し、ページ上の要素をプログラムで検査・計測・操作します。スペースのずれや要素のサイズ、算出されたスタイルといったUIレイアウトの問題を検出し、ボットに修正させることを目的に設計されました。

 

コアアーキテクチャ

  • DOMInspector クラス:Puppeteerのブラウザ・ページのライフサイクルを管理する中心的なオブジェクトです。完全に自前でブラウザを起動するモードと、静的ファクトリメソッド fromPage() で外部のページを受け取るセッション管理モードの2つがあります。

  • ブラウザ管理:メモリ制限フラグ(--max-old-space-size=256、レンダラープロセス数の制限)を指定してヘッドレスChromeを起動し、5秒のタイムアウト後にPIDでプロセスを強制終了するグレースフルシャットダウンを処理します。

  • DOM検査メソッドinspectElement()(寸法と算出CSS)、measureDistance()(2要素間のピクセル/rem単位のギャップと、それを生み出しているCSSプロパティ)、measureLayoutShift()(ページをリロードして遷移前後の要素位置を差分比較)、debugPage()(セレクターが見つからない場合にDOMをスキャンして一般的なコンポーネントパターンを探す)を含みます。

  • インタラクションとナビゲーションinteractWithElement() はセレクターをクリックして前後の状態を計測し、navigateToUrl() は新しいURLに遷移して古いコンソールログをクリアし、setViewport() は名前付きプリセット(mobile/tablet/desktop/large)または任意のピクセル幅と自動計算された高さをサポートします。

  • ユーティリティメソッドscreenshot()(ページ全体またはセレクター単位のスクリーンショット、base64で返却)、evaluateJs()(ページコンテキストで任意の非同期JSを実行)、waitForSelector()getPageContent()(テキスト/HTML/outerHTMLを切り詰め対応で取得)、getConsoleLogs()(バッファリング済み、500エントリ上限)を含みます。

  • CLIエントリーポイントmain() はファイルが直接実行された場合のみ動作し(require() 経由では不可)、--url--port フラグを受け取り、ハードコードされたコンポーネント(.WhoSentYouWrapper)のクイック検査をスモークテストとして実行します。

  • extractUrlFromText():クラスと一緒にエクスポートされるヘルパー関数で、自然言語の文字列からlocalhostのURLを解析します。ユーザーのテキストプロンプトを受け取るMCPサーバーから呼び出されることを想定した設計です。

 

うまくいったこと

PlaywrightのビジュアルリグレッションテストとDOM Inspector MCPは、組み合わせて使うと最も効果的でした。ビジュアルテストのワークフローは、各テンプレートのPlaywrightテストでビジュアルリグレッションを検出することから始まります。その結果を別のエージェントに渡して修正し、次にDOM Inspector MCPでPlaywrightのテスト修正後も残った要素レベルの問題を細かく調整しました。DOM Inspectorは要素単位の細かい検査において、より精度が高いことが分かりました。それでも100%ではありませんでしたが、面倒なスタイル修正にかかる時間を節約することができました。

 

コンテンツの更新(こちらもボットで)

CMSでのコンテンツ更新は手間がかかるため、Frontmatterやコードの深い知識がなくてもコンテンツを更新できるよう、いくつかのClaude Skillsを作成しました。

 

コマンドライン向けスキル

非開発者にとって、git操作(あるいはターミナル自体)は敷居が高いものです。しかし品質と一貫性のためにPRベースのワークフローに価値があると考え、これを助けるユーティリティスキルを作成しました。

  • /new-branch:originのmainブランチを最新の状態に更新して回避可能なマージコンフリクトを防ぎ、スキルからのブランチとわかるようにブランチ名にプレフィックスを付け、過去のブランチチェックアウトの残骸が新しいPRに混入しないようにします。

  • /deploy-local-preview:ローカル開発サーバーを起動してプレビューするには数行のターミナル操作が必要なため、それをユーザーの代わりに行うスキルを作成しました。対象のサイトに移動し、開発サーバーを起動して、ローカルプレビューをデプロイします。

 

コンテンツ更新向けスキル

各ページタイプごとに、Frontmatterファイルの作成、フィールドごとのユーザーへの入力促し、画像のアップロード(画像サイズチェックあり)、作業確認のための /deploy-local-preview の呼び出し、GitHub CLIを使ったPull Requestの作成、までを行うスキルを構築しました。これにより必要な情報がすべて揃うよう誘導し、煩雑なCMS UIの操作を減らし、巨大な画像ファイルの使用を防ぎ(250KB以下への圧縮を丁寧に促し、それより大きいファイルは受け付けない)、ページ更新をコードではなくコンテンツだけに集中できるようにしています。

 

考慮すべき点

AIを使ったコンテンツ更新スキルを構築した経験から、いくつか念頭に置くべきことがあります。

  • コンピュートはコストがかかる。 ローカルプレビューのデプロイにはHaikuで十分なのに、Opusを使う必要はありません。タスクに適したモデルが使われるよう、特定のスキルにはデフォルトモデルを設定しています。また、リポジトリのデフォルトモデルはOpus 4.6に設定して使用量を抑えています。

  • スキルを使って大きな画像ファイルやパフォーマンスを低下させる一般的な問題を検出する。 巨大な画像がコードベースにアップロードされてビルドやサイトのパフォーマンスを低下させないよう、ページスキルにファイルサイズの上限を設けました。

  • Hooksでサイトの重要な部分を保護する。 モデルはコードベース全体にアクセスできるため、変更されたくない重要な部分はAIによる変更を禁止します。例えば、コンテンツセキュリティポリシーは PreToolUse フックで保護し、CSPへの変更を防いでいます。

 

 

「レート制限問題」の解決

内部を改修するついでに、もう一つの悩みの種だったAPIのレート制限問題にも対処しました。

フォームはビルド時にマーケティングオートメーションシステムからフィールドを取得することに依存していました。レート制限に達するとビルドが壊れていました。この問題を解決するために、Vercel Blobを使ったサービスを構築しました。ビルドの冒頭でフォームフィールドを取得し、高速で安定したBlobストアに保存するようにしました。

これにより、ビルドの重要フェーズにおけるマーケティングオートメーションシステムへのAPIコールをほぼゼロに削減し、障害の原因をさらに一つ取り除くことができました。

 

 

結果:信頼性という機能

重厚でAPI依存のCMSから、軽量なファイルベースのAstroサイトへの移行は、生産性に大きな変化をもたらしました。

指標 移行前(Gatsby + CMS) 移行後(Astro + Claude)
平均ビルド時間 14分 4分未満
Web Vitalsスコア 89 97
ステージングビルドの失敗 頻発(API・プラグイン起因) 95%削減
コンテンツスキーマの制限 プランによる制限あり 制限なし
使用感 苦痛 ハイタッチできるレベル

コンテンツをコードベースに取り込み、非技術者向けにはClaude Codeが橋渡し役を担うことで、サイトを高速化しただけでなく、デプロイパイプライン全体の信頼性を高めることができました。

結局のところ、壊れたビルドを修正する最善の方法は、壊れる原因を最初から取り除くことなのです。

 

 

 

 




IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談は「お問い合わせ」からお気軽にお問い合わせください。

 

シェアする

Recent Posts

;