SEO cleanup: sitemap, 404 metadata, coming-soon heading - #133
Merged
Conversation
Three small fixes found while validating the live site. Sitemap advertised /_not-found/. collectPages() emits a URL for any directory holding an index.html and filters only top-level names in an explicit deny-list. With trailingSlash the export writes out/_not-found/index.html, and _not-found was not in the list. documentdb#123 fixed exactly this class for 404 but only added that one name. The page also serves noindex, so the sitemap was submitting a URL that tells crawlers not to index it. Added _not-found to the exclusion set. 404 page emitted two conflicting robots tags. not-found.tsx exported no metadata, so it inherited the root layout's, which hardcodes index/follow in metadataService - and Next.js separately injects noindex for the not-found route. It also carried the homepage title byte for byte. Added a metadata export with a distinct title and index: false. /docs/architecture had no heading element at all - not just no h1, zero h1-h6. The coming-soon layout renders the graphic plus placeholder prose, and the markdown carries no heading, while the sidebar section label is deliberately a <p> because "the article's h1 comes from the markdown content". That contract is unmet for coming-soon pages, so the h1 now comes from the frontmatter title, guarded in case a future coming-soon page does start with a markdown heading. The docs index also showed the Architecture card with no marker, styled identically to the six finished ones. Marked it the same way the Kubernetes Operator card marks preview status, via a title suffix. Fixes documentdb#129
The exclusion list was growing one framework route at a time. documentdb#123 added 404 after it appeared in the sitemap; this branch added _not-found for the same reason; and the versioned-docs work in progress adds a third hand-written skip for the archived version directories. Each is the same rule discovered again: do not advertise a page that tells crawlers not to index it. That property is readable from the page itself, so collectPages now reads each index.html and skips the ones carrying a noindex robots meta. The name list keeps only the directories that hold no pages at all - _next, deb, rpm, images - where it is a traversal concern rather than an indexing decision. The tag is matched in either attribute order and tolerates content lists such as "noindex,nofollow", since Next.js and hand-written metadata do not agree on either. The final log line now reports how many pages were skipped, so a filter that starts matching too much is visible in the build output instead of silently shrinking the sitemap. Verified against a synthetic export carrying an indexable root, /docs, /docs/versions, /packages and /samples, plus three noindex pages written in three different tag forms and an excluded _next directory: five URLs emitted, three skipped, and out/404.html left alone as the file it is. Note that the archived-version case is now covered by this rule, so the docs/versions skip on the versioned-docs branch can go when it lands.
guanzhousongmicrosoft
approved these changes
Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #129. Three independent fixes, each small.
1. Sitemap advertised
/_not-found/collectPages()emits a URL for any directory containing anindex.htmland filters only top-level names in an explicit deny-list. WithtrailingSlash: truethe export writesout/_not-found/index.html, and_not-foundwas not on the list.#123 (
9505e9c) fixed exactly this class for404, but only added that one name. Note the two are not symmetric:404exists in both forms (/404.htmland/404/both 200) while_not-foundonly exists as a directory.This matters more than a stray URL:
/_not-found/serves<meta name="robots" content="noindex">, so the sitemap was actively submitting a URL that tells crawlers not to index it — the Search Console "submitted URL marked noindex" warning class.Verified by running the real script against a synthetic export containing
_not-found/,404/,404.html,docs/architecture/, andpackages/:Both not-found forms are excluded and
/packages/still survives, which is the regression #123 was guarding.Update: filtering on
noindexinstead of on the nameRevised after review. The name list was growing one framework route at a time — #123 added
404, this branch added_not-found, and the versioned-docs work in progress adds a third hand-written skip for the archived version directories. Each is the same rule rediscovered: do not advertise a page that tells crawlers not to index it.collectPages()now reads eachindex.htmland skips the ones carrying anoindexrobots meta. The name list keeps only the directories holding no pages at all —_next,deb,rpm,images— where it is a traversal concern rather than an indexing decision. The tag is matched in either attribute order and toleratesnoindex,nofollow, since Next.js and hand-written metadata do not agree on either form. The final log line now reports how many pages were skipped, so a filter that starts matching too much shows up in the build output instead of silently shrinking the sitemap.Re-verified against a synthetic export — indexable root,
/docs,/docs/versions,/packages,/samples, three noindex pages written three different ways, and an excluded_next:out/404.htmlis left alone, being a file rather than a directory with anindex.html. Note this also covers the archived-version case, so thedocs/versionsskip on the versioned-docs branch can go when that lands.2. The 404 page emitted two conflicting
robotstagsapp/not-found.tsxexported nometadata, so it inherited the root layout's — andmetadataService.ts:58-61hardcodesindex: true, follow: true. Next.js separately injectsnoindexfor the not-found route, hence both tags. The page also carried the homepage title byte for byte (DocumentDB - Open Source Document Database).Crawlers generally honour the most restrictive directive, so the practical impact was low; this is mostly about not shipping a self-contradicting page with a misleading title.
3.
/docs/architectureshipped with no heading elementZero
h1-h6, not just noh1. Not a hydration artifact —output: "export", and the placeholder prose is present in the served HTML.The cause is a contract that the
coming-soonlayout does not meet. The sidebar section label is deliberately a<p>, with the comment "Not a heading: the article's h1 comes from the markdown content" — butarchitecture/index.mdis frontmatter plus one placeholder paragraph, no markdown heading. The h1 now comes from the frontmatter title (Architecture under the hood), guarded with a check so a future coming-soon page that does start with#will not end up with two.The card on
/docswas also unmarked — class-for-class identical to the six finished sections. Marked it via a title suffix, the same mechanism the Kubernetes Operator card already uses for(Preview).Left alone deliberately: the issue also floats excluding
coming-soonpages from the sitemap. With a real h1 and a useful description the page is reasonable to index, so I would rather not hide it — happy to add it if maintainers disagree.Not addressed here
The issue mentions in passing that the navbar logo renders
loading="lazy"above the fold. Since the image isunoptimized, addingpriorityonly buys a preload hint — different concern, so I left it for a separate change.Validation
npm is blocked on this machine, so lint and the Next.js build are left to CI. The sitemap script is dependency-free and was executed directly, as shown above.
Review notes
Two things a reviewer should weigh, neither of which changed the diff:
The
(Coming soon)marker and the page it describes live in different repos. The card title is in this repo'sarticles/content.yml, butarticles/architecture/index.mdand itslayout: coming-soonfrontmatter come fromdocumentdb/docs. If the architecture content is filled in upstream, nothing here notices and the suffix goes stale. Deriving the marker from the article's frontmatter would be self-maintaining, butgetArticleContent()only readscontent.yml, so that is a larger change than this fix warrants. Flagging it as a known trade-off.The 404 page may still emit two
robotstags. Next.js injects its ownnoindexfor the not-found route, and whether an explicitmetadataexport replaces that tag or sits alongside it was not verified locally (npm is blocked on this machine, so no local build). Either way the substantive defect is fixed: the page previously emittednoindexandindex, follow— a contradiction — and now emits at worstnoindexplusnoindex, follow, which agree. Worth a quick check of the deployed HTML after merge if a single tag is wanted.