This is an automated email from the ASF dual-hosted git repository. Yilialinn pushed a commit to branch codex/technical-mobile-seo in repository https://gitbox.apache.org/repos/asf/apisix-website.git
commit 23ea0695684afe70e1f83c4e3dd75dcab8efa407 Author: Yilia Lin <[email protected]> AuthorDate: Tue Jun 16 15:33:44 2026 +0800 Improve technical SEO and mobile performance --- blog/en/docusaurus.config.js | 8 ++ blog/src/css/customTheme.scss | 55 ++++++++++++ blog/src/theme/CodeBlock/styles.module.css | 9 ++ blog/src/theme/NotFound/index.tsx | 20 +++-- blog/zh/docusaurus.config.js | 8 ++ config/ssrTemplate.js | 41 ++++++--- doc/docusaurus.config.js | 8 ++ doc/src/css/customTheme.scss | 55 ++++++++++++ doc/src/pages/edit.tsx | 2 +- doc/src/theme/CodeBlock/styles.module.css | 9 ++ doc/src/theme/NotFound/index.tsx | 20 +++-- seo_technical_mobile_changes.csv | 15 ++++ seo_technical_mobile_followup_items.csv | 15 ++++ seo_technical_mobile_implementation_summary.md | 115 +++++++++++++++++++++++++ seo_technical_mobile_review_checklist.md | 43 +++++++++ website/docusaurus.config.js | 8 +- website/src/components/AIGateway/AvifImage.tsx | 10 ++- website/src/components/AIGateway/Hero.tsx | 3 +- website/src/components/HeroCanvas.tsx | 15 ++-- website/src/css/customTheme.scss | 55 ++++++++++++ website/src/css/landing-sections/hero.scss | 49 ++++++++++- website/src/pages/ai-gateway.tsx | 9 ++ website/src/pages/index.tsx | 4 + website/src/theme/NotFound/index.tsx | 20 +++-- website/static/robots.txt | 14 +++ 25 files changed, 562 insertions(+), 48 deletions(-) diff --git a/blog/en/docusaurus.config.js b/blog/en/docusaurus.config.js index f07832c66e1..93003060185 100644 --- a/blog/en/docusaurus.config.js +++ b/blog/en/docusaurus.config.js @@ -15,10 +15,18 @@ const metadatas = [ name: 'robots', content: 'index,follow', }, + { + property: 'og:site_name', + content: 'Apache APISIX', + }, { name: 'twitter:card', content: 'summary_large_image', }, + { + name: 'twitter:site', + content: '@apacheapisix', + }, ]; module.exports = { diff --git a/blog/src/css/customTheme.scss b/blog/src/css/customTheme.scss index 6a330ec0073..f220effa6cb 100644 --- a/blog/src/css/customTheme.scss +++ b/blog/src/css/customTheme.scss @@ -526,3 +526,58 @@ button[class*="announcementBarClose"] { font-weight: 500; } } + +/* stylelint-disable no-descending-specificity */ +.markdown img, +article img { + max-width: 100%; + height: auto; +} + +.markdown table { + display: block; + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.markdown pre { + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +h1, +h2, +h3, +[id] { + scroll-margin-top: calc(var(--ifm-navbar-height) + 16px); +} + +@media screen and (max-width: 996px) { + article { + font-size: 17px; + line-height: 1.75; + } + + article p { + font-size: 17px; + line-height: 1.75; + } + + article h1 { + font-size: 2.1rem; + line-height: 1.15; + } + + article h2 { + font-size: 1.75rem; + line-height: 1.2; + } + + article h3 { + font-size: 1.35rem; + line-height: 1.25; + } +} +/* stylelint-enable no-descending-specificity */ diff --git a/blog/src/theme/CodeBlock/styles.module.css b/blog/src/theme/CodeBlock/styles.module.css index 707a187e50e..9a9e1705c3b 100644 --- a/blog/src/theme/CodeBlock/styles.module.css +++ b/blog/src/theme/CodeBlock/styles.module.css @@ -17,6 +17,8 @@ .codeBlockContent { position: relative; direction: ltr; + max-width: 100%; + overflow-x: auto; } .codeBlockTitle { @@ -30,6 +32,7 @@ margin: 0; padding: 0; border-radius: 0; + min-width: 100%; } .copyButton { @@ -65,3 +68,9 @@ white-space: pre-wrap; } } + +@media (hover: none) { + .copyButton { + opacity: 1; + } +} diff --git a/blog/src/theme/NotFound/index.tsx b/blog/src/theme/NotFound/index.tsx index f8c6490bf6d..c8a513b32b1 100644 --- a/blog/src/theme/NotFound/index.tsx +++ b/blog/src/theme/NotFound/index.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react'; import React from 'react'; import Layout from '@theme/Layout'; +import Head from '@docusaurus/Head'; import { translate } from '@docusaurus/Translate'; import Link from '@docusaurus/Link'; import style from './styles.module.scss'; @@ -14,6 +15,9 @@ const NotFound: FC = () => ( message: 'Page Not Found', })} > + <Head> + <meta name="robots" content="noindex,follow" /> + </Head> <main className={style.container}> <section> <Fitty tagName="h1" contentEditable>404</Fitty> @@ -31,12 +35,16 @@ const NotFound: FC = () => ( . </p> <p> - You can also return to + You can also open the {' '} - <Link href="/"> - the home page - </Link> - . Or, return to + <Link to="/">home page</Link> + , + {' '} + <Link to="/docs/">documentation</Link> + , + {' '} + <Link to="/blog/">blog</Link> + , or {' '} <a role="button" @@ -45,7 +53,7 @@ const NotFound: FC = () => ( window?.history.back(); }} > - the source page + return to the source page </a> . </p> diff --git a/blog/zh/docusaurus.config.js b/blog/zh/docusaurus.config.js index 3af01760c79..23d6b7b915b 100644 --- a/blog/zh/docusaurus.config.js +++ b/blog/zh/docusaurus.config.js @@ -16,10 +16,18 @@ const metadatas = [ name: 'robots', content: 'index,follow', }, + { + property: 'og:site_name', + content: 'Apache APISIX', + }, { name: 'twitter:card', content: 'summary_large_image', }, + { + name: 'twitter:site', + content: '@apacheapisix', + }, ]; module.exports = { diff --git a/config/ssrTemplate.js b/config/ssrTemplate.js index 7edf02dd6eb..8bd22cd7d32 100644 --- a/config/ssrTemplate.js +++ b/config/ssrTemplate.js @@ -6,6 +6,11 @@ module.exports = { <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="ahrefs-site-verification" content="c2f7370ecf46173f4fb25f114e74c97e0a2976d4f02f61c9b00a9d7d34e34698"> <meta name="generator" content="Docusaurus v<%= it.version %>"> + <link rel="preconnect" href="https://static.apiseven.com" crossorigin> + <link rel="preconnect" href="https://apisix-website-static.apiseven.com" crossorigin> + <link rel="preconnect" href="https://static.api7.ai" crossorigin> + <link rel="dns-prefetch" href="https://analytics.apache.org"> + <link rel="dns-prefetch" href="https://widget.kapa.ai"> <% if (it.noIndex) { %> <meta name="robots" content="noindex, nofollow" /> <% } %> @@ -22,21 +27,29 @@ module.exports = { <% }); %> <!-- Matomo from the ASF --> <script> - var _paq = window._paq = window._paq || []; - /* tracker methods like "setCustomDimension" should be called before + window._paq = window._paq || []; + function loadMatomo() { + var _paq = window._paq; + /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ - /* We explicitly disable cookie tracking to avoid privacy issues */ - _paq.push(['disableCookies']); - _paq.push(['trackPageView']); - _paq.push(['enableLinkTracking']); - (function() { - var u="https://analytics.apache.org/"; - _paq.push(['setTrackerUrl', u+'matomo.php']); - _paq.push(['setSiteId', '17']); - var d=document, g=d.createElement('script'), - s=d.getElementsByTagName('script')[0]; - g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); - })(); + /* We explicitly disable cookie tracking to avoid privacy issues */ + _paq.push(['disableCookies']); + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="https://analytics.apache.org/"; + _paq.push(['setTrackerUrl', u+'matomo.php']); + _paq.push(['setSiteId', '17']); + var d=document, g=d.createElement('script'), + s=d.getElementsByTagName('script')[0]; + g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); + })(); + } + if ('requestIdleCallback' in window) { + window.requestIdleCallback(loadMatomo, { timeout: 3000 }); + } else { + window.addEventListener('load', loadMatomo, { once: true }); + } </script> <!-- End Matomo Code --> </head> diff --git a/doc/docusaurus.config.js b/doc/docusaurus.config.js index 80324e4e15d..ef8c7e8d008 100644 --- a/doc/docusaurus.config.js +++ b/doc/docusaurus.config.js @@ -251,10 +251,18 @@ module.exports = { name: 'robots', content: 'index,follow', }, + { + property: 'og:site_name', + content: 'Apache APISIX', + }, { name: 'twitter:card', content: 'summary_large_image', }, + { + name: 'twitter:site', + content: '@apacheapisix', + }, ], }, scripts: [ diff --git a/doc/src/css/customTheme.scss b/doc/src/css/customTheme.scss index 26ecfa5e636..dfa1d0d3df3 100644 --- a/doc/src/css/customTheme.scss +++ b/doc/src/css/customTheme.scss @@ -524,3 +524,58 @@ button[class*="announcementBarClose"] { font-weight: 500; } } + +/* stylelint-disable no-descending-specificity */ +.markdown img, +article img { + max-width: 100%; + height: auto; +} + +.markdown table { + display: block; + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.markdown pre { + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +h1, +h2, +h3, +[id] { + scroll-margin-top: calc(var(--ifm-navbar-height) + 16px); +} + +@media screen and (max-width: 996px) { + article { + font-size: 17px; + line-height: 1.75; + } + + article p { + font-size: 17px; + line-height: 1.75; + } + + article h1 { + font-size: 2.1rem; + line-height: 1.15; + } + + article h2 { + font-size: 1.75rem; + line-height: 1.2; + } + + article h3 { + font-size: 1.35rem; + line-height: 1.25; + } +} +/* stylelint-enable no-descending-specificity */ diff --git a/doc/src/pages/edit.tsx b/doc/src/pages/edit.tsx index 2914c8291b4..c9a14bda71f 100644 --- a/doc/src/pages/edit.tsx +++ b/doc/src/pages/edit.tsx @@ -57,7 +57,7 @@ const Edit: FC = () => { /> <meta name="twitter:site" content="@apacheapisix" /> <meta - name="og:description" + property="og:description" content="Apache APISIX is a dynamic, real-time, high-performance Cloud-Native API gateway, based on the Nginx library and etcd." /> </Head> diff --git a/doc/src/theme/CodeBlock/styles.module.css b/doc/src/theme/CodeBlock/styles.module.css index 707a187e50e..9a9e1705c3b 100644 --- a/doc/src/theme/CodeBlock/styles.module.css +++ b/doc/src/theme/CodeBlock/styles.module.css @@ -17,6 +17,8 @@ .codeBlockContent { position: relative; direction: ltr; + max-width: 100%; + overflow-x: auto; } .codeBlockTitle { @@ -30,6 +32,7 @@ margin: 0; padding: 0; border-radius: 0; + min-width: 100%; } .copyButton { @@ -65,3 +68,9 @@ white-space: pre-wrap; } } + +@media (hover: none) { + .copyButton { + opacity: 1; + } +} diff --git a/doc/src/theme/NotFound/index.tsx b/doc/src/theme/NotFound/index.tsx index f8c6490bf6d..c8a513b32b1 100644 --- a/doc/src/theme/NotFound/index.tsx +++ b/doc/src/theme/NotFound/index.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react'; import React from 'react'; import Layout from '@theme/Layout'; +import Head from '@docusaurus/Head'; import { translate } from '@docusaurus/Translate'; import Link from '@docusaurus/Link'; import style from './styles.module.scss'; @@ -14,6 +15,9 @@ const NotFound: FC = () => ( message: 'Page Not Found', })} > + <Head> + <meta name="robots" content="noindex,follow" /> + </Head> <main className={style.container}> <section> <Fitty tagName="h1" contentEditable>404</Fitty> @@ -31,12 +35,16 @@ const NotFound: FC = () => ( . </p> <p> - You can also return to + You can also open the {' '} - <Link href="/"> - the home page - </Link> - . Or, return to + <Link to="/">home page</Link> + , + {' '} + <Link to="/docs/">documentation</Link> + , + {' '} + <Link to="/blog/">blog</Link> + , or {' '} <a role="button" @@ -45,7 +53,7 @@ const NotFound: FC = () => ( window?.history.back(); }} > - the source page + return to the source page </a> . </p> diff --git a/seo_technical_mobile_changes.csv b/seo_technical_mobile_changes.csv new file mode 100644 index 00000000000..be0a28b5f62 --- /dev/null +++ b/seo_technical_mobile_changes.csv @@ -0,0 +1,15 @@ +"Priority","Workstream","Issue","Action Taken","Files Changed","Expected SEO Impact","Review Notes" +"P0","Mobile Core Web Vitals","Mobile LCP risk on homepage hero due animated first-viewport text and full-height layout","Disabled hero entrance animation on mobile/reduced-motion, switched to mobile min-height with svh, added responsive clamp sizing and wrapping","website/src/css/landing-sections/hero.scss","Improve mobile first-content readability and reduce LCP/perceived LCP delay","Check homepage mobile visual layout around 360px, 390px, 768px, and desktop" +"P0","Performance / INP","Head analytics script competes with critical rendering work","Delayed Matomo loading using requestIdleCallback with load fallback","config/ssrTemplate.js","Reduce initial main-thread and network pressure during LCP window","Confirm analytics stakeholders accept delayed pageview initialization" +"P0","Performance / LCP","Critical static asset domains had no explicit early connection hints","Added preconnect for static asset domains and dns-prefetch for analytics/widget domains","config/ssrTemplate.js","Reduce connection setup latency for fonts/static assets and third-party scripts","Verify generated head includes the new hints once in built HTML" +"P0","AI Gateway LCP","AI Gateway hero image could inherit lazy behavior from shared image component","Set AI Gateway hero image to eager and reserved minimum hero image height","website/src/components/AIGateway/Hero.tsx","Protect likely LCP image from accidental lazy loading and reduce layout shift","Check hero image does not create too much blank space on mobile" +"P1","Image Loading","Shared AI Gateway image component lacked default loading/decoding behavior","Added default loading=lazy and decoding=async while allowing callers to override","website/src/components/AIGateway/AvifImage.tsx","Improve non-critical image loading and browser decoding behavior","Confirm Chakra Image passes loading/decoding to img output" +"P1","Rendering Performance","Hero WebGL canvas rendered at full devicePixelRatio and did not remove listeners on unmount","Capped renderer pixel ratio at 1.5 and removed resize/mousemove listeners during cleanup","website/src/components/HeroCanvas.tsx","Reduce GPU/render cost and avoid listener leaks affecting interactions","Check desktop hero animation still looks acceptable on Retina screens" +"P1","Mobile UX / CLS","Docs/blog/main content images, tables, and code blocks can overflow mobile viewport","Added mobile-safe image, table, pre, article typography, and anchor offset rules across website/doc/blog themes","website/src/css/customTheme.scss; doc/src/css/customTheme.scss; blog/src/css/customTheme.scss","Reduce horizontal overflow, improve mobile reading, reduce layout instability","Review docs/blog article typography on mobile and desktop" +"P1","Mobile Docs UX","Code block copy button depended on hover and long code could be awkward on touch devices","Added max-width/overflow handling and visible copy button on hoverless devices","doc/src/theme/CodeBlock/styles.module.css; blog/src/theme/CodeBlock/styles.module.css","Improve docs/blog mobile usability and reduce interaction friction","Check copy button does not cover important code on narrow screens" +"P1","Metadata / CTR","Homepage lacked page-specific meta description and had malformed OG description attribute","Added homepage description and og:title; changed og description from name to property; normalized title dash","website/src/pages/index.tsx","Improve homepage snippet quality and Open Graph correctness","Check final rendered head has no duplicate conflicting descriptions" +"P1","Metadata / Social SEO","AI Gateway page lacked social image metadata and used small Twitter card","Added og:image/twitter:image and summary_large_image Twitter card","website/src/pages/ai-gateway.tsx","Improve share preview and reinforce AI Gateway landing page relevance","Confirm image URL remains stable and public" +"P1","Metadata / Social SEO","Default site-level social metadata was incomplete across website/doc/blog builds","Added og:site_name and twitter:site in all Docusaurus configs","website/docusaurus.config.js; doc/docusaurus.config.js; blog/en/docusaurus.config.js; blog/zh/docusaurus.config.js","Improve social metadata consistency across templates","Verify no conflicting site_name values in page-specific Head" +"P1","Indexing / Soft 404","Static 404 pages could be treated as indexable pages in static hosting contexts","Added noindex,follow and useful recovery links to website/doc/blog 404 templates","website/src/theme/NotFound/index.tsx; doc/src/theme/NotFound/index.tsx; blog/src/theme/NotFound/index.tsx","Reduce 404/Soft 404 index risk and improve crawl/user recovery paths","Confirm host still returns proper 404 status for 404.html routes" +"P1","Indexing / Duplicate Docs","Robots blocked versioned docs through 3.15 but current version config includes 3.16","Added 3.16 versioned docs paths to robots exclusions for all docs projects and zh equivalents","website/static/robots.txt","Reduce duplicate latest vs versioned docs indexing signals","Confirm maintainers agree latest unversioned docs should be the only indexed current docs" +"P2","Metadata Syntax","Doc edit page used name instead of property for Open Graph description","Changed name=og:description to property=og:description","doc/src/pages/edit.tsx","Fix Open Graph metadata syntax","Low-risk syntax correction" diff --git a/seo_technical_mobile_followup_items.csv b/seo_technical_mobile_followup_items.csv new file mode 100644 index 00000000000..2025edbf584 --- /dev/null +++ b/seo_technical_mobile_followup_items.csv @@ -0,0 +1,15 @@ +"Priority","Issue","Why Not Changed Directly","Recommended Next Step","Owner" +"P0","Crawled - currently not indexed: 2935 URLs","GSC export used for this task contains aggregate counts, not URL-level samples; changing canonical/noindex/content blindly is unsafe","Export URL samples from GSC, classify by page type and business value, then fix high-value docs/blog/landing pages first","SEO + Website" +"P0","404: 873 URLs","No URL-level backlink/internal-link/traffic context was available; bulk redirects could send users and crawlers to wrong targets","Export 404 URL list, join with internal links and backlinks, then create a reviewed redirect map for valuable URLs","SEO + Website" +"P0","Soft 404: 584 URLs","Soft 404 causes vary by URL: thin content, empty templates, obsolete docs, or wrong status; template-only fix would be risky","Sample and classify Soft 404 URLs; fix templates for systemic cases and redirect/remove only confirmed obsolete pages","SEO + Website" +"P0","Full combined build did not complete in local checkout","Docs content was not synced, GitHub API hit rate limit, and local blog prepare did not create src folders under Node 26","Run full build in CI or prepared local env with GITHUB_TOKEN, yarn sync-docs, generated repo info, and blog prepared folders","Engineering" +"P0","Isolated build reports many broken docs/blog links","The main site build was run without merged doc/blog outputs, so Docusaurus reported expected cross-part links as broken","Review broken links after full generate-website build with docs and blog outputs present","Engineering" +"P1","Versioned docs indexing strategy","Robots currently blocks versioned docs; switching to canonical/noindex needs maintainer agreement and build-output validation","Decide whether versioned docs should be robots-blocked, noindexed, or canonicalized to latest/current equivalents","SEO + Maintainers" +"P1","Indexed though blocked by robots.txt: 629 URLs","Robots changes alone cannot remove already indexed blocked URLs; samples are needed to choose noindex/canonical/removal","Export samples and use URL inspection to decide whether to unblock + noindex, canonicalize, or request removal","SEO" +"P1","Duplicate, Google chose different canonical: 537 URLs","Need sample URL pairs to understand whether issue comes from docs versions, language alternates, trailing slash, or duplicate content","Export samples and compare rendered canonical/hreflang in production HTML","SEO + Engineering" +"P1","Internal links to high-opportunity pages","Several target pillar/landing pages are not built yet; adding links to placeholders would create broken links","After Task 3 content pages exist, add natural internal links from docs/blog/topic hubs to AI Gateway, API Security, Kubernetes, Comparison pages","Content + SEO" +"P1","Kapa widget JS loads on all pages","Changing support widget loading behavior may affect documentation support UX; needs owner approval","Evaluate idle-loading or route-specific loading for Kapa widget and measure INP impact","Docs + Engineering" +"P1","Mobile Core Web Vitals validation","Local code changes need field/lab validation on production-like build and real target URLs","Run Lighthouse/PageSpeed on homepage, AI Gateway, docs getting started, plugin docs, and high-traffic blog pages before/after deploy","SEO + Engineering" +"P2","Hreflang/canonical output audit","Docusaurus should generate alternates, but this needs rendered HTML verification across website/doc/blog builds","Crawl built site and verify canonical, hreflang, trailing slash, and locale alternates for representative pages","SEO" +"P2","Blog prepare script behavior under Node 26","Local `yarn workspace blog prepare-en` did not produce `blog/en/src`, blocking isolated blog build validation","Reproduce on CI-supported Node version; if still failing, replace hexo-fs copy step with a deterministic fs.cp script","Engineering" +"P2","Browserslist and Docusaurus warnings","Build passes with warnings, but dependencies are old and can affect modern browser targets","Schedule dependency maintenance separately; do not combine with SEO implementation PR","Engineering" diff --git a/seo_technical_mobile_implementation_summary.md b/seo_technical_mobile_implementation_summary.md new file mode 100644 index 00000000000..6e0abc39f24 --- /dev/null +++ b/seo_technical_mobile_implementation_summary.md @@ -0,0 +1,115 @@ +# APISIX Technical SEO + Mobile SEO Implementation Summary + +## 1. Summary + +本次基于 APISIX SEO 报告、GSC 技术 SEO 数据和 `apache/apisix-website` 当前代码,完成了一批可直接落地、低风险、可 review 的技术 SEO 与移动端优化。 + +重点处理了四类问题: + +- 移动端 LCP / CLS 风险:减少首页移动端首屏动画阻塞,优化 AI Gateway 首屏图加载,稳定图片、表格、代码块在移动端的布局。 +- 页面体验与 INP 风险:延迟 Matomo 加载、减少首屏网络竞争、清理 HeroCanvas 事件监听并限制高 DPI WebGL 渲染开销。 +- Metadata / Social SEO:补充和修复默认站点级社交信号、首页 description、AI Gateway 分享图片、Open Graph 属性错误。 +- Indexing / Coverage 信号:404 页面增加 `noindex,follow`,robots 补齐 `3.16` 版本化 docs URL 的排除规则,减少 latest 与 versioned docs 重复索引风险。 + +没有做高风险动作,例如批量删除页面、批量 301、批量 noindex 旧内容、大规模 URL 改写。这些已经放入 follow-up 清单。 + +## 2. Repository Audit + +| Item | Finding | +| --- | --- | +| Repository | `/Users/api7/Documents/GitHub/contents/apisix-website` | +| Remote | `https://github.com/apache/apisix-website.git` | +| Branch | `pr/2028` | +| Framework | Docusaurus v2 beta multi-workspace static site | +| Workspaces | `website`, `doc`, `blog`, `scripts` | +| Main build | `yarn build` -> `yarn workspace scripts generate-website` | +| Main site config | `website/docusaurus.config.js` | +| Docs config | `doc/docusaurus.config.js` | +| Blog config | `blog/en/docusaurus.config.js`, `blog/zh/docusaurus.config.js` | +| Head template | `config/ssrTemplate.js` | +| Structured data | `config/schema-org.js` | +| Robots | `website/static/robots.txt` | +| Sitemap post-process | `scripts/update-sitemap-loc.js` | +| Main styles | `website/src/css/customTheme.scss`, `doc/src/css/customTheme.scss`, `blog/src/css/customTheme.scss` | +| Homepage | `website/src/pages/index.tsx`, `website/src/components/sections/HeroSection.tsx` | +| AI Gateway page | `website/src/pages/ai-gateway.tsx`, `website/src/components/AIGateway/*` | + +## 3. Input Data Audit + +| File | Type | Main Content | Used For | Notes | +| --- | --- | --- | --- | --- | +| `/Users/api7/Documents/APISIX SEO/apisix_seo_integrated_final_report_zh.md` | Final SEO report | GSC, Semrush, technical SEO, opportunities | Overall direction | Used as the main source of priorities | +| `/Users/api7/Documents/APISIX SEO/apisix_gsc_technical_seo_update_zh.md` | Technical SEO update | CWV, Coverage, Internal Links findings | Technical prioritization | Identified mobile LCP, indexing, internal-link risks | +| `/Users/api7/Documents/APISIX SEO/gsc_core_web_vitals_issues.csv` | GSC CWV | Mobile LCP and INP issue counts | Mobile performance scope | Confirmed P0 mobile LCP issue | +| `/Users/api7/Documents/APISIX SEO/gsc_indexing_coverage_issues.csv` | GSC Coverage | Crawled not indexed, 404, Soft 404, robots, duplicate issues | Indexing scope | Used to decide what can and cannot be directly changed | +| `/Users/api7/Documents/APISIX SEO/gsc_internal_link_opportunities.csv` | GSC internal links | High-value pages with low internal links | Follow-up planning | Not directly changed because target pillar pages need content decisions | +| `/Users/api7/Documents/APISIX SEO/gsc_internal_links_top_targets.csv` | GSC internal links | Current internal-link distribution | Follow-up planning | Used to avoid adding arbitrary template links | +| `/Users/api7/Documents/APISIX SEO/gsc_apisix_page_opportunities.csv` | GSC page opportunities | Page-level SEO opportunities | Page prioritization | Used to focus on homepage, docs, AI Gateway, high-value templates | + +## 4. Directly Changed + +| Area | What Changed | Why | +| --- | --- | --- | +| Head resource hints | Added `preconnect` for static asset domains and `dns-prefetch` for analytics/widget domains | Reduce connection setup cost for critical assets and third-party scripts | +| Analytics loading | Delayed Matomo initialization via `requestIdleCallback` / `load` fallback | Reduce head-script competition during LCP window | +| Homepage metadata | Added stronger homepage `description`, fixed title format, added `og:title`, fixed `og:description` property | Improve default search/social snippet quality and fix Open Graph syntax | +| AI Gateway metadata | Added `og:image`, `twitter:image`, changed Twitter card to `summary_large_image` | Improve share preview and strengthen AI Gateway landing-page metadata | +| Default social metadata | Added `og:site_name` and `twitter:site` in website/doc/blog configs | Improve default social metadata consistency | +| AI Gateway images | Made `AvifImage` default to lazy + async decoding; set hero image to eager | Avoid lazy-loading the likely LCP image while keeping non-critical images lazy | +| Homepage mobile hero | Disabled hero entrance animation on mobile/reduced-motion, added `svh`, clamp sizing, better wrapping | Reduce mobile LCP delay and layout overflow risk | +| HeroCanvas | Capped WebGL pixel ratio and removed resize/mousemove listeners on unmount | Reduce render cost and cleanup interaction listeners | +| Mobile content CSS | Added image/table/pre overflow and mobile article typography rules in website/doc/blog | Improve docs/blog readability and reduce horizontal overflow / CLS risk | +| Code blocks | Added max-width/overflow handling and visible copy button on touch devices | Improve mobile docs/blog usability | +| 404 pages | Added `noindex,follow` and useful recovery links in website/doc/blog 404 templates | Avoid indexing static 404 pages and help users/crawlers recover | +| Robots | Added `3.16` versioned docs to robots exclusions | Align robots with current version config and latest-only docs indexing strategy | +| Open Graph bug | Fixed `name="og:description"` to `property="og:description"` | Correct OG metadata syntax | + +## 5. Not Directly Changed + +| Issue | Reason | +| --- | --- | +| Bulk 301 redirects for 404 URLs | GSC export did not include concrete URL samples with backlink/traffic context; unsafe to batch redirect blindly | +| Soft 404 remediation | Needs URL-level classification: thin content, obsolete version docs, real missing page, or duplicate content | +| Crawled currently not indexed | Needs sample URLs and page-type classification before changing canonical/noindex/content | +| Versioned docs canonical strategy | Robots already blocks versioned docs; switching to canonical/noindex strategy needs maintainer decision | +| Internal-link additions to pillar pages | Several recommended pillar pages do not exist yet; linking to placeholders would create broken links | +| Large-scale content rewrites | Belongs to content strategy tasks, not low-risk technical SEO implementation | +| Kapa widget full lazy-loading | Possible, but should be reviewed with docs/support owners because it changes user support behavior | + +## 6. Validation + +| Check | Result | Notes | +| --- | --- | --- | +| `yarn install --frozen-lockfile` | Passed after network authorization | First attempt failed due DNS/network restriction | +| `git diff --check` | Passed | No whitespace errors | +| `node --check config/ssrTemplate.js` | Passed | JS syntax valid | +| `node --check website/docusaurus.config.js` | Passed | JS syntax valid | +| `node --check doc/docusaurus.config.js` | Passed | JS syntax valid | +| `node --check blog/en/docusaurus.config.js` | Passed | JS syntax valid | +| `node --check blog/zh/docusaurus.config.js` | Passed | JS syntax valid | +| Targeted ESLint | Passed | Checked modified TSX files | +| Targeted Stylelint | Passed | Checked modified SCSS/CSS files; project-level deprecation warnings only | +| `SHOW_BUILD_LOGS=false yarn build` | Failed due environment/prep issues | Full build needs docs sync and generated files; initial failure included sandbox write permission and missing doc sidebars | +| `yarn build:website` | Passed after generating local ignored build fixtures | English and Chinese main site compiled; isolated build logs existing broken links because doc/blog outputs were not merged | + +## 7. Build Caveats + +The main website build passed, but the full combined build could not be completed cleanly in this local checkout for reasons outside this SEO implementation: + +- `doc/docs/apisix/sidebars.json` and other synced docs files are missing until `yarn sync-docs` is run. +- `generate-repos-info` hit GitHub API rate limit without `GITHUB_TOKEN`. +- `blog prepare-en/prepare-zh` did not create `blog/en/src` / `blog/zh/src` in this local Node 26 environment, causing isolated blog builds to miss `./src/css/customTheme.scss`. +- Isolated main-site build reports broken links to docs/blog paths because those outputs are normally merged by the full build. + +These are recorded in `seo_technical_mobile_followup_items.csv`. + +## 8. Review Focus + +Reviewers should focus on: + +- Whether delaying Matomo until idle/load is acceptable for ASF analytics requirements. +- Whether adding `3.16` versioned docs to robots matches the intended latest-only docs indexing strategy. +- Mobile homepage hero visual regression on common viewports. +- AI Gateway hero image behavior on mobile: it should be eager for the first viewport but still use AVIF/WebP sources. +- 404 page `noindex,follow` behavior and recovery links. +- Whether global mobile typography changes are acceptable for docs/blog readability. diff --git a/seo_technical_mobile_review_checklist.md b/seo_technical_mobile_review_checklist.md new file mode 100644 index 00000000000..e4698b3988b --- /dev/null +++ b/seo_technical_mobile_review_checklist.md @@ -0,0 +1,43 @@ +# Technical SEO + Mobile SEO Review Checklist + +## Head And Metadata + +- [ ] Confirm `config/ssrTemplate.js` renders preconnect/dns-prefetch tags only once. +- [ ] Confirm delayed Matomo loading still satisfies analytics expectations. +- [ ] Confirm homepage rendered head contains the intended title, description, `og:title`, and `og:description`. +- [ ] Confirm AI Gateway rendered head contains `og:image`, `twitter:image`, and `summary_large_image`. +- [ ] Confirm `og:site_name` and `twitter:site` do not conflict with page-level metadata. + +## Mobile / Core Web Vitals + +- [ ] Test homepage at 360px, 390px, 768px, and desktop widths. +- [ ] Confirm mobile hero text is visible immediately and does not overflow. +- [ ] Confirm the homepage CTA still looks correct after animation changes. +- [ ] Confirm AI Gateway hero image loads in the first viewport and does not create layout shift. +- [ ] Confirm non-critical AI Gateway images still lazy-load. +- [ ] Confirm desktop HeroCanvas still renders acceptably after pixel ratio cap. + +## Docs / Blog Mobile UX + +- [ ] Open a docs page with a long code block and check horizontal scrolling. +- [ ] Open a blog post with images and verify images do not overflow on mobile. +- [ ] Open a docs page with a table and verify horizontal scrolling is usable. +- [ ] Check that anchor links scroll below the sticky navbar. +- [ ] Verify copy buttons are visible on touch devices and do not cover too much code. + +## Indexing / Coverage + +- [ ] Confirm `404.html` includes `noindex,follow`. +- [ ] Confirm 404 pages still return HTTP 404 in production hosting. +- [ ] Confirm `robots.txt` 3.16 exclusions match the docs version strategy. +- [ ] Confirm sitemap filtering still excludes versioned docs via `scripts/update-sitemap-loc.js`. +- [ ] Do not merge bulk redirect/noindex changes until GSC URL samples are classified. + +## Build / QA + +- [ ] Run `yarn install --frozen-lockfile`. +- [ ] Run targeted ESLint on modified TSX files. +- [ ] Run targeted Stylelint on modified SCSS/CSS files. +- [ ] Run `yarn build:website`. +- [ ] In CI or a prepared local environment, run full `yarn prepare-data` / `yarn build` with docs and blog generated. +- [ ] Review broken-link output only after docs/blog outputs are present in the merged build. diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index f6211b8d4ef..0cb370dfac7 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -154,6 +154,10 @@ module.exports = { name: 'robots', content: 'index,follow', }, + { + property: 'og:site_name', + content: 'Apache APISIX', + }, { name: 'twitter:card', content: 'summary_large_image', @@ -162,10 +166,6 @@ module.exports = { name: 'twitter:site', content: '@apacheapisix', }, - { - property: 'og:site_name', - content: 'Apache APISIX', - }, { property: 'og:type', content: 'website', diff --git a/website/src/components/AIGateway/AvifImage.tsx b/website/src/components/AIGateway/AvifImage.tsx index b33560b8698..0af8199cb2d 100644 --- a/website/src/components/AIGateway/AvifImage.tsx +++ b/website/src/components/AIGateway/AvifImage.tsx @@ -3,15 +3,21 @@ import type { ImageProps } from '@chakra-ui/react'; import { Image } from '@chakra-ui/react'; const AvifImage: React.FC<ImageProps> = ({ src, alt, ...props }) => { + const imageProps = { + decoding: 'async', + loading: 'lazy', + ...props, + }; + if (src?.toLowerCase().includes('.svg') || src?.includes('imageMogr2/')) { - return <Image src={src} alt={alt} {...props} />; + return <Image src={src} alt={alt} {...imageProps} />; } return ( <picture> <source srcSet={`${src}?imageMogr2/format/avif`} type="image/avif" /> <source srcSet={`${src}?imageMogr2/format/webp`} type="image/webp" /> - <Image src={src} alt={alt} {...props} /> + <Image src={src} alt={alt} {...imageProps} /> </picture> ); }; diff --git a/website/src/components/AIGateway/Hero.tsx b/website/src/components/AIGateway/Hero.tsx index 2da332e8cdd..ea52d9313bc 100644 --- a/website/src/components/AIGateway/Hero.tsx +++ b/website/src/components/AIGateway/Hero.tsx @@ -59,10 +59,11 @@ const Hero: React.FC = () => { display="flex" alignItems="center" > - <Box w="full"> + <Box w="full" minH={{ base: '260px', md: '360px' }}> <AvifImage src="https://static.api7.ai/uploads/2025/04/17/zdPVQ1zg_apisix-ai-gateway.png" alt="Apache APISIX AI Gateway architecture overview" + loading="eager" animation={fadeInAnimation} w="full" transform="scale(1.1)" diff --git a/website/src/components/HeroCanvas.tsx b/website/src/components/HeroCanvas.tsx index 32b13accfb8..fd93e4f6136 100644 --- a/website/src/components/HeroCanvas.tsx +++ b/website/src/components/HeroCanvas.tsx @@ -50,8 +50,6 @@ const HeroCanvas: FC = () => { let camera; let mesh; let scene; let renderer; let material; let geometry; - window.addEventListener('resize', onWindowResize, false); - if (screenWidth > 1100) { canvasHeight = screenHeight; canvasWidth = screenWidth / 2; @@ -63,7 +61,7 @@ const HeroCanvas: FC = () => { canvasRef.current.width = canvasWidth; canvasRef.current.height = canvasHeight; - canvasRef.current.addEventListener('mousemove', (event) => { + const handleCanvasMouseMove = (event: MouseEvent) => { const ctx = { x: (event.clientX), y: (event.clientY), @@ -96,7 +94,10 @@ const HeroCanvas: FC = () => { material.uniforms.u_fragMouse.value.y = fragMouse.y; }, }); - }); + }; + + window.addEventListener('resize', onWindowResize, false); + canvasRef.current.addEventListener('mousemove', handleCanvasMouseMove); function getRandom(a, b) { return a + (b - a) * Math.random(); @@ -114,8 +115,6 @@ const HeroCanvas: FC = () => { if (entry.isIntersecting && isLoaded) { if (isLoaded && !isRendering) { animate(); - } else { - console.log('Loading'); } } else { if (animationFrame) { @@ -210,7 +209,7 @@ const HeroCanvas: FC = () => { controls.update(); - renderer.setPixelRatio(window.devicePixelRatio); + renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 1.5)); onWindowResize(); isLoaded = true; @@ -249,6 +248,8 @@ const HeroCanvas: FC = () => { } return () => { + window.removeEventListener('resize', onWindowResize, false); + canvasRef.current?.removeEventListener('mousemove', handleCanvasMouseMove); // eslint-disable-next-line prefer-spread scene.remove.apply(scene, scene.children); canvasObserver.disconnect(); diff --git a/website/src/css/customTheme.scss b/website/src/css/customTheme.scss index 9d1950e8f7a..e12aff151cb 100644 --- a/website/src/css/customTheme.scss +++ b/website/src/css/customTheme.scss @@ -530,3 +530,58 @@ button[class*="announcementBarClose"] { font-weight: 500; } } + +/* stylelint-disable no-descending-specificity */ +.markdown img, +article img { + max-width: 100%; + height: auto; +} + +.markdown table { + display: block; + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +.markdown pre { + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +h1, +h2, +h3, +[id] { + scroll-margin-top: calc(var(--ifm-navbar-height) + 16px); +} + +@media screen and (max-width: 996px) { + article { + font-size: 17px; + line-height: 1.75; + } + + article p { + font-size: 17px; + line-height: 1.75; + } + + article h1 { + font-size: 2.1rem; + line-height: 1.15; + } + + article h2 { + font-size: 1.75rem; + line-height: 1.2; + } + + article h3 { + font-size: 1.35rem; + line-height: 1.25; + } +} +/* stylelint-enable no-descending-specificity */ diff --git a/website/src/css/landing-sections/hero.scss b/website/src/css/landing-sections/hero.scss index ac00c56029e..61bdaa5005f 100644 --- a/website/src/css/landing-sections/hero.scss +++ b/website/src/css/landing-sections/hero.scss @@ -37,7 +37,7 @@ .hero-ctas { display: flex; align-items: center; - animation-delay: 0.5; + animation-delay: 0.5s; } .hero-sec-wrap { @@ -158,3 +158,50 @@ width: 40vw; } } + +@media (max-width: 996px) { + .hero-title, + .hero-subtitle, + .hero-ctas { + animation: none; + } + + .hero-sec-wrap { + min-height: calc(100svh - var(--ifm-navbar-height)); + height: auto; + padding: 72px 0 48px; + } + + .hero-text { + width: 100%; + padding: 0 24px; + align-content: center; + } + + .hero-title { + width: 100%; + max-width: 680px; + font-size: clamp(2.4rem, 12vw, 4.2rem); + line-height: 1.05; + } + + .hero-subtitle { + width: 100%; + max-width: 680px; + padding-right: 0; + margin: 18px 0; + } + + .hero-ctas { + flex-wrap: wrap; + gap: 12px; + } +} + +@media (prefers-reduced-motion: reduce) { + .hero-title, + .hero-subtitle, + .hero-ctas { + animation: none; + } +} diff --git a/website/src/pages/ai-gateway.tsx b/website/src/pages/ai-gateway.tsx index eb3e6d056d3..bed576b649b 100644 --- a/website/src/pages/ai-gateway.tsx +++ b/website/src/pages/ai-gateway.tsx @@ -30,7 +30,12 @@ const ChakraTestPage: React.FC = () => ( property="og:description" content="An AI gateway manages traffic between applications and LLM providers. Apache APISIX AI Gateway provides LLM load balancing, token rate limiting, MCP support, and security for AI agents." /> + <meta + property="og:image" + content="https://static.api7.ai/uploads/2025/04/17/zdPVQ1zg_apisix-ai-gateway.png" + /> + <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:title" content="What is an AI Gateway? APISIX AI Gateway for LLMs & AI Agents" @@ -39,6 +44,10 @@ const ChakraTestPage: React.FC = () => ( name="twitter:description" content="An AI gateway manages traffic between applications and LLM providers. Apache APISIX AI Gateway provides LLM load balancing, token rate limiting, MCP support, and security for AI agents." /> + <meta + name="twitter:image" + content="https://static.api7.ai/uploads/2025/04/17/zdPVQ1zg_apisix-ai-gateway.png" + /> <script type="application/ld+json"> {JSON.stringify({ diff --git a/website/src/pages/index.tsx b/website/src/pages/index.tsx index 2b6e6318c42..97212bb9bdd 100644 --- a/website/src/pages/index.tsx +++ b/website/src/pages/index.tsx @@ -49,6 +49,10 @@ const Index: FC = () => ( <Head> <title>{translate({ id: 'homepage.meta.title', message: 'Apache APISIX - Open Source API Gateway & AI Gateway' })}</title> <link rel="canonical" href="https://apisix.apache.org/" /> + <meta + name="description" + content="Apache APISIX is a dynamic, high-performance, open-source API gateway and AI gateway. Features include load balancing, authentication, rate limiting, AI proxying, LLM load balancing, and 100+ plugins." + /> <meta property="og:title" content="Apache APISIX - Open Source API Gateway & AI Gateway" diff --git a/website/src/theme/NotFound/index.tsx b/website/src/theme/NotFound/index.tsx index f8c6490bf6d..c8a513b32b1 100644 --- a/website/src/theme/NotFound/index.tsx +++ b/website/src/theme/NotFound/index.tsx @@ -2,6 +2,7 @@ import type { FC } from 'react'; import React from 'react'; import Layout from '@theme/Layout'; +import Head from '@docusaurus/Head'; import { translate } from '@docusaurus/Translate'; import Link from '@docusaurus/Link'; import style from './styles.module.scss'; @@ -14,6 +15,9 @@ const NotFound: FC = () => ( message: 'Page Not Found', })} > + <Head> + <meta name="robots" content="noindex,follow" /> + </Head> <main className={style.container}> <section> <Fitty tagName="h1" contentEditable>404</Fitty> @@ -31,12 +35,16 @@ const NotFound: FC = () => ( . </p> <p> - You can also return to + You can also open the {' '} - <Link href="/"> - the home page - </Link> - . Or, return to + <Link to="/">home page</Link> + , + {' '} + <Link to="/docs/">documentation</Link> + , + {' '} + <Link to="/blog/">blog</Link> + , or {' '} <a role="button" @@ -45,7 +53,7 @@ const NotFound: FC = () => ( window?.history.back(); }} > - the source page + return to the source page </a> . </p> diff --git a/website/static/robots.txt b/website/static/robots.txt index 2f71ab386d7..bb355ad7d64 100644 --- a/website/static/robots.txt +++ b/website/static/robots.txt @@ -18,6 +18,7 @@ Disallow: /docs/apisix/3.12/ Disallow: /docs/apisix/3.13/ Disallow: /docs/apisix/3.14/ Disallow: /docs/apisix/3.15/ +Disallow: /docs/apisix/3.16/ Disallow: /docs/apisix/next/ Disallow: /docs/ingress-controller/3.10/ Disallow: /docs/ingress-controller/3.11/ @@ -25,6 +26,7 @@ Disallow: /docs/ingress-controller/3.12/ Disallow: /docs/ingress-controller/3.13/ Disallow: /docs/ingress-controller/3.14/ Disallow: /docs/ingress-controller/3.15/ +Disallow: /docs/ingress-controller/3.16/ Disallow: /docs/ingress-controller/next/ Disallow: /docs/helm-chart/3.10/ Disallow: /docs/helm-chart/3.11/ @@ -32,6 +34,7 @@ Disallow: /docs/helm-chart/3.12/ Disallow: /docs/helm-chart/3.13/ Disallow: /docs/helm-chart/3.14/ Disallow: /docs/helm-chart/3.15/ +Disallow: /docs/helm-chart/3.16/ Disallow: /docs/helm-chart/next/ Disallow: /docs/docker/3.10/ Disallow: /docs/docker/3.11/ @@ -39,6 +42,7 @@ Disallow: /docs/docker/3.12/ Disallow: /docs/docker/3.13/ Disallow: /docs/docker/3.14/ Disallow: /docs/docker/3.15/ +Disallow: /docs/docker/3.16/ Disallow: /docs/docker/next/ Disallow: /docs/java-plugin-runner/3.10/ Disallow: /docs/java-plugin-runner/3.11/ @@ -46,6 +50,7 @@ Disallow: /docs/java-plugin-runner/3.12/ Disallow: /docs/java-plugin-runner/3.13/ Disallow: /docs/java-plugin-runner/3.14/ Disallow: /docs/java-plugin-runner/3.15/ +Disallow: /docs/java-plugin-runner/3.16/ Disallow: /docs/java-plugin-runner/next/ Disallow: /docs/go-plugin-runner/3.10/ Disallow: /docs/go-plugin-runner/3.11/ @@ -53,6 +58,7 @@ Disallow: /docs/go-plugin-runner/3.12/ Disallow: /docs/go-plugin-runner/3.13/ Disallow: /docs/go-plugin-runner/3.14/ Disallow: /docs/go-plugin-runner/3.15/ +Disallow: /docs/go-plugin-runner/3.16/ Disallow: /docs/go-plugin-runner/next/ Disallow: /docs/python-plugin-runner/3.10/ Disallow: /docs/python-plugin-runner/3.11/ @@ -60,6 +66,7 @@ Disallow: /docs/python-plugin-runner/3.12/ Disallow: /docs/python-plugin-runner/3.13/ Disallow: /docs/python-plugin-runner/3.14/ Disallow: /docs/python-plugin-runner/3.15/ +Disallow: /docs/python-plugin-runner/3.16/ Disallow: /docs/python-plugin-runner/next/ # Chinese equivalents @@ -69,6 +76,7 @@ Disallow: /zh/docs/apisix/3.12/ Disallow: /zh/docs/apisix/3.13/ Disallow: /zh/docs/apisix/3.14/ Disallow: /zh/docs/apisix/3.15/ +Disallow: /zh/docs/apisix/3.16/ Disallow: /zh/docs/apisix/next/ Disallow: /zh/docs/ingress-controller/3.10/ Disallow: /zh/docs/ingress-controller/3.11/ @@ -76,6 +84,7 @@ Disallow: /zh/docs/ingress-controller/3.12/ Disallow: /zh/docs/ingress-controller/3.13/ Disallow: /zh/docs/ingress-controller/3.14/ Disallow: /zh/docs/ingress-controller/3.15/ +Disallow: /zh/docs/ingress-controller/3.16/ Disallow: /zh/docs/ingress-controller/next/ Disallow: /zh/docs/helm-chart/3.10/ Disallow: /zh/docs/helm-chart/3.11/ @@ -83,6 +92,7 @@ Disallow: /zh/docs/helm-chart/3.12/ Disallow: /zh/docs/helm-chart/3.13/ Disallow: /zh/docs/helm-chart/3.14/ Disallow: /zh/docs/helm-chart/3.15/ +Disallow: /zh/docs/helm-chart/3.16/ Disallow: /zh/docs/helm-chart/next/ Disallow: /zh/docs/docker/3.10/ Disallow: /zh/docs/docker/3.11/ @@ -90,6 +100,7 @@ Disallow: /zh/docs/docker/3.12/ Disallow: /zh/docs/docker/3.13/ Disallow: /zh/docs/docker/3.14/ Disallow: /zh/docs/docker/3.15/ +Disallow: /zh/docs/docker/3.16/ Disallow: /zh/docs/docker/next/ Disallow: /zh/docs/java-plugin-runner/3.10/ Disallow: /zh/docs/java-plugin-runner/3.11/ @@ -97,6 +108,7 @@ Disallow: /zh/docs/java-plugin-runner/3.12/ Disallow: /zh/docs/java-plugin-runner/3.13/ Disallow: /zh/docs/java-plugin-runner/3.14/ Disallow: /zh/docs/java-plugin-runner/3.15/ +Disallow: /zh/docs/java-plugin-runner/3.16/ Disallow: /zh/docs/java-plugin-runner/next/ Disallow: /zh/docs/go-plugin-runner/3.10/ Disallow: /zh/docs/go-plugin-runner/3.11/ @@ -104,6 +116,7 @@ Disallow: /zh/docs/go-plugin-runner/3.12/ Disallow: /zh/docs/go-plugin-runner/3.13/ Disallow: /zh/docs/go-plugin-runner/3.14/ Disallow: /zh/docs/go-plugin-runner/3.15/ +Disallow: /zh/docs/go-plugin-runner/3.16/ Disallow: /zh/docs/go-plugin-runner/next/ Disallow: /zh/docs/python-plugin-runner/3.10/ Disallow: /zh/docs/python-plugin-runner/3.11/ @@ -111,6 +124,7 @@ Disallow: /zh/docs/python-plugin-runner/3.12/ Disallow: /zh/docs/python-plugin-runner/3.13/ Disallow: /zh/docs/python-plugin-runner/3.14/ Disallow: /zh/docs/python-plugin-runner/3.15/ +Disallow: /zh/docs/python-plugin-runner/3.16/ Disallow: /zh/docs/python-plugin-runner/next/ Sitemap: https://apisix.apache.org/sitemap.xml
