This is an automated email from the ASF dual-hosted git repository. moonming pushed a commit to branch feat/astro-docs-wave3 in repository https://gitbox.apache.org/repos/asf/apisix-website.git
commit 478fe7182cfa7506d1e35ad3d8f256c6ecfbf3c4 Author: Ming Wen <[email protected]> AuthorDate: Sun Jul 26 17:33:50 2026 +0800 feat(docs): serve the latest-version docs from the static build (wave 3) Migrates the current-version project docs to the Astro build. The version archives (3.10–3.16, next) stay exactly as Docusaurus produces them. - CI sparse-clones docs/ from the seven upstream Apache repos so the sync script has content to render; a repo that fails to clone yields no pages for that project, which the parity gate then catches. - The docs overlay is per-page, not per-subtree: under docs/<project>/ the version directories sit beside the latest-version pages, so a subtree swap would delete the archive. Only paths Astro actually produced are copied, and the step asserts 3.16/next are still the Docusaurus build. - A parity gate fails the deploy if any version-less page Docusaurus built is missing from the Astro build. Version dirs are excluded by design, as are docs/*/tags/ — Docusaurus emits those empty (a single self-link, absent from the sitemap, linked from no doc page) and the per-page swap leaves them in place, so those URLs keep resolving. - Algolia DocSearch (the index the current site already uses) loads on docs pages only. Every other page stays zero-JS. Simulated against the live asf-site tree: 3410 → 3416 pages, 0 deleted, 6 added (new upstream plugin docs), and all 2908 archived version pages byte-identical. --- .github/workflows/deploy.yml | 61 +++++++++++++++++++++++++++++++++++++++- next/.gitignore | 1 + next/src/components/Header.astro | 16 +++++++++-- next/src/layouts/Base.astro | 11 +++++++- next/src/layouts/DocPage.astro | 1 + next/src/styles/global.css | 7 +++++ 6 files changed, 93 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 35f6672faf1..ca465c1e5f2 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -165,8 +165,21 @@ jobs: working-directory: next run: | npm ci + # Project docs live in the upstream Apache repos. Sparse, depth-1 + # clones of just docs/ keep this to a few seconds each; the sync + # script reads .sync/<repo>/docs/{en,zh}/latest and skips any repo + # that is absent, so a fetch failure degrades to "no pages for that + # project" — which the parity gate below then catches. + mkdir -p .sync + for repo in apisix apisix-ingress-controller apisix-helm-chart \ + apisix-docker apisix-java-plugin-runner \ + apisix-go-plugin-runner apisix-python-plugin-runner; do + git clone --depth 1 --filter=blob:none --sparse -q \ + "https://github.com/apache/$repo.git" ".sync/$repo" || continue + (cd ".sync/$repo" && git sparse-checkout set docs) || true + done # Blog/learning-center/articles markdown is synced from this very - # checkout (WEBSITE_REPO); project docs stay un-synced until wave 3. + # checkout (WEBSITE_REPO); project docs come from .sync/ above. WEBSITE_REPO="$GITHUB_WORKSPACE" node scripts/sync-content.mjs npx astro build @@ -200,6 +213,26 @@ jobs: echo "NON-HTML files not in the Astro tree and not in the feed-carry list:"; echo "$unhandled"; fail=1 fi done + # Latest-version docs: every version-less page Docusaurus produced + # must exist in the Astro build, or the swap would leave a stale + # Docusaurus page behind a URL we claim to own. Versioned dirs are + # excluded — they stay Docusaurus by design. So are docs/*/tags/ + # index pages: Docusaurus emits them empty (one self-link, absent + # from the sitemap, linked from no doc page). The per-page swap + # leaves them in place, so the URLs keep resolving. + for docs_root in docs zh/docs; do + [ -d "website/build/$docs_root" ] || continue + missing=$(cd "website/build/$docs_root" && find . -name index.html \ + | sed 's|^\./||' \ + | grep -vE '(^|/)([0-9]+\.[0-9]+|next|v[0-9][^/]*)/' \ + | grep -vE '(^|/)tags/index\.html$' \ + | sort | while read -r f; do + [ -f "$ROOT/next/dist/$docs_root/$f" ] || echo "$docs_root/$f" + done) + if [ -n "$missing" ]; then + echo "MISSING latest-version docs in the Astro build:"; echo "$missing"; fail=1 + fi + done exit $fail - name: Carry the Docusaurus RSS/atom feeds into the Astro tree @@ -229,6 +262,32 @@ jobs: mkdir -p "website/build/$(dirname "$path")" cp -R "next/dist/$path" "website/build/$path" done + # Latest-version docs come from Astro; every versioned directory + # (3.16/, next/, v1.6/, …) stays exactly as Docusaurus built it. + # Replacement is per-page, not per-subtree: under docs/<project>/ the + # version dirs and the latest-version pages sit side by side, so a + # subtree swap would delete the archive. Only paths the Astro build + # actually produced are touched. + for locale_prefix in "" "zh/"; do + src="next/dist/${locale_prefix}docs" + [ -d "$src" ] || continue + (cd "$src" && find . -name index.html) | sed 's|^\./||' | while read -r rel; do + case "$rel" in + # Never touch an archived version directory. + */[0-9].[0-9]*/*|*/next/*|*/v[0-9]*/*) continue ;; + esac + dest="website/build/${locale_prefix}docs/$rel" + mkdir -p "$(dirname "$dest")" + cp "$src/$rel" "$dest" + done + done + # The version archives must survive untouched. + test -f website/build/docs/apisix/3.16/plugins/cors/index.html + test -f website/build/docs/apisix/next/plugins/cors/index.html + grep -q 'docusaurus' website/build/docs/apisix/3.16/plugins/cors/index.html + # …and the latest-version pages must now be the Astro build. + grep -q '/_astro/' website/build/docs/apisix/plugins/cors/index.html + grep -q '/_astro/' website/build/zh/docs/apisix/plugins/cors/index.html # Fail the deploy if the landing pages are not the Astro build, or # if the homepage lost its stylesheet link. grep -q 'The same gateway, now for your LLM traffic' website/build/index.html diff --git a/next/.gitignore b/next/.gitignore index eb5a90df25f..d2b0fe9f85f 100644 --- a/next/.gitignore +++ b/next/.gitignore @@ -3,3 +3,4 @@ dist/ .sync/ content/ .astro/ +.sync/ diff --git a/next/src/components/Header.astro b/next/src/components/Header.astro index 30a0e51f6f8..225f574ba0c 100644 --- a/next/src/components/Header.astro +++ b/next/src/components/Header.astro @@ -1,8 +1,8 @@ --- import { NAV, LOGO, localePrefix, type Locale } from '../lib/site'; -interface Props { locale: Locale; path: string } -const { locale, path } = Astro.props; +interface Props { locale: Locale; path: string; search?: boolean } +const { locale, path, search = false } = Astro.props; const prefix = localePrefix(locale); const label = (item: { label: string; labelZh?: string }) => locale === 'zh' && item.labelZh ? item.labelZh : item.label; @@ -31,6 +31,18 @@ const switchUrl = locale === 'zh' ? path : `/zh${path}`; ))} <a href="https://github.com/apache/apisix" title="GitHub">GitHub</a> <a href={switchUrl} title={locale === 'zh' ? 'English' : '简体中文'}>{locale === 'zh' ? 'EN' : '中'}</a> + {search && <div id="docsearch" class="docsearch-slot" />} + {search && ( + <script + src="https://cdn.jsdelivr.net/npm/@docsearch/js@3" + data-appid="38VC84A2WJ" + data-apikey="73248b6e5908d49bb7986c4aef5fd30d" + data-indexname="apache_apisix" + is:inline + defer + onload="docsearch({container:'#docsearch',appId:this.dataset.appid,apiKey:this.dataset.apikey,indexName:this.dataset.indexname})" + /> + )} </nav> <details class="mobile-toggle"> <summary aria-label="Menu">☰</summary> diff --git a/next/src/layouts/Base.astro b/next/src/layouts/Base.astro index 82b5544f5d8..8bff41dbd85 100644 --- a/next/src/layouts/Base.astro +++ b/next/src/layouts/Base.astro @@ -17,6 +17,8 @@ interface Props { /** Open Graph object type; article pages pass "article". */ ogType?: 'website' | 'article'; noindex?: boolean; + /** Load Algolia DocSearch (docs pages only — every other page stays zero-JS). */ + search?: boolean; /** Cross-site canonical embedded in upstream docs (docs.api7.ai hub pages). */ canonicalOverride?: string; /** Set false when the title is already the complete tag (homepage). */ @@ -35,6 +37,7 @@ const { canonicalOverride, titleSuffix = true, ogType = 'website', + search = false, } = Astro.props; const enUrl = `${SITE}${path}`; @@ -68,9 +71,15 @@ const allJsonLd = [...ORG_JSONLD, ...jsonLd]; <meta name="twitter:card" content={image ? 'summary_large_image' : 'summary'} /> <meta name="twitter:site" content="@apacheapisix" /> <script type="application/ld+json" set:html={JSON.stringify(allJsonLd)} /> + {search && ( + <> + <link rel="preconnect" href="https://38VC84A2WJ-dsn.algolia.net" crossorigin /> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docsearch/css@3" /> + </> + )} </head> <body> - <Header locale={locale} path={path} /> + <Header locale={locale} path={path} search={search} /> <main> <slot /> </main> diff --git a/next/src/layouts/DocPage.astro b/next/src/layouts/DocPage.astro index 3d07ba5cf4a..4be638d6b3a 100644 --- a/next/src/layouts/DocPage.astro +++ b/next/src/layouts/DocPage.astro @@ -37,6 +37,7 @@ const renderable = (node: SidebarNode): boolean => !!node.id || !!(node.items && path={path} jsonLd={jsonLd} canonicalOverride={entry.mod.frontmatter.canonical} + search > <div class="container docs-layout"> {sidebar.length > 0 && ( diff --git a/next/src/styles/global.css b/next/src/styles/global.css index 00a1dff941d..0dd5d93fdbf 100644 --- a/next/src/styles/global.css +++ b/next/src/styles/global.css @@ -428,3 +428,10 @@ section.endcta.alt { background: transparent; padding: 4rem 1rem 0; } .anchor-link { opacity: 0; margin-left: .35rem; font-size: .8em; } h2:hover .anchor-link, h3:hover .anchor-link, .anchor-link:focus-visible { opacity: 1; } @media (hover: none) { .anchor-link { opacity: .55; } } + +/* ---------- docs search (Algolia DocSearch, docs pages only) ---------- */ +.docsearch-slot { margin-left: .5rem; } +.docsearch-slot .DocSearch-Button { height: 36px; margin: 0; border-radius: 8px; background: var(--color-surface-alt); } +.docsearch-slot .DocSearch-Button:hover { box-shadow: none; border-color: var(--color-hover-border); } +:root { --docsearch-primary-color: var(--color-primary); --docsearch-highlight-color: var(--color-primary); } +@media (max-width: 996px) { .docsearch-slot { display: none; } }
