Skip to content

Docs site: reduce maintenance (single source for code, non-blocking translations, simpler CI) #456

Description

@vishr

Summary

Make the docs site cheaper to maintain: one source for every fact, no build steps that block unrelated doc fixes, and fewer pages to keep in sync. Work is split into 5 phases that can land as separate PRs, in this order. Each phase has a checklist and a "Done when".

Progress — 2026-09-30

Merged #457 as 508a246.

  • Phase 4 complete: removed HTTP/2 server push, JSONP, and load balancing recipes and their unused assets/dependencies; added replacement redirects across current locales, stable/next channels, and legacy Docusaurus URLs.
  • Phase 3 source conversion complete: all 85 maintained cookbook pages and the ten Request Logger/Static middleware pages across five locales render Go/HTML from repository files. The include plugin supports regions, Markdown/MDX, source-aware caching, and actionable validation errors. JWT/SSE documentation drift and generated-file copies are removed; cookbook ownership checks run in CI.
  • Phase 3 remains open: Prometheus package alignment, targeted recipe tests, and removal of the remaining cookbook/http2/ sample certificate/key. The server-push certificate/key were removed with that recipe. The combined compile/test checkbox remains open because the requested recipe tests have not been added.
  • Phases 1 and 5 remain open. Translation checks and /next/ remain in place after ci: consolidate checks and derive docs sources from Go modules #458.

Validation before merge: 22 Node tests; 18 Go tests across 30 packages; go vet ./...; stable/next production builds; 767 routes and 56,576 internal links/assets; exact checks of 440 rendered source snippets and 175 redirect destinations. Local browser QA covered desktop/mobile layouts, light/dark themes, examples across all five locales, search, copy controls, navigation, channel switching, and sampled redirects. No merge-blocking regression found.

Phase 2 complete: merged #458 as 0e7e4df. CI is consolidated; Go minimum/preferred toolchain and stable/external source versions come from the module files; both Go modules share Dependabot version/security update groups; publishing refreshes weekly; API diffs appear in the Actions summary. New routes pass with a warning to record them for future removal protection. The origin budget covers declared resources (including preloads, icons, images and embeds) while excluding navigation links/preconnects; byte-size budgets are unchanged. All six review findings were fixed and replied to. Validation: all 36 Node tests, Go vet/race checks, stable/next builds, 767 routes and 56,576 internal links/assets, workflow linting, and local browser checks passed. Final pre-merge CI passed.

Phase 3 follow-up merged: #461 merged as 9d234d5. The homepage Hello World now comes from its runnable source, and Casbin middleware/enforcer/JWT excerpts and model/policy files come from the recipe across all five locales. Both review findings were fixed: the hidden hero code is excluded from keyboard focus, and Casbin pages define the enforcer and list the JWT dependencies. All 37 Node tests, Go vet/race checks, stable/next builds, link/accessibility/performance checks, and local desktop/mobile/light/dark browser checks passed. Final head CI passed. The two corresponding Phase 3 checkboxes are complete; Phase 3 remains open for Prometheus alignment, targeted recipe tests, and the HTTP/2 sample certificate/key.

