zudo-doc
GitHub repository

Type to search...

to open search from anywhere

Deployment

Created Apr 13, 2026Updated Jun 14, 2026Takeshi Takatsudo

Deploy zudo-doc sites to Cloudflare Workers with GitHub Actions CI/CD.

Overview

zudo-doc is a fully static site generator — the output of pnpm build is a directory of HTML, CSS, and JavaScript files that can be deployed anywhere. The default deployment target is Cloudflare Workers (static assets), using GitHub Actions for CI/CD automation.

The CI pipeline is split into parallel jobs to keep total build time low. Site generation and document history extraction run as separate jobs and are merged before deployment.

Cloudflare Workers Static Assets

The built site is deployed using wrangler deploy. The deploy artifact includes:

  • The zfb build output (dist/)

  • Pre-generated doc history JSON files (if docHistory is enabled)

  • dist/_worker.js — the explicit main entry produced by the CF adapter

The site is served at root (base = "/") via the Workers static asset layer. Dynamic routes (e.g. /api/ai-chat) are handled by dist/_worker.js; all other GET requests are served as static assets from dist/.

Info

The site URL is configured via [[routes]] in wrangler.toml (custom domain binding). Bindings such as ANTHROPIC_API_KEY, DOCS_SITE_URL, and RATE_LIMIT KV are also declared in wrangler.toml.

CI Pipeline Structure

The project uses three GitHub Actions workflows: production deploys (main-deploy.yml), PR checks and previews (pr-checks.yml), and branch previews (preview-deploy.yml).

Production (main-deploy.yml)

Triggered on push to main. Runs five jobs:

  1. build-site — full clone (fetch-depth: 0), builds the zfb site with pnpm build (no SKIP_DOC_HISTORY — the preBuild step needs full git history to populate the SSG meta block)

  2. html-validate — validates the built dist/ for HTML element errors

  3. build-history — full clone (fetch-depth: 0), runs @takazudo/zudo-doc-history-server generate to pre-extract git history for all content files

  4. deploy — merges the site and history artifacts, then deploys via wrangler deploy (production)

  5. notify — sends an IFTTT webhook notification with the deploy status

Concurrency: group: production-deploy, cancel-in-progress: false — earlier deploys are allowed to finish rather than being cancelled.

PR Checks (pr-checks.yml)

Triggered on pull requests targeting main. Runs fifteen jobs:

  1. check-template-drift — verifies no drift between source files and generator templates

  2. check-pin-parity — verifies @takazudo/zfb pin is consistent across all package sources

  3. check-fixture-settings-drift — verifies every key in src/config/settings.ts is present in all e2e fixture settings files (or allowlisted)

  4. check-package-safelist — verifies the generated dist/safelist.css covers all responsive/arbitrary utility classes in the @takazudo/zudo-doc package

  5. check-b4push-ci-parity — verifies every lightweight guard gate in scripts/run-b4push.sh has a matching CI job

  6. check-e2e-spec-naming — verifies all e2e spec filenames use known fixture prefixes so Playwright picks them up

  7. lint-gates — runs pnpm tags:audit --ci and pnpm lint:tokens (design token lint)

  8. typecheck — runs pnpm check (TypeScript type checking)

  9. package-tests — runs all package-scoped vitest suites

  10. root-tests — runs the root unit test suite

  11. build-site — full clone (fetch-depth: 0), pnpm build, then check:links (no SKIP_DOC_HISTORY — same rationale as production: preBuild needs full history for SSG meta dates)

  12. html-validate — validates the built dist/ for HTML element errors

  13. build-history — full clone, doc history generation

  14. e2e — runs Playwright end-to-end tests

  15. preview — merges artifacts and uploads a preview via wrangler versions upload --preview-alias, then posts the URL as a PR comment

Concurrency: group: pr-checks-{pr-number}, cancel-in-progress: true — outdated runs are cancelled to save CI minutes.

Preview Deployments

