Architecture & Build Pipeline

Luma Docs orchestrates a deterministic multi-step content pipeline. Each step produces an artifact that the next can consume — keeping builds reproducible and easy to debug.

Pipeline Overview

versions → routes → css → search → sitemap → ssg
StepScriptOutputPurpose
Versionsgenerate:versionssrc/generated-versions.tsEnumerates archived version labels for UI + routing + search filtering
Routesgenerate:routessrc/generated-routes.tsx + .meta.tsDiscovers MDX pages, extracts frontmatter, attaches version + meta
CSSbuild:csssrc/components/public/index.cssTailwind + typography utilities compiled once
Searchgenerate:search-indexsrc/generated-search-index.tsStatic JSON-like index of headings + snippets + version
Sitemapgenerate:sitemapdist/sitemap.xmlSEO discovery + can be extended for priority/archived handling
SSGvite-react-ssg builddist/**/*.htmlPre-rendered HTML + hydration entry points

All of this is wrapped by npm run build and by the dev script (which runs incremental rebuilds as needed).

Why Separate Steps?

  • Isolation: Fail fast in the earliest script that breaks (e.g. malformed frontmatter).
  • Cacheability: Intermediate artifacts let future tooling (analytics, lint, link checkers) run without parsing raw MDX again.
  • Determinism: Each stage has a single responsibility, simplifying reasoning about regressions.

Route Generation Details

The route generator:

  1. Scans content/pages/ for current docs.
  2. Scans content/versions/<label>/ for archived snapshots.
  3. Normalizes slugs (/foo/bar/) and paths (/foo/bar).
  4. Emits React route components (lazy loaded) plus a separate lightweight metadata file.
  5. Attaches version for downstream consumers (search, badges, switcher, SEO tweaks).

Frontmatter Extraction

Frontmatter is parsed and validated (see validate:frontmatter). Only whitelisted keys make it into meta. This keeps the runtime lean and prevents accidental leakage of experimental flags.

Search Index Structure

Each entry contains:

// Shape of each search index record (illustrative only)
// (Removed local interface declaration to satisfy lint rule)
// {
//   path: string;
//   pageTitle: string;
//   heading: string;
//   headingId?: string;
//   content: string;
//   version?: string;
// }

No network calls, no 3rd-party service — pure static asset.

Version Awareness

Version scoping is structural, not dynamic rewriting. This means your old snapshots are immutable references of history — a huge win for reproducibility.

Extensibility Points

NeedHook
Add lint for broken internal linksNew script after generate:routes
Exclude very old versions from searchFilter in generate-search-index.js
Add RSS or Atom feedAfter sitemap (shares route meta)
Pre-compute Algolia indexReplace local search stage with remote push

Debugging Tips

npm run generate:routes -- --debug  # (hypothetical future flag)
node src/tools/generate-search-index.js > /tmp/index.json

Because artifacts are plain TS/JS files, you can open them directly to inspect structure.

Future Ideas

  • Parallelization (routes + css) where I/O bound
  • Build manifest for plugin ecosystem
  • Incremental sitemap updates

The pipeline is intentionally minimal but explicit — easy to extend without becoming a black box.