デプロイ
GitHub Actions CI/CDを使用してzudo-docサイトをCloudflare Workersにデプロイする。
概要
zudo-docは完全な静的サイトジェネレーターです。pnpm buildの出力はHTML、CSS、JavaScriptファイルのディレクトリであり、どこでもデプロイできます。デフォルトのデプロイ先はCloudflare Workers(静的アセット)で、CI/CDの自動化にはGitHub Actionsを使用します。
このguideはzudo-doc showcase repositoryのhost-owned Workerとworkflowを説明します。 fresh downstream scaffoldには、これらworkflow file、live AI handler、worker-entry.ts、 AiChatDailySpendCapは含まれません。host側の部品を追加するときの参照として利用してください。
CIパイプラインは合計ビルド時間を短縮するために並列ジョブに分割されています。サイト生成とドキュメント履歴の抽出は独立したジョブとして実行され、デプロイ前にマージされます。
Cloudflare Workers静的アセット
ビルドされたサイトはwrangler deployを使用してデプロイされます。デプロイアーティファクトには以下が含まれます:
zfbのビルド出力(
dist/)事前生成されたdocヒストリーJSONファイル(
docHistoryが有効な場合)worker-entry.ts— source-ownedのWrangler entry。生成されたdist/をimportし、_ worker. js dist/を維持します_ zfb_ inner. mjs
サイトはWorkers静的アセット層によりルート(base = "/")で配信されます。動的ルート(例:/)はdist/が処理し、それ以外のGETリクエストはdist/から静的アセットとして配信されます。
Info
サイトURLはwrangler.tomlの[[routes]]でカスタムドメインバインディングとして設定します。 ライブAIチャットではANTHROPIC_API_KEYシークレット、DOCS_SITE_URL、ソフトなIPごとのRATE_LIMIT KV、そしてexport class AiChatDailySpendCapへバインドしたAI_CHAT_DAILY_SPEND_CAP名前空間も使います。Worker migrationはv1-ai-chat-daily-spend-capとnew_sqlite_classes = ["AiChatDailySpendCap"]で、 本番のwrangler deployが適用します。
デプロイentryは生成されたアダプターだけでなく、カスタムworker-entry.tsです。Wranglerより前に ビルドしてdist/とdist/を用意し、カスタムentryがアダプターハンドラーと Durable Object exportを維持します。PR CIは同じビルドartifactを復元し、Workers-runtime SQLite testと Wrangler dry-runをその同一ファイルに対して実行します。
CIパイプラインの構造
プロジェクトでは3つのGitHub Actionsワークフローを使用します:本番デプロイ(main-deploy.yml)、PRチェックとプレビュー(pr-checks.yml)、ブランチプレビュー(preview-deploy.yml)。
本番環境(main-deploy.yml)
mainへのプッシュでトリガーされます。5つのジョブが実行されます:
build-site — フルクローン(
fetch-depth: 0)、pnpm buildでzfbサイトをビルド(SKIP_DOC_HISTORYなし — preBuildステップがSSGメタブロックを生成するためにフルgit履歴が必要)html-validate — ビルド済み
dist/のHTMLエレメントエラーを検証build-history — フルクローン(
fetch-depth: 0)、@takazudo/zudo-doc-history-server generateを実行してすべてのコンテンツファイルのgit履歴を事前抽出deploy — サイトと履歴のアーティファクトをマージし、
wrangler deployで本番環境にデプロイnotify — デプロイステータスをIFTTTウェブフックで通知
コンカレンシー: group: production-deploy, cancel-in-progress: false — 先行するデプロイはキャンセルされずに完了が許可されます。
PRチェック(pr-checks.yml)
mainを対象としたプルリクエストでトリガーされます。20のジョブが実行されます:
check-template-drift — ソースファイルとジェネレーターテンプレート間のドリフトを検証
check-no-host-alias-in-package — package sourceからhost専用import aliasを拒否
check-pin-parity —
@takazudo/zfbのピンがすべてのパッケージソース間で一致しているか確認check-fixture-settings-drift —
src/のすべてのキーがe2eフィクスチャー設定ファイルに存在するか(またはアローリスト済みか)を確認config/ settings. ts check-package-safelist —
@takazudo/zudo-docパッケージ内のすべてのレスポンシブ・任意値ユーティリティクラスを生成済みのdist/がカバーしているか検証safelist. css check-b4push-ci-parity —
scripts/の軽量ガードゲートすべてに対応するCIジョブが存在するか確認run- b4push. sh check-e2e-spec-naming — すべてのe2eスペックファイル名が既知のフィクスチャープレフィックスを使用しているか確認(Playwrightが確実に検出できるよう)
check-flaky-tracking-issue — flaky/local-only testにtracking issueを必須化
check-wait-debt — E2E testの注釈なし固定waitを拒否
check-component-tokens — 生成されたcomponent-token CSSが最新か確認
lint-gates — tag、compatibility、resolution、design-token guardを実行
typecheck — rootとworkspaceのTypeScript checkを実行
worker-contract —
build-siteartifactを復元し、Workers-runtime Durable Object testとWrangler dry-runを実行package-tests — すべてのパッケージスコープのvitestスイートを実行
root-tests — ルートユニットテストスイートを実行
build-site — フルクローン(
fetch-depth: 0)、pnpm build、その後check:links(SKIP_DOC_HISTORYなし — 本番と同じ理由:preBuildにSSGメタ日付のためのフルgit履歴が必要)html-validate — ビルド済み
dist/のHTMLエレメントエラーを検証build-history — フルクローン、docヒストリーの生成
e2e — Playwrightエンドツーエンドテストを実行
preview — アーティファクトをマージして
wrangler versions upload --preview-aliasでプレビューをアップロード、PRコメントとしてURLを投稿
コンカレンシー: group: pr-checks-{pr-number}, cancel-in-progress: true — 古い実行はCIの消費を節約するためにキャンセルされます。
プレビューデプロイ
各PRはwrangler versions upload --preview-alias <alias>により安定したプレビューエイリアスURLを取得します。生成されるアダプター専用preview configはpreview_urls = trueを維持し、本番と同様にprimary workers_dev routeは無効のままにします。エイリアスはPRチェックではpr-<番号>、ブランチプレビューではブランチスラッグです。URLは*.workers.dev上にあり(本番のカスタムドメインではありません)、サブドメインはエイリアスで始まります:
https://<alias>-zudo-doc-preview.<your-subdomain>.workers.dev CIはwranglerの出力から正確なホストを解析し、previewジョブによってPRのコメントとして自動的に投稿されます。 分離されたserviceを初めて作成するときは、CIがCloudflare APIを介してpreview URLのsubdomain設定だけを明示的に有効化し、alias付きuploadを再試行します。 preview entryはGET/HEADを内部hostnameでASSETSへ直接送り、その他のmethodを生成されたadapterへ委譲します。Cloudflareのasset bindingはpathnameだけでmatchするため、API POST smoke gateを維持しながらpreview aliasがsame-zone Worker fetchとして扱われることを避けられます。本番は生成されたadapterを引き続き直接exportします。
Durable Objectsを実装するversionにはCloudflareがプレビューURLを発行しないため、プレビューworkflowは サイトのビルド後に、別のpreview service用のアダプター専用config/entryを生成します。プレビューはSSRと assetsを検証しますが、AI_CHAT_DAILY_SPEND_CAPをバインドせず、migrationも適用せず、本番のRATE_LIMIT KVとcustom-domain routeもコピーしません。liveのAI admissionとrate-limit経路は本番専用です。
SKIP_DOC_HISTORY
SKIP_DOC_HISTORY=1が設定されると、doc-historyのzfbプラグインはすべてのgit履歴呼び出しをスキップして空のマニフェストを書き出し、すべてのSSGページから作成日・更新日・著者ブロックが消えます。標準CIではbuild-siteジョブにこのフラグは設定されません — preBuildステップが実際の日付を生成するためにフルgitアクセスが必要なためです。
| コンテキスト | 値 | 理由 |
|---|---|---|
CI build-siteジョブ | 未設定 | preBuildがSSGメタブロック(作成日・更新日・著者)を生成するためにフルgit履歴が必要 |
CI e2eジョブ | 未設定 | E2Eテストはインラインで履歴機能を検証する |
ローカルpnpm build | 未設定 | 作成日・更新日・著者のメタブロックは埋め込まれる(preBuild)。ページごとの履歴ドロップダウンJSONはデフォルトではローカル生成されない — 後述のGEN_DOC_HISTORYを参照 |
Tip
SKIP_DOC_HISTORY=1はシャロークローンやgit履歴が利用できないカスタムCIバリアント向けのエスケープハッチです。設定するとすべてのページから作成日・更新日・著者ブロックが消えます。
GEN_DOC_HISTORY
GEN_DOC_HISTORY=1(#1986で導入)はdoc-historyプラグインのpostBuildフックを制御します — dist/doc-history/にページごとのリビジョン/差分JSONを書き出し、DocHistoryドロップダウンアイランドに供給するステップです。プラグインのpreBuildフック(表示される作成日・更新日・著者のメタブロック)はこれに影響されず、SKIP_DOC_HISTORYのみで制御されます。postBuildは次の決定表に従います:
| コンテキスト | postBuild JSON | 理由 |
|---|---|---|
SKIP_DOC_HISTORY=1 | スキップ | 以下すべてを上書きする — DOC_HISTORY_SKIP_POSTBUILD、GEN_DOC_HISTORY、CIに優先する |
DOC_HISTORY_SKIP_POSTBUILD=1 | スキップ | GEN_DOC_HISTORYとCIを上書きする — SKIP_DOC_HISTORYにのみ劣後する |
GEN_DOC_HISTORY=1 | 生成 | 明示的なローカルオプトイン |
CI / GITHUB_ACTIONSが設定 | 生成 | build-siteアーティファクトを以前とバイト単位で同一に保つ |
通常のローカルpnpm build | スキップ | #1986のデフォルト — 下記のTipを参照 |
Tip
postBuildがローカルでデフォルトオフなのは、コンテンツファイルごとのgit log --followチェーンが大規模なコーパスではzfbの120秒のpostBuildライフサイクル予算を超え、通常のpnpm buildを失敗させるためです。ローカルでは冗長でもあります:開発時は履歴をスタンドアロンの:4322サーバーからライブで読み取り、CIは専用の並列build-historyジョブでJSONを生成します。ローカルビルドしたdist/をプレビューするとき(またはTauriオフラインリーダーをビルドするとき)にドロップダウンを動作させるには、GEN_DOC_HISTORY=1 pnpm buildを実行します。これはzfbプラグインのpostBuildのみを制御する点に注意してください — build-historyジョブで使われるスタンドアロンの@takazudo/zudo-doc-history-server generate CLIは制御対象外で、呼び出されると常に生成します。
DOC_HISTORY_SKIP_POSTBUILD
DOC_HISTORY_SKIP_POSTBUILD=1(#2927で導入)は、上の決定表にあるpostBuildのページごとのドロップダウンJSONステップのみをスキップします — GEN_DOC_HISTORYがオプトインするのと同じステップです。SKIP_DOC_HISTORY=1と異なり、preBuildマニフェストは空にしません。そのため、作成日・更新日・著者ブロックには実際のgit日付が引き続き表示されます。
これはシャロークローンのCIバリアント向けです:軽量なpreBuildの--name-status走査には十分なgit履歴があるものの、より重いpostBuildのファイルごとのgit log --followチェーンは明示的にオプトアウトしたい場合に使います。ローカルビルドのデフォルト(postBuildをスキップ)に頼るのではなく明示的に指定する必要があるのは、そのバリアントがCI=trueも設定している場合、CIではデフォルトで生成されるためです。
Tip
この名前は意図的にSKIP_DOC_HISTORYという部分文字列を含みません。そのためscripts/のリテラル文字列によるサバイバースキャンでは別のマーカーとして扱われ、許可リストの変更は不要です。
ジョブ間のデータ共有
build jobは出力をtarにまとめ、**actions/upload-artifact**で公開します。consumer jobは actions/download-artifactを使い、validation/deploy前に${{ runner.temp }}から展開します:
name: site-dist # contains site-dist.tar
name: doc-history # contains doc-history.tar
retention-days: 1deployとpreview jobは両archiveを復元し、Wranglerの前にdoc historyをdist/へmergeします。 worker-contract jobも同じsite-dist artifactを復元するため、runtime testとdry-runは後で preview/deployが使うものと同じbuildを検証します。
Note
tarはartifact upload中も任意のroute filenameを維持します。retentionを1日にすることでstorageを 抑えながらrun単位のpaper trailを残し、このhandoffはmutable cache keyやcross-run cache stateに依存しません。
必要なシークレット
リポジトリのSettings → Secrets and variables → Actionsで設定します:
| シークレット | 説明 |
|---|---|
CLOUDFLARE_API_TOKEN | WorkersデプロイのためのCloudflare APIトークン |
CLOUDFLARE_ACCOUNT_ID | CloudflareアカウントID |
IFTTT_PROD_NOTIFY | デプロイ通知用のIFTTTウェブフックURL(オプション) |
Warning
CLOUDFLARE_API_TOKENにはWorkers: Edit権限が必要です(KVネームスペースを使用する場合はKV Storage: Editも必要)。アカウント全体へのアクセス権限を付与するのではなく、特定のWorkerにスコープすることを推奨します。