Each PR gets a stable preview-alias URL via wrangler versions upload --preview-alias <alias> (enabled by preview_urls = true in wrangler.toml). The alias is pr-<number> for PR checks and the branch slug for branch previews. The URL is on *.workers.dev (not the production custom domain) and its subdomain starts with the alias:

https://<alias>-zudo-doc.<your-subdomain>.workers.dev

CI parses the exact host from wrangler's output and posts it automatically as a comment on the PR by the preview job.

SKIP_DOC_HISTORY

When SKIP_DOC_HISTORY=1 is set, the doc-history zfb plugin skips all git history calls and writes an empty manifest, causing the visible Created/Updated/Author block to be absent from every SSG page. In standard CI this flag is not set on the build-site job — the preBuild step needs full git access to populate real dates.

ContextValueWhy
CI build-site jobunsetpreBuild needs full git history to populate the SSG meta block (Created/Updated/Author)
CI e2e jobunsetE2E tests verify history features inline
Local pnpm buildunsetThe Created/Updated/Author meta block is embedded (preBuild). The per-page history dropdown JSON is not generated locally by default — see GEN_DOC_HISTORY below

Tip

SKIP_DOC_HISTORY=1 is an escape hatch for shallow-clone or custom CI variants where git history is unavailable. Setting it causes the Created/Updated/Author block to be absent from every page.

GEN_DOC_HISTORY

GEN_DOC_HISTORY=1 (introduced in #1986) gates the doc-history plugin's postBuild hook — the step that writes the per-page revision/diff JSON into dist/doc-history/ feeding the DocHistory dropdown island. The plugin's preBuild hook (the visible Created/Updated/Author meta block) is unaffected and is governed by SKIP_DOC_HISTORY alone. postBuild now follows this decision table:

ContextpostBuild JSONWhy
SKIP_DOC_HISTORY=1skippedoverrides GEN_DOC_HISTORY and CI — wins over everything
GEN_DOC_HISTORY=1generatedexplicit local opt-in
CI / GITHUB_ACTIONS setgeneratedkeeps the build-site artifact byte-identical to before
plain local pnpm buildskippedthe #1986 default — see Tip below

Tip

postBuild is off by default locally because its per-content-file git log --follow chain exceeds zfb's 120s postBuild lifecycle budget on a large corpus and fails a plain pnpm build. It is redundant locally anyway: dev reads history live from the standalone :4322 server, and CI generates the JSON in the dedicated parallel build-history job. To make the dropdown work when previewing a locally-built dist/ (or building the Tauri offline reader), run GEN_DOC_HISTORY=1 pnpm build. Note this gates only the zfb plugin's postBuild — the standalone @takazudo/zudo-doc-history-server generate CLI used by the build-history job is never gated and always generates when invoked.

Inter-Job Data Sharing

Build artifacts are shared between jobs using actions/cache rather than actions/upload-artifact. Cache keys are scoped to github.run_id to prevent cross-run contamination:

key: dist-${{ github.run_id }}
key: doc-history-${{ github.run_id }}

The deploy (or preview) job restores both caches and merges the dist/ directories before calling wrangler deploy (production) or wrangler versions upload (preview).

Note

Using actions/cache for job-to-job data transfer (rather than artifacts) avoids the overhead of uploading and downloading large ZIP archives. Cache entries are cheaper for temporary intra-run data.

Required Secrets

Configure these in your repository's Settings → Secrets and variables → Actions:

SecretDescription
CLOUDFLARE_API_TOKENCloudflare API token with Workers deployment permissions
CLOUDFLARE_ACCOUNT_IDYour Cloudflare account ID
IFTTT_PROD_NOTIFYIFTTT webhook URL for deploy notifications (optional)

Warning

The CLOUDFLARE_API_TOKEN needs the Workers: Edit permission (and KV Storage: Edit if you use KV namespaces). Scoping it to the specific Worker is recommended over granting account-wide access.

Revision History

Takeshi TakatsudoCreated: 2026-04-13T21:29:34+09:00Updated: 2026-06-14T15:45:56Z

AI Assistant

Ask a question about the documentation.