Why

  • Pasted code: complete cookbook programs are pasted into every locale page: 120 blocks, about 6,100 lines. Some copies have already drifted (cookbook/jwt.md, cookbook/sse.md). The CRUD page (cookbook(crud): handle missing users and invalid ids consistently #455) already imports its code instead.
  • Blocking translation checks: translation-status.mjs and security-translation-status.mjs fail the build, so an English edit can block deployment until 4 translations are updated.
  • /next/ channel: it doubles the build and the baselines, is currently one commit ahead of stable, and publishes about 305 duplicate pages without noindex.
  • CI overlap and pins: two workflows build the site on every PR, and Go versions differ (1.25 vs 1.27). Echo is pinned in several places, and Dependabot doesn't cover Go modules.

Phase 1: Unblock deployment (~1 day)

Goal: an English doc fix can always ship.

  • Make translation checks report-only:
    • site/scripts/translation-status.mjs: drop process.exitCode = 1 and write the report to $GITHUB_STEP_SUMMARY when set.
    • site/scripts/security-translation-status.mjs: replace the throw with a report, like the line above.
    • site/scripts/build-site.mjs: keep running both, but never fail on them.
  • Show readers when a translation may be stale: extend site/src/components/VersionBanner.astro to show "This translation may be outdated. Read the English version" on pages the report flags.
  • Stop publishing /next/:
    • site/scripts/build-site.mjs: build only the stable channel, and remove rewriteNextLinks.
    • Delete site/next-source.json and site/next-reference-baseline.json, and remove the next rules from check-site.mjs and check-performance.mjs.
    • Redirect /next/* to the stable URL, so existing links keep working.
  • Add .github/workflows/echo-master.yml, a weekly, non-required check against Echo master:
    • go get github.com/labstack/echo/v5@master, then go vet ./... and go test ./... for the cookbook and reference/.
    • Run the config-field extractor and print the API diff against site/reference-baseline.json in the job summary.
    • Open or update an issue when it fails.

Done when: a PR that changes only English text builds and deploys with stale translations, /next/ redirects to stable, and the weekly job runs green on Echo master.

Phase 2: One CI workflow and one Echo pin (~1 day)

Goal: a single version bump is a single PR.

  • Merge docs.yml, test.yaml and test-deploy.yaml into one PR workflow: go vet + go test -race ./..., then the site build and checks. Keep deploy.yaml for publishing.
  • Use go-version-file: go.mod in every workflow instead of hard-coded 1.25/1.27, and drop the hard-coded Go version in the go.work written by prepare-echo-source.mjs.
  • Derive the Echo source from go.mod: in prepare-echo-source.mjs, resolve Echo with go mod download -json github.com/labstack/echo/v5 (as external modules already are) instead of cloning a SHA. Delete site/echo-source.json.
  • Derive the external module versions (site/external-sources.json) from go.mod too, or check that they match.
  • Add gomod to .github/dependabot.yml for / and /reference, grouped into one PR.
  • Route baseline (check-site.mjs): fail only on removed routes; new pages shouldn't need an accept step.
  • Performance check: count only scripts and stylesheets as external origins, not plain <a href> links.
  • deploy.yaml: change the daily cron (it only refreshes the star count) to weekly.

Done when: a Dependabot Go PR updates Echo in one place, and CI builds, checks and shows any API diff in one workflow.

Phase 3: Code comes from source files (~2 days)

Goal: no page contains a pasted copy of a program from the repo.

  • Add a small remark plugin in site/ that reads a fenced block like ```go file=cookbook/jwt/custom-claims/server.go (path from the repo root) and fills in the file's content. Support optional regions (#name, between // docs:start name and // docs:end name) for step-by-step excerpts. Pages stay .md, with no per-locale import paths.
  • Convert cookbook/crud.mdx (all locales) to the fence syntax, and remove the copyFileSync special case from prepare-echo-source.mjs.
  • Replace every pasted cookbook program with a file= fence in all locales. Script it: replace a block only when it exactly matches the source file, and review the rest by hand.
  • Fix the known drift while converting:
    • cookbook/jwt.md vs cookbook/jwt/custom-claims/server.go
    • cookbook/sse.md vs cookbook/sse/broadcast/server.go
    • middleware/prometheus.mdx and site/external-sources.json use echo-prometheus, but cookbook/prometheus/server.go uses echo-contrib/v5/echoprometheus. Pick one.
    • middleware/casbin-auth.md pastes the same middleware twice.
    • Render the homepage Hello World (site/src/components/HomeHero.astro) from cookbook/hello-world/server.go.
  • Add a CI rule: fail if a page under cookbook/ has a bare ```go block of more than ~15 lines without file=.
  • Every recipe compiles (go vet ./...). Add server_test.go only where there is real logic (crud already has one; also jwt, cors, file-upload, timeout), using the newServer() pattern from crud.
  • Delete the committed sample certificates and keys in cookbook/http2/ and cookbook/http2-server-push/ (expired 2017). Generate them at run time or document mkcert.

Done when: CI fails on a pasted program, every code block on a cookbook page comes from a compiled file, and the drift items are fixed.

Phase 4: Prune the cookbook (~½ day)

Goal: less to maintain, and no broken links.

  • Remove or merge the recipes with low value and high upkeep:
    • http2-server-push: browsers removed HTTP/2 push.
    • jsonp: the page itself recommends JSON with CORS.
    • load-balancing: Armor/nginx configs. Also fix the page's HTTPS instructions, which don't match its plain-HTTP example.
  • Add an explicit redirect for every removed URL in all locales (site/src/redirects.mjs currently derives redirects from existing files, so removals silently drop them).
  • Remove unused assets and Go dependencies that belonged to removed recipes (go mod tidy).

Done when: removed pages redirect, and the link check and go vet ./... pass.

Phase 5: Translate less (~1½ days)

Goal: translation work matches what readers use.

  • Decide which locales and pages stay translated, using site analytics. Suggested start is the learning path (about 11–25 pages): installation, quickstart, routing, context, request, response, binding, error handling, the middleware index, hello-world, crud.
  • Don't translate security pages: a stale translated security warning is worse than English. Remove the localized copies and let Starlight fall back to English.
  • Delete the other translation files, relying on Starlight's English fallback.
  • Make the scripts fallback-aware: check-source.mjs and check-site.mjs currently require every page in every locale.
  • Keep one list of locales (it's hard-coded in about 11 files), and move component labels (for example ConfigReference.astro) to Starlight's i18n strings with Astro.currentLocale.
  • Keep one staleness check covering all translated pages: merge translation-sections.mjs, translation-status.mjs and security-translation-status.mjs, with code blocks excluded from the hashes.

Done when: every page that isn't translated renders in English under each locale URL, the checks pass, and the staleness report covers all translated pages.


Out of scope

  • Moving docs into labstack/echo: echox stays a separate repo.
  • A separate v4 site: instead, add one "Migrating from v4" page, link pkg.go.dev for v4 APIs, and note v4 LTS support until 2026-12-31.
  • Generating all API docs: the config-field extractor stays narrow, and pkg.go.dev covers the rest.

Notes

  • The phases are independent PRs. 1 and 2 remove most of the recurring cost, 3 is the largest.
  • Keep existing link, anchor, accessibility and asset-size checks unless a phase changes them on purpose.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions