Migrate documentation to Astro Starlight - #1686
Conversation
Replaces the VuePress 1.x docs site with Astro 6 + Starlight 0.38. The previous `docs/.vuepress/` configuration stays in place for now since it's no longer wired into the build pipeline -- a separate cleanup will remove it. Migration highlights: - `docs/astro.config.mjs` configures Starlight with the Rapide theme, Expressive Code (line numbers + collapsible sections), a sitemap, and `starlight-page-actions` (Copy Markdown + Open in ChatGPT / Claude buttons on every page). - Guide pages, the homepage, and the 404 move from the legacy `docs/guide/*.md` + `docs/index.md` tree into `src/content/docs/` and are tracked in git. They were run through the VuePress preprocessor once at migration time, so they now contain Starlight-native asides (`:::tip[Title]`), HTML `<details>` accordions, fully resolved `@[code]` includes, and rewritten links with the `/docs` base prefix. - The TypeDoc-generated API reference is the only path that still passes through `scripts/generate-content.mjs` -- it normalizes TypeDoc's link forms and badge tokens. - The Netlify `_redirects` file (legacy `.html` URLs → clean URLs) is also generated by `generate-content.mjs`, now derived from the tracked content under `src/content/docs/guide/`. - Custom Starlight component overrides for `Head`, `Header`, `Footer`, and `ThemeSelect` reproduce the Handsontable docs look-and-feel (two-row header, sun/moon theme toggle, spreadsheet-style footer). - Root build orchestration (`docs:build` script chain, Netlify build command, GitHub Actions `build-docs.yml`) updated to invoke the Astro build via `npm ci && npm run build` inside `docs/`. Legacy `docs/guide/`, `docs/index.md`, and `docs/api-ref-readme.md` are deleted -- their content lives under `src/content/docs/` now.
Introduces four governance files under `docs/` so contributors -- and AI coding agents -- have a clear, self-contained reference for how to work on the docs site: - `docs/CLAUDE.md`: authoring standards. Diátaxis page-type taxonomy with folder-to-type mapping, voice and style rules with a banned-word list, four page-structure templates (tutorial / how-to / reference / explanation), example-data domain conventions, code-example rules (language tags, `licenseKey: 'gpl-v3'`, builder methods), the frontmatter schema with permanent 8-char IDs and the `| HyperFormula` metaTitle suffix, link conventions, the Excel / Google Sheets trademark notice text, the sidebar registration step, the Starlight-native asides / live-runner HTML pattern, and a PR checklist. - `docs/AGENTS.md`: symlink to `CLAUDE.md` so both naming conventions resolve to the same file. - `docs/README-EDITING.md`: practical reference -- frontmatter long-form, Starlight aside examples, the live-runner HTML pattern with file layout, line highlighting in code blocks, and sidebar registration. - `docs/README-DEPLOYMENT.md`: deployment reference -- Netlify build command, the `docs:build` pipeline (`bundle-all` → `typedoc:build-api` → `npm ci && npm run build`), GitHub Actions CI verification, and the auto-generated `_redirects` map.
The `starlight-page-actions` plugin defaults to rendering its action row directly under the page heading. Match the Handsontable docs UI by moving the actions (Copy Markdown, Open in ChatGPT, Open in Claude) into the right-hand sidebar, below the "On this page" table of contents. Adds two Starlight component overrides: - `PageTitle.astro`: renders only the default page title and drops the plugin's button row. The plugin's override is suppressed because user- configured overrides win over plugin-supplied ones in Starlight. - `PageSidebar.astro`: renders the default TOC, then appends a flat action list styled to match the right-sidebar typography. The Copy Markdown handler reuses the plugin's `.md` companion routes and shows a transient checkmark on success.
✅ Deploy Preview for hyperformula-dev-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
CI flagged two issues on PR #1686: - The `build-docs` GitHub Actions job and the Netlify deploy preview both failed because Astro 6 requires Node >=22.12.0, but every Node pin in the docs setup specified 20. Bump `.nvmrc`, the docs `engines.node` constraint, the `build-docs.yml` job matrix, the Netlify `NODE_VERSION`, and the "Node 20" mentions in the README / CLAUDE.md / README-DEPLOYMENT to 22 (22.12 for the engines pin). - CodeQL flagged `cleanTitleText()` in `vuepress-preprocessor.mjs` for incomplete multi-character sanitization (`js/incomplete-multi-character-sanitization`). A single pass of `/<[^>]+>/g` could leave a `<script>` substring behind for inputs like `<sc<script>ript>`. Iterate the strip to a fixed point so nested tags collapse fully. The downstream consumer (Starlight rendering a YAML `title:`) already escapes HTML, so this is defence-in-depth, but the warning is correct in principle.
Performance comparison of head (61190e7) vs base (8bfa558) |
The Netlify deploy preview for #1686 kept failing with "Node.js v18.20.8 is not supported by Astro" even after setting NODE_VERSION = "22" in netlify.toml's [build.environment]. The deploy log showed Netlify resolving Node from the root .nvmrc ("v18") rather than honoring the netlify.toml env var. Bump .nvmrc to 22 so both sources agree. The HyperFormula library is already exercised on Node 20/22/24 by .github/workflows/build.yml, so bumping the local-dev default to 22 is consistent with what CI already tests.
Astro builds the site with `base: '/docs'`, so generated HTML references `/docs/_astro/*`, `/docs/guide/*`, etc. In production the canonical URL `hyperformula.handsontable.com/docs/` is served by a reverse proxy that strips the `/docs` prefix before forwarding to the Netlify project, so the prefix in the HTML resolves to the right files. Netlify deploy previews (and the netlify.app subdomain in general) don't sit behind that proxy, so `/docs/`-prefixed paths 404 — only the home page rendered, and even then without styles or images because every `/docs/_astro/*` URL came back as a 404. Add a wildcard rewrite to netlify.toml so the preview mimics the production proxy: any `/docs/<path>` request is served from `<path>` in the publish directory. The Astro-generated `_redirects` file is processed first (so the legacy `.html` → clean URL redirects still match), then this catch-all rewrites everything else.
The version pill in the docs header rendered as "v0.0.0" on the Netlify deploy preview even though the same code returned the correct "3.3.0" locally. The cause was the brittle `../../..` arithmetic used to find the library root: in some build environments (apparently Astro's build container on Netlify), `import.meta.url` resolves through a location that's one directory deeper than expected, so three parent hops landed inside `docs/` instead of at the repo root. That made the fallback read `docs/package.json` (version `0.0.0`) instead of the library's `package.json`. Replace the path arithmetic with an upward walk that stops at the first `package.json` whose `name` is `hyperformula`. This is robust to any build-cache layout. While here, also fall back gracefully when the UMD bundle exists but is missing individual fields.
|
@sequba @sl01k , this is still a draft, but it's getting close. Here's the latest DP if you want to have a look: |
The toolbar's horizontal divider was constructed from `border-top` on each `.hf-nav__link` element, so it only rendered where the framed nav tabs sat. To the left of the first tab and to the right of the Support dropdown, the line broke off and left visible gaps. Mirror Handsontable's `.header-row-2::before` pattern: add a single full-viewport `::before` pseudo-element to `.hf-header__row--nav` so a continuous 1px line stretches edge-to-edge. The per-tab top borders sit at the same Y-coordinate and overlap the pseudo-element where tabs exist; the pseudo-element bridges the gaps elsewhere. The active-tab brand-blue frame and z-index stacking are unchanged.
Brings in `00e5c730a` "Clean up in-repo dev docs (HF-65) (#1682)" which adds root-level `DEV_DOCS.md`, `AGENTS.md`, `.cursor/rules/main.mdc`, and re-points root `CLAUDE.md` / `CONTRIBUTING.md` as symlinks. Those files live at the repo root and govern library development, separate from the docs-site governance files this PR adds under `docs/` (`docs/CLAUDE.md`, `docs/AGENTS.md`, `docs/README-EDITING.md`, `docs/README-DEPLOYMENT.md`). Git's rename detection auto-applied develop's edits to `docs/guide/building.md` to the migrated location at `docs/src/content/docs/guide/building.md` — no conflicts.
…border The continuous `::before` divider line was already in place, but two layout issues remained: 1. The per-tab `border-top` sat ~0.5rem below `::before` because `.hf-header__row` (the shared row class) applies `padding: 0.5rem 1rem` and `align-items: center` to every row. That offset rendered as a doubled line where the tabs were. 2. Inside `header.header`, Starlight's `padding-block` reserved ~0.75rem of dead space below `.hf-header`, so the per-tab vertical borders and hover backgrounds stopped short of the visible `border-bottom: 1px solid hairline-shade` boundary. Three targeted overrides — modeled on Handsontable's `.header-row-2` layout: - `.hf-header__row--nav` drops vertical padding, sets `align-items: stretch`, `gap: 0`, and `min-height: 0`. Nav links now sit flush against the row's top so their `border-top` overlaps `::before` perfectly (single line). - `.hf-header` changes `grid-template-rows` from `auto auto` to `auto 1fr` so row 2 absorbs the remaining vertical track height rather than leaving it empty. - `header.header` overrides Starlight's `padding-bottom` to `0` so `.hf-header__row--nav` reaches the header's actual bottom border. The per-tab vertical lines and hover backgrounds now extend the full height of the toolbar, matching Handsontable's design.
|
@qunabu @sequba , this is ready for review now |
Starlight constructs the "Edit this page" URL by appending `entry.filePath` (the source file path relative to the Astro project root, which is `docs/`) to `editLink.baseUrl`. With the previous value ending in `docs/content/`, the resulting URL would have been `.../edit/develop/docs/content/src/content/docs/guide/<slug>.md` — a path that does not exist in the repository. The `docs/content/` suffix was carried over from Handsontable's `astro.config.mjs`, where guides actually live at `docs/content/` via a symlink. In HyperFormula the sources live directly at `docs/src/content/docs/`, so the base needs to point at `docs/`. No "Edit on GitHub" link is currently rendered (my Footer / PageTitle / PageSidebar overrides don't include one, and `starlight-page-actions` doesn't expose an edit action), so the misconfigured URL was latent. This fix removes the trap before anyone adds the button back.
Brings in two content-only commits that landed on develop after the last sync: - 0e047ee docs: fix SSR section framing in React integration guide (#1688) - 79f2f15 docs: rewrite Vue integration guide around markRaw pattern (#1689) Both touch files we migrated from `docs/guide/` to `docs/src/content/docs/guide/`. Git's rename detection auto-applied the develop-side edits to the new locations — no conflicts. GitHub had flagged the PR as CONFLICTING because its mergeability check hadn't recomputed since develop's last push; pushing this merge clears that flag.
Co-authored-by: GreenFlux <GreenFlux@users.noreply.github.com>
Caught by Cursor Bugbot on PR #1686. `astro.config.mjs` gates the Google Tag Manager snippet on `process.env.BUILD_MODE === 'production'`, but nothing in the Netlify config or the GitHub Actions docs-build workflow was setting the variable — so the production deploy of the docs site would silently ship without GTM, dropping analytics that the previous VuePress site had always loaded. Setting `BUILD_MODE = "production"` under `[context.production.environment]` is the right Netlify-native pattern: it only applies to deploys from the production branch, leaving PR deploy previews and branch deploys with `BUILD_MODE` unset so analytics doesn't fire on non-canonical URLs.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0509e26. Configure here.
|
@sequba ready for review |
Brings in one content-only commit that landed on develop: - d4195b5 HF-238 - Review "Integration with Angular" guide and demo (#1691) It touches `docs/guide/integration-with-angular.md`, which this PR migrated to `docs/src/content/docs/guide/integration-with-angular.md`. Git's rename detection auto-applied the develop-side edits to the new location — no conflicts. Pushes the merge so GitHub's `mergeable: CONFLICTING` flag recomputes.
Brings in two content commits that landed on develop: - 72205bd docs(api): fix getAllSheetsSerialized/getRangeSerialized JSDoc for number cells (HF-219) (#1693) — library JSDoc edit; API ref regens from source, no docs-side conflict. - 8bfa558 docs(guide): named ranges in formulas + fix limitations pointer (HF-222) (#1695) — added ~40 lines to two guide pages that we migrated. Auto-merge couldn't reconcile these because git's rename detection was defeated by the size of the change (named-expressions) and by our base-prefixed link rewrites (known-limitations). Manual resolutions: - `docs/guide/named-expressions.md`: confirmed the delete (legacy path). - `docs/src/content/docs/guide/named-expressions.md`: appended develop's new "Using named ranges in formulas" section before "## Available methods", verbatim except for using the same link form our tree uses. - `docs/src/content/docs/guide/known-limitations.md`: took develop's replacement bullet in place of the older "no data validation against named ranges" line, then rewrote its links from legacy `named-expressions.md#...` / `custom-functions.md#...` to our base-prefixed `/docs/guide/named-expressions#...` / `/docs/guide/custom-functions#...` form. Local `npm run build` produces 214 pages, no errors.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1686 +/- ##
========================================
Coverage 97.16% 97.16%
========================================
Files 176 176
Lines 15322 15322
Branches 3387 3387
========================================
Hits 14887 14887
Misses 435 435 🚀 New features to boost your workflow:
|
…guide (HF-154) (#1703) ### Context HF-154 — make the HyperFormula docs friendlier to coding agents and LLMs. On top of the existing VuePress portal this adds: - **Per-page `.md` companions** — every doc page is also served as clean, VuePress-stripped Markdown (a build-time `md-companions` plugin), plus an aggregate `llms-full.txt`. Both are also mirrored to the site root so `/llms.txt` and `/llms-full.txt` resolve on GitHub Pages (prod) and the Netlify preview. - **`llms.txt`** — a top-level index pointing agents at the Markdown sources. - **View-as-Markdown link** (`ViewMarkdownLink.vue`) — links to the page's `.md` source so an agent can open and read it directly. - **Coding-agent setup guide** (`docs/guide/setup-coding-agent.md`) plus a `CodingAgentWizard.vue` helper. - **`context7.json`** so agent doc-access tooling (Context7 / GitMCP) can discover the sources. The Markdown stripper (`md-companions/strip.js`) is the fidelity-critical piece: it turns VuePress-flavoured Markdown (`:::` containers, `<script>`/Vue components, `[[toc]]`, `{{ }}` bindings, Vue-bound `<a :href>`/`<img :src>`, live `:::example` demos, nested code fences) into clean Markdown. ### How did you test your changes? - Manually verified the stripper on representative inputs (tip/warning containers, nested code fences, Vue-bound `<a :href>`/`<img :src>`, `[[toc]]`, `<script>`/component removal, `:::example` demos) — confirming code fences, **including Vue-shaped samples inside container bodies**, survive verbatim while prose is cleaned. - Sanity-checked the full corpus against the Netlify deploy-preview (`llms-full.txt` populated, per-page `.md` clean, no leaked components). - `npm run lint` clean. ### Note on test coverage The `md-companions` stripper currently has **no automated regression tests**. The earlier `test/docs/*.spec.js` suites (strip / corpus / generated) were removed in `363a5e2` — the public repo carries smoke tests only (`test/README.md`), and this is build-time docs tooling, not shipped `src/` code, so a stripper regression degrades the generated `.md`/`llms.txt`, not engine/product behaviour. The working safety net is Cursor Bugbot + the Netlify deploy-preview + review. That said, this is the **second fidelity bug** in the stripper (after the Vue-bound link/image fix), and the removed suites did **not** cover the case that regressed here — Vue markup inside a code fence sitting **inside** a container. If we want coverage, the right home is the private `hyperformula-tests` repo (restore the removed cases + this container-fence intersection). ### Types of changes - [x] New feature or improvement (a non-breaking change that adds functionality) - [x] Change to the documentation ### Related issues: 1. HF-154 ### Checklist: - [x] I have reviewed the guidelines about Contributing to HyperFormula and I confirm that my code follows the code style of this project. - [x] I described my changes in the CHANGELOG.md file. ### Notes - Supersedes #1696 (moved to an upstream branch so CI can access the private `hyperformula-tests` repo). Current `develop` is merged in. - The docs-portal Astro migration (#1686) is a separate track. If it lands first it supersedes this VuePress plumbing (the `md-companions` plugin and `.vue` components are VuePress-specific); the agent-friendly *outputs* (`.md` companions, `llms.txt`, setup guide) would need re-homing in Astro. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Docs-site and build-time tooling only; no changes to `src/` engine behavior. Main operational risk is stripper fidelity regressions in generated `.md`/`llms-full.txt` (currently manual/preview validation, no automated stripper tests in this PR). > > **Overview** > Adds **LLM/agent-friendly documentation outputs** on top of the existing VuePress docs build, without changing the spreadsheet engine. > > A new **`md-companions` VuePress plugin** runs at build time: it strips VuePress-only syntax (`:::example` demos, Vue components, `[[toc]]`, bound `<a :href>` / `<img :src>`, etc.) via **`strip.js`**, resolves injected `{{ $page.* }}` values, rebases root-relative links for the docs `base`, and writes a **clean `.md` companion** beside each HTML page plus an aggregated **`llms-full.txt`** (with absolute links in the corpus). **`context7.json`** points Context7-style tooling at the `docs` folder with project-specific rules. > > The **local theme** injects **`ViewMarkdownLink`** (“View as Markdown”) on every page; **`setup-coding-agent.md`** and **`CodingAgentWizard`** document Claude Code skills, Cursor/Copilot rules, MCP (GitMCP / Context7), and copyable snippets (via **`clipboard.js`**). Sidebar and **`DEV_DOCS.md`** / **`docs/README.md`** are updated accordingly. **Netlify** build uses **Node 22**; **`.eslintrc.js`** gets a minor override-array syntax fix. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f2e95fc. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY --> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Kuba Sekowski <jakub.sekowski@handsontable.com> Co-authored-by: Kuba Sekowski <kuba.sekowski.dev@gmail.com> Co-authored-by: Kuba Sekowski <sequba@gmail.com>

Status
Draft. Asking for an early structural look — happy to split this into separate PRs if reviewers prefer:
src/content/docs/)CLAUDE.md,README-EDITING.md,README-DEPLOYMENT.md)starlight-page-actionsfeature + the right-sidebar UI placementCurrently three logical commits, easiest to review per-commit:
e227a2479— Migrate documentation from VuePress to Astro Starlightec5c7d126— Add documentation authoring standards and editing/deployment guides510fb6d5a— Move page action buttons into the right sidebarSummary
Replaces the VuePress 1.x docs site with Astro 6 + Starlight 0.38. The previous
docs/.vuepress/configuration stays in place for now since it's no longer wired into the build pipeline — a separate cleanup will remove it.Site structure
docs/src/content/docs/and are tracked in git (no longer regenerated on every build).docs/src/content/docs/api/is the only path still processed byscripts/generate-content.mjs(it normalizes TypeDoc output)._redirectsmap preserves the legacy/docs/guide/<slug>.html→ clean URLs and is auto-generated.Custom Starlight component overrides
Head(Inter font, example-runner client script),Header(two-row HT-style nav with logo + version pill, search, GitHub stars, primary nav, support dropdown),Footer(link grid + social row),ThemeSelect(sun/moon toggle),PageTitle+PageSidebar(moves the Copy Markdown / Open in ChatGPT / Open in Claude buttons into the right sidebar under "On this page", matching the HT docs layout).Plugins
starlight-theme-rapide(typography + chrome) andstarlight-page-actions(page-action buttons + auto-generated.mdcompanions next to each.html).Authoring governance
docs/CLAUDE.md(symlinked fromdocs/AGENTS.md) — Diátaxis-based authoring rules, frontmatter schema with permanent 8-char IDs, code-example conventions (licenseKey: 'gpl-v3', builder methods), Excel/Google Sheets trademark callouts, and a PR checklist.docs/README-EDITING.md— practical reference for Starlight-native asides, the live-runner HTML pattern, and sidebar registration.docs/README-DEPLOYMENT.md— Netlify build chain,docs:buildpipeline, GitHub Actions CI verification.Build wiring
netlify.tomlrunsnpm run docs:buildfrom the repo root and publishesdocs/dist..github/workflows/build-docs.ymlruns the same command on PRs and pushes tomaster,develop,release/**.docs:buildscript chains:bundle-all→typedoc:build-api→cd docs && npm ci && npm run build.Test plan
::: exampleblock (e.g./docs/guide/basic-usage), and an API ref page (e.g./docs/api/classes/hyperformula).mdcompanion, Open in ChatGPT / Open in Claude prefill a prompt.htmlURL redirects in_redirectsresolve (e.g./docs/guide/basic-usage.html→/docs/guide/basic-usage)npm run docs:buildfrom the repo root completes without errorsKnown follow-ups (not in this PR)
docs/.vuepress/directoryCLAUDE.md§9Note
Medium Risk
Large public-docs and deployment-path change (publish
docs/dist, URL shape, redirects) with no core library logic, but broken builds or redirects would affect production SEO and inbound links.Overview
Replaces the VuePress 1.x documentation site with Astro 6 + Starlight, served under
/docsonhyperformula.handsontable.com. Root anddocs/Node versions move to 22; the root.eslintignorenow excludes the wholedocs/package instead of onlydocs/examples/.Content and build: Guide pages, homepage, and 404 are authored in
docs/src/content/docs/(tracked in git). Legacydocs/guide/*.mdanddocs/api-ref-readme.mdare removed from the old tree.scripts/generate-content.mjsnow only normalizes TypeDoc output intosrc/content/docs/api/and writes Netlify_redirectsfrom legacy.htmlURLs.astro.config.mjswires Starlight (Rapide theme, sitemap, Expressive Code, GTM/Sentry in head),starlight-page-actions, and custom Header, Footer, Head, ThemeSelect, PageTitle, PageSidebar (page actions in the right TOC column).Ops and authoring: New
docs/package.jsonscripts (dev,build,generate:content,test:build),README-DEPLOYMENT.md,README-EDITING.md, andCLAUDE.md(Diátaxis standards, frontmatter, examples).test-build.mjsadds post-build checks (links, redirects, example modules, Pagefind).Reviewed by Cursor Bugbot for commit 61190e7. Bugbot is set up for automated code reviews on this repo. Configure here.