feat(rspress): add Rspress documentation site with PR preview CI#5415
Draft
kduret wants to merge 32 commits into
Draft
feat(rspress): add Rspress documentation site with PR preview CI#5415kduret wants to merge 32 commits into
kduret wants to merge 32 commits into
Conversation
Sets up a rspress 2.0.0-beta.21 site under rspress/ with EN/FR locales and 26.10/25.10 versioning. Migrates the full getting-started section (84 files) for all 4 lang×version combos, with tabs, homepage components, and proper sidebar configuration.
Extend migration from getting-started-only POC to all 22 sections (~325 files per lang/version combo). Key additions: - migrate.py: recursive migration of all .md/.mdx source files + full assets - Sidebar auto-generated from versioned_sidebars JSON + FR label translations - rspress.config.ts now imports sidebar from src/sidebar.ts - transform(): fix indented code fences, normalize languages (SQL→text, XML→text, phpconf/apacheconf→bash), strip @site/ imports, remove HTML comments in MDX, decode %20 in asset paths - Asset files with spaces renamed to hyphens to satisfy rspack resolver
Replace auto-migrated placeholder index.md with proper HomePage component pages mirroring the 26.10 homepage but with /25.10/ links. Also guard migrate.py against overwriting hand-crafted version index files.
In rspress v2 multiVersion, replaceVersion() only strips the version prefix from the current URL when current != default. If sidebar links use /26.10/... and the user switches to 25.10, the result is /25.10/26.10/... (double prefix). Fix: default version (26.10) sidebar links and homepage/nav links now use no version prefix (/getting-started/welcome instead of /26.10/...). Sidebar key changes from '/26.10/' to '/' and '/fr/26.10/' to '/fr/'.
- New custom theme (theme/index.tsx) with URL-driven VersionSelector and LanguageSelector. The built-in version selector always read '26.10' due to our docs/<lang>/<version> layout (rspress expects the reverse), and the built-in language selector only showed a globe icon. Both are hidden via CSS and replaced. - Config: search.versioned, enableScrollToTop and per-locale editLink to GitHub. Clear themeConfig.nav since the custom theme provides nav items. - tsconfig: jsx + DOM lib so the IDE typechecks the new theme files. - migrate.py: normalize (../)+assets/... references to the correct depth based on the file's location, and skip FR-only files with no EN counterpart (they pulled in stale broken asset paths). - Remove 8 already-migrated FR orphan files the new filter would now skip.
- Add pp (Monitoring Connectors) and cloud migration to migrate.py: 745
pp files and 119 cloud files per language, plus their CommonJS sidebar
files loaded via node. Factor the per-tree migration loop into
_migrate_tree() so versioned-docs, pp and cloud share the same code path
(orphan FR filter, asset copy, asset-with-spaces rename, asset-ref depth
normalization).
- generate_sidebar: include /pp/, /cloud/ and their /fr/ variants, and
emit non-default keys (/25.10/, /pp/, /cloud/, /fr/25.10/, ...) before
the default keys (/, /fr/). rspress sidebar matching is first-match so
the default `/` key would otherwise swallow every nested request.
- Tighten the code-fence language regex so inline triple-backtick spans
like ```rrdcached``` is not supported. don't get falsely treated as
fence openers. Trailing fence attributes (e.g. ```bash {1,3}) are
preserved by capturing them.
- Add shiki aliases for languages not bundled in rspress v2 beta:
smarty/csv/txt → text, cmd → bash.
- theme: replace the external cloud link with a local /cloud/... link
(now that the cloud docs are migrated locally).
- src/sidebar.ts and rspress/docs/{en,fr}/{pp,cloud} regenerated.
- Add LM_SOURCE_{EN,FR}, LM_SIDEBAR_JS, LM_FR_LABELS_PATH constants and a
migrate_logmanagement() call backed by the existing _migrate_tree helper.
- generate_sidebar: register /logmanagement/ and /fr/logmanagement/ in the
non-default key group so they sit before / and /fr/ (rspress's first-match
sidebar resolution).
- theme: add a "Log Management" Link in the top nav, language-prefixed and
pointing at the local /logmanagement/getting-started/welcome.
18 markdown files + 10 assets per language.
The rspress v2 stable line moved to a new npm package name: @rspress/core (the rspress package itself stays at v1.47.x). The CLI binary is still named rspress, only imports and the package name change. Changes: - package.json: replace `rspress@2.0.0-beta.21` with `@rspress/core@~2.0.14`, add `"type": "module"` (eliminates a parse-as-CJS warning + perf overhead rspress v2 prints on startup). - pnpm-workspace.yaml: declare `rspress` as a workspace member so the lockfile tracks its deps properly. Add `minimumReleaseAgeExclude` for `@rspress/core` and `@rspress/shared` so the 7-day minimum-release-age rule doesn't block picking up fresh @rspress/core releases. - rspress.config.ts: switch `defineConfig` import to `@rspress/core`. The `markdown.checkDeadLinks` option moved to `markdown.link.checkDeadLinks` in the v2 stable API. Add an opt-in Rsdoctor integration via `builderConfig.tools.rspack` — set `RSDOCTOR=true pnpm build` to instrument the build and open the analysis dashboard. - theme/index.tsx: switch to named imports from `@rspress/core/theme-original` per the v2 breaking change notice (the previous `default` export from `rspress/theme` is gone; the migration is named exports from `theme-original`). - migrate.py: rewrite injected `<Tabs>/<TabItem>` imports to point at `@rspress/core/theme` instead of `rspress/theme`. All ~2005 affected MDX files regenerated. - Add `@rsdoctor/rspack-plugin` as devDependency (pinned to ^1.5.12 because 1.5.13 is too recent under minimumReleaseAge).
Bring the Rspress documentation visually in line with the production Docusaurus site (docs.centreon.com) for both style and navigation: - Add the Centreon navbar logo (light/dark variants) and favicon. - Set the brand palette via a global stylesheet: Centreon blue (#2213e2) in light mode, green (#37d6ae) and navy background (#00003d) in dark mode, overriding the default Rspress theme vars. - Load the site typography: Red Hat Display for body text and Esphimere for headings. - Tint blockquotes and inline code with the brand color, and add a footer with the corporate links and copyright. Font faces are referenced through paths relative to the stylesheet so Rspack resolves and emits them; root-absolute url() paths failed module resolution and dropped the whole global stylesheet. Assisted-by: Claude Code (claude-opus-4-8)
Continue the visual alignment with the production Docusaurus site (docs.centreon.com): - Highlight code with the github-light / dracula Shiki themes, matching the Prism themes used on the Docusaurus site. - Enable click-to-zoom on documentation images via medium-zoom, re-attaching on each navigation and tinting the overlay per theme (white in light mode, Centreon navy in dark mode). - Render a global footer on documentation pages (corporate links, logo and copyright) through the DocLayout afterDocFooter slot. - Raise the navbar height to 96px to match the Docusaurus header. The official @rspress/plugin-medium-zoom targets the rspress 1.x runtime and is incompatible with 2.x, so the medium-zoom library is wired up directly in the custom theme instead. Assisted-by: Claude Code (claude-opus-4-8)
Two issues surfaced by visual review of the rendered site: - Logos (navbar + footer) and homepage images were broken because the assets lived in rspress/public, but rspress serves the public folder located under the doc root (docs/public). Move images to docs/public/img and keep the fonts bundled by Rspack under styles/fonts (referenced relatively from the global stylesheet). - The navbar showed duplicate language/version selectors: the rule that hid rspress's built-in switchers targeted the obsolete .translation class. In rspress 2.x NavLangs/NavVersions render as plain .rp-nav-menu__item elements inside .rp-nav__others, so hide those while keeping the appearance toggle and social links. Assisted-by: Claude Code (claude-opus-4-8)
Clicking any sidebar entry on a 26.10 (default version) page led to a 404. The migration keyed the default version under '/' with version-less links (/getting-started/foo), assuming rspress would serve the default version at the root. It does not: pages are only served under /<version>/..., and the custom version switcher (VersionAwareNav) already builds /<version>/... links. Version-less URLs are unrouted and 404. Key the default version like the others (/26.10/ and /fr/26.10/) with version-prefixed links, in both migrate.py and the generated src/sidebar.ts. Non-default versions, pp, cloud and logmanagement are unchanged. Assisted-by: Claude Code (claude-opus-4-8)
On viewports below 1280px the custom version-aware nav rendered its links inline, so they overflowed and overlapped the logo. Collapse it into a hamburger button at the top right that opens a panel with the product links, the version and language selectors, and the appearance toggle. rspress's own mobile hamburger is hidden so only one burger is shown. The desktop layout (>=1280px) is unchanged. Assisted-by: Claude Code (claude-opus-4-8)
Add the Experience Monitoring (XM) product documentation, migrated from Docusaurus like the other standalone trees (pp, cloud, logmanagement): English and French content plus assets, served under /experience-monitoring/ and /fr/experience-monitoring/ with their own sidebar sections. migrate.py gains the sources, a migrate_experience() step and the sidebar generation for it. This is needed so the product switcher can link to Experience Monitoring without a 404. Assisted-by: Claude Code (claude-opus-4-8)
Add a grid (apps) icon at the top right that opens a product switcher, mirroring docs.centreon.com: Infrastructure Monitoring (IM), Experience Monitoring (XM) and Log Management (LM), each with its coloured initials badge. Infrastructure Monitoring is version-aware. Experience Monitoring is also added to the mobile burger panel so it stays reachable on small screens. Assisted-by: Claude Code (claude-opus-4-8)
Derive the current product family (Infrastructure Monitoring, Experience Monitoring, Log Management) from the URL and show only that family's sections in the navbar header: Infrastructure Monitoring keeps OnPrem / Cloud / Connectors, while Experience Monitoring and Log Management show only themselves. Show the version selector only on actually-versioned pages (the on-prem docs). It is now hidden on Experience Monitoring and Log Management — as well as Cloud and Connectors — where versions don't exist and switching would 404. The product switcher highlights the active family and the mobile panel mirrors the same product-aware logic. Assisted-by: Claude Code (claude-opus-4-8)
Lay the navbar out like docs.centreon.com: the product sections move to the left next to the logo (with the active one highlighted), and the right cluster is ordered Search, version, language, appearance toggle, product switcher. The version selector gains the star marker. rspress's built-in 'others' group is fully hidden since the appearance toggle is now rendered in our own cluster in the right position. Assisted-by: Claude Code (claude-opus-4-8)
The homepage cards still linked to docs.centreon.com (and the Infra OnPrem link was version-less, hitting a 404). Now that Experience Monitoring, Cloud, Connectors and Log Management are all migrated, repoint every card link to the local pages: Infra OnPrem to the versioned /26.10 path, the others to their product trees. Docusaurus /category/ links are mapped to real pages (digital sobriety, the OpenTelemetry collector page). English and French homepages updated. Assisted-by: Claude Code (claude-opus-4-8)
The footer was attached to the doc layout's afterDocFooter slot, so it only showed on documentation pages and was missing from the custom homepage. Move it to the Layout bottom slot so it renders full-width at the bottom of every page (homepage included), matching the docs.centreon.com footer. Assisted-by: Claude Code (claude-opus-4-8)
The language selector always inserted a /<version>/ segment, so switching language off the on-prem docs went to broken targets: from the homepage it landed on /fr/26.10 instead of the French homepage /fr, and on cloud/connectors/experience/log management pages it produced /fr/26.10/<tree>/... (404). buildPathname now only adds the version on versioned pages, so language switching preserves the current location everywhere (homepage included). Assisted-by: Claude Code (claude-opus-4-8)
Images are the largest part of the output (~96 MB) and are served as-is, so gzip can't shrink them — unlike JS, reducing them cuts the deployed bundle and per-page transfer directly. Add @rsbuild/plugin-image-compress to the builder config to compress PNG/JPEG/ICO at build. Result: PNG output 71.5 MB -> 33.4 MB (-53%), total emitted 154 MB -> 114 MB gzipped (-40 MB), for +8s build and no visible quality loss. GIF/SVG are left untouched. Assisted-by: Claude Code (claude-opus-4-8)
Images were already compressed at build, but GIF and MP4 have no build-time codec and were served raw at full size. Optimize them in the migration with vendored binaries: - GIFs via gifsicle (-O3 --lossy=80): output 24.1 MB -> 15.5 MB. - The demo video via ffmpeg/libx264 (crf 30, 128k audio): 20.8 MB -> 3.5 MB. Combined with the earlier image compression, the deployed bundle drops from 154 MB to 87 MB gzipped (-43%). migrate.py gains an optimize_media() step (no-op when the tools are absent) and ffmpeg-static/gifsicle are added as dev tooling. No visible quality loss. Assisted-by: Claude Code (claude-opus-4-8)
Build the rspress docs in CI and deploy a Cloudflare Pages preview on every PR touching rspress/, posting the URL as a sticky comment. Each PR gets its own stable preview URL; deploying prebuilt assets via wrangler doesn't use the Cloudflare build quota, so it scales to many concurrent PRs for free. Actions are SHA-pinned (reusing the repo's existing pins); wrangler runs via pnpm dlx so no extra action needs pinning. Previews are skipped for fork PRs (no access to secrets). Requires a maintainer to create the Cloudflare Pages project 'centreon-docs-preview' and set CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID. Assisted-by: Claude Code (claude-opus-4-8)
…imit The French search index (25.07 MiB) exceeds Cloudflare Pages' 25 MiB per-file hard limit, which would fail the preview deployment. Drop code blocks from the search index only on preview builds (PREVIEW_BUILD=true, set by the preview workflow): the fr index drops to 22.8 MiB, comfortably under the limit. Staging and production keep the full search index (code blocks included) since they deploy to self-hosted infra with no such limit. Assisted-by: Claude Code (claude-opus-4-8)
…ning) - Make the nav dropdowns keyboard- and screen-reader-accessible: real <button> trigger with aria-haspopup/aria-expanded, open on focus/click, close on Escape and focus-out (the mobile burger was already accessible). - Give the homepage social links an accessible name (alt + aria-label). - Anchor familyOf()/activeSection() on the path prefix (after lang/version) instead of substring matching, so doc slugs containing cloud/pp/... aren't misclassified. - Pin wrangler via the lockfile (devDependency) and call it with pnpm exec instead of fetching the latest at runtime with pnpm dlx in a job holding the Cloudflare token. - Log ffmpeg/gifsicle stderr on failure in migrate.py and drop an unused var. Assisted-by: Claude Code (claude-opus-4-8)
Contributor
|
Re-run the migration against the source docs brought in by the staging resync, regenerating rspress/docs and the sidebar. Also harden migrate.py so re-runs are reproducible: - Clean each destination tree before writing, so a changed JSX detection (foo.md -> foo.mdx) no longer leaves a stale file and duplicate route. - Normalize bare/relative image asset references (assets/... and ./assets/...) to the correct depth-aware path, so same-directory images don't compile to unresolvable MDX bare imports. Build verified (preview build passes; search indexes stay under 25 MiB). Assisted-by: Claude Code (claude-opus-4-8)
Truncate each page's content in the generated search index to 12000 chars on preview builds, dropping the per-language index from ~24 MiB to ~14 MiB. This keeps comfortable headroom under Cloudflare Pages' 25 MiB per-file limit as the docs grow, while preserving useful search on previews. Preview-only (post-build step in the preview workflow); staging and production keep the full search index. Assisted-by: Claude Code (claude-opus-4-8)
Build the PR-preview search index from page headings (title + H2/H3) rather than truncating page bodies. Reviewers can search by title and section, and the per-language index drops to ~2.9 MiB (from ~24 MiB) for ample headroom under Cloudflare Pages' 25 MiB per-file limit. Staging and production keep the full-text search index. Assisted-by: Claude Code (claude-opus-4-8)
- Cache rspack's persistent build cache (node_modules/.cache) in the preview workflow so successive builds reuse it (rspack recompiles only changed modules). - Skip the Docusaurus build/preview jobs for the rspress migration PR by guarding get-versions on the branch (the rspress site has its own preview). Other branches and the staging deploy are unaffected; remove the guard once the migration branch merges. Assisted-by: Claude Code (claude-opus-4-8)
Contributor
|
📘 rspress documentation preview https://pr-5415.centreon-docs-preview.pages.dev Updated on every push to this pull request. |
Low-risk build optimizations identified while reviewing the rspress config options: - output.legalComments: 'none' — drop the separate *.LICENSE.txt files. - performance.printFileSize.compressed: false — skip the per-asset gzip size computation (costly across thousands of files, no functional impact). - markdown.cjkFriendlyEmphasis: false — the docs are EN/FR only (no CJK). - markdown.image.checkDeadImages: false on preview builds only (kept on for staging/production to catch broken image references before deploy). Assisted-by: Claude Code (claude-opus-4-8)
Set output.minify.jsOptions.minimizerOptions.compress.passes to 1 (rspack defaults to 2 since web-infra-dev/rspack#8853). Minification is the dominant build cost; one pass recovers a chunk of that time with no measurable size change (JS stays 176 MB raw / 21 MB gzipped — the gzipped transfer is already near-optimal). Assisted-by: Claude Code (claude-opus-4-8)
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.
Description
Adds a parallel Rspress (v2) documentation site under
rspress/, mirroring docs.centreon.com, without changing the current Docusaurus production site.Target version (i.e. version that this PR changes)