Skip to content

feat: port to Redoc 3 (3.0.1) - #2

Open
ramseydsilva wants to merge 11 commits into
mainfrom
redoc-3
Open

ramseydsilva wants to merge 11 commits into
mainfrom
redoc-3

Conversation

@ramseydsilva

@ramseydsilva ramseydsilva commented Nov 3, 2026 •

Copy link
Copy Markdown

Summary

Ports redocusaurus from Redoc 2.4 to Redoc 3.0.1 (tracking #473). This is a port, not a version bump: Redoc 3 removes the Redoc 2 internals the theme was built on (AppStore, OperationModel, Section, mobx, redoc/typings/*), ships as a browser-only ES module, routes by URL path instead of hash, and is themed with CSS variables instead of a theme object.

This is a staging PR in the fork, to review the change and agree the shape of it before proposing it upstream. The checklist at the end tracks what is left before that.

What changed

  • Dependencies: redoc 2.4.0 → 3.0.1, @redocly/openapi-core 1.16 → ^2.
  • Rendering in the browser: the theme renders Redoc 3 inside BrowserOnly. ServerRedoc, ServerStyles, Styles, useSpec, ApiOperation and ApiSchema are removed.
  • Build-time server rendering (new ssr option, default true): Redoc 3 can't be required from Node, so the plugin renders each spec in a worker thread with Redoc 3's own server API. Every tag and operation gets its own exact route and static HTML, with a shared stylesheet per spec. ssr: 'required' fails the build if a spec can't be rendered. HTML is rendered only for production builds of the default locale. The dev server and other locales get the same exact routes (so a path that is not a page is a "Page Not Found" everywhere and links are checked), rendered in the browser. Because every page is a real file, hosts need no fallback rule for deep links and unknown paths are real 404s. Redoc replaces the server HTML when it mounts (it does not hydrate it).
  • Routing: Redoc 3 routes by path, so the spec route is passed as Redoc's basePath. Embedded pages (<ApiDocMdx>, @theme/Redoc in a custom page) use the right base.
  • Spec download: Redoc 2 took the spec's address as specUrl. The spec's download link (the bundled copy, or its own url) is now passed as Redoc 3's downloadUrls, in the browser and in the build-time render. A relative url is relative to the site's baseUrl, or with normalizeUrl: false to the API's route (never to the page the reader is on, because Redoc 3 reads a relative URL against each tag and operation page, and the Copy menu's "Open in Claude/ChatGPT" prompt would link to a 404).
  • Embedded APIs: <ApiDocMdx> used a Redoc 2 breakpoint override that Redoc 3 ignores, which left the three columns squeezed into the docs column. It now sets layout: 'stacked' as a default that a site's own layout overrides.
  • Legacy deep links: utils/legacyHash.ts redirects Redoc 2 #tag/<Tag> and #tag/<Tag>/operation/<id> hashes to the new path URLs in the browser. #operation/..., #section/... and #schema/... are not handled.
  • Theming: Redoc 3 has no theme option. The API pages now follow the Docusaurus theme by default: Redoc's tokens are set from Infima variables, in light and dark mode. primaryColor and primaryColorDark set the primary tokens, and a new cssVariables: { light, dark } option sets any other token. The Redoc 2 theme object is ignored, with one warning per build. On screens up to 600px wide the page title and section headings use smaller sizes (Redoc's 36px title leaves no room next to its Copy button on a phone and a word is broken in the middle; a site's own cssVariables still win). In production the stylesheet is a small linked file (Docusaurus doesn't render <style> from <Head> into static HTML), in dev it's a <style> tag.
  • Telemetry off by default: Redoc 3 sends usage events to otel.cloud.redocly.com unless disableTelemetry is true. The theme now sets it to true by default (override with disableTelemetry: false), and the build-time render does too. This differs from Redoc's own default, so I'd like to confirm it.
  • operationId whitespace is trimmed, with a warning, for the rendered pages only. The downloadable spec stays as written.
  • Color mode: Redoc 3 keeps its own mode (localStorage['redoc.colorMode'], a light/dark class on <html>) and ignores Docusaurus's data-theme. The theme syncs both ways and restores the class after navigation. When the Docusaurus mode changes, Redoc's own mode switch is clicked, so Redoc changes in place and the page keeps its scroll position; remounting Redoc is only the fallback if that switch is not on the page. This relies on Redoc internals, not a documented API, so it lives in one module, can be turned off with syncColorMode: false, and a test checks the installed Redoc still behaves that way.
  • Dependencies of the theme: react-router ^7.0.0 is declared, with a webpack rule that resolves it from Redoc's own location for Redoc's files only. Docusaurus makes @docusaurus/core's react-router 5 win for every import in the bundle, which broke Redoc.
  • Network requests: a guide lists what Redoc 3 requests at run time and what to allow in a Content Security Policy.
  • Tests and tooling: unit tests with Node's built-in runner (yarn test:unit, run in the build workflow), a changeset (a major bump for the three linked packages), a migration guide (website/docs/guides/migrating-to-v3.md), local types/redoc-compat.ts in place of the removed Redoc typings, and engines.node >=22.
  • Version: 2.6.0-redoc3.N is only for local packs. The changeset sets the real version, and the local version commits are dropped before submitting.

Known limitations

  • Reloading a link inside an API you embed yourself returns a 404. This applies to <ApiDocMdx> in an MDX page and to @theme/Redoc or @theme/ApiDoc in a custom page. Redoc 3 routes by path below the page it is on, and a page of your own has no routes below it, so after clicking around inside the page, a reload (or a copied link) to an operation gives a 404. Redoc 2's hash links survived a reload. APIs with their own route are not affected: every tag and operation is a static page. It is documented in the migration guide and in "Showing Multiple APIs". Options if you want it fixed: a hash router for embedded APIs (links like /docs/nested/nested-1#/pet/getpetbyid), which I have not tried.
  • The "Copy" menu has "Open in Claude/ChatGPT" actions that send the page text or the spec URL to those sites when a reader clicks, and Redoc 3 has no option to remove it. The "API docs by Redocly" badge is requested from cdn.redoc.ly and cannot be turned off, but it hides itself if blocked. See the network requests guide.

Breaking changes / requirements

  • Node >=22.
  • Peer dependencies: react and react-dom 18.3+ or 19 (already in every Docusaurus site). react-router 7 and styled-components 6 are installed for Redoc, next to the versions Docusaurus uses.
  • Deep links change from hash to path, e.g. #tag/Accounts/operation/getBillingAccounts → /accounts/getbillingaccounts (lowercased). The browser redirect covers tag and operation hashes, not the rest.
  • The Redoc 2 theme option and theme.openapi.theme in redocly.yaml no longer have an effect.
  • ApiOperation, ApiSchema, ServerRedoc and ServerStyles are removed.
  • Telemetry is off unless turned on.

See the migration guide for details.

Testing

  • Builds and renders in a large consuming Docusaurus site (30+ OpenAPI specs, 700+ API pages), with no broken links or anchors in a production build.
  • The website in this repo builds against the workspace packages (Docusaurus 3.6.0, React 18.3.1, the faster/Rspack bundler). Checked with a sub-path baseUrl, trailingSlash true and false, OpenAPI 3.x, Swagger 2.0 JSON, multi-file YAML, a remote URL spec, several specs on one site, and embedded pages.
  • Light and dark mode, the configured primary color, and the dev server were checked by hand. On the website, switching Docusaurus's light/dark mode on a scrolled example page keeps the scroll position and the page height and does not rebuild Redoc, and Redoc's own switch still drives Docusaurus. The fallback remount (when Redoc's switch is not on the page) was not checked in a browser. Unit tests cover the theme stylesheet builder, option defaults, the legacy mapper, route collection, ssr option validation and the plugin's route registration against the real Redoc 3 renderer.
  • Not tested yet: other locales with the plugin, Safari and Firefox, and upstream's own visual e2e snapshots (all baselines will change and need approval).

Path to upstream readiness

Checklist for going from this staging PR to the PR against rohit-gohri/redocusaurus. Details and notes are tracked in REDOC3.md on this branch, which is deleted before submitting.

Coordination

  • Agree the PR split with the maintainer: (1) the port, (2) color mode sync, (3) server rendering, (4) website, docs and migration guide, and ask whether they want a pre-release (next) or a major version

Required for any PR

  • Lint, type check and build are green
  • Changeset
  • Migration guide and list of breaking changes
  • Unit tests
  • Demo website: Redoc 2 docs text and READMEs updated, example pages compared with Redoc 2 (found and fixed the missing spec download link and the cramped embedded layout)
  • Visual e2e snapshots: all three pages differ and the baselines need the maintainer's approval. Before and after screenshots of the three pages (1280px and 375px, light and dark, against the live Redoc 2 site) are captured for the final description, and comparing them found and fixed a mobile title problem

Functional

  • Port to Redoc 3, path routing, legacy hash mapper
  • Color mode sync
  • Build-time server rendering with exact routes
  • Theming with CSS variables that follow the Docusaurus theme
  • Telemetry off by default (confirm with the maintainer)
  • operationId trimming that doesn't change the downloadable spec
  • Reliance on Redoc internals: Redoc 3 has no option for its color mode, so the sync is isolated in one module, has a syncColorMode theme option to turn it off, and a test that fails if a Redoc upgrade changes what it relies on
  • Compatibility matrix: tested by hand in Safari 27.2, Firefox 159.0.1 and Chrome 156 (macOS, arm64), and in Chrome for sub-path baseUrl, both trailingSlash settings, OpenAPI 3.x and Swagger 2.0, remote and multi-file specs, several specs, embedded pages, the dev server and other locales (en, fr, ja). One known limitation, below
  • Declare requirements: react and react-dom (^18.3.0 || ^19.0.0, Redoc's range) are peers of the theme and the preset, react-router ^7.0.0 stays a dependency (Docusaurus core depends on react-router 5, so a peer on 7 would conflict), @redocly/config (a types-only peer of Redoc) is a theme dependency, and unused Redoc 2 dependencies were removed. Checked with a strict-layout install; pnpm itself not tested
  • Audit the requests Redoc 3 makes at run time: only the "API docs by Redocly" badge (cdn.redoc.ly) by default, with no option to turn it off but it hides itself if blocked; icon sets and telemetry only on demand; documented with CSP directives in a new guide (website/docs/guides/network-requests.md)

Decisions to document

  • ssr on by default (true): a failed render warns and falls back, 'required' fails the build
  • operationId whitespace: trimmed with a warning (rendered pages only)
  • HTML for the default locale only, with exact routes (no HTML) in the dev server and other locales; no "all locales" option until asked
  • Swap (Redoc replaces the server HTML) for this PR; true hydration is a follow-up experiment

Packaging (final stage)

  • Rebuild the history from upstream main: squash the checkpoint commits, set the commit identity, drop the local version commits (done: the history is 11 commits on top of upstream main with the public identity; still to do: drop the local version bumps)
  • Regenerate yarn.lock from upstream's and keep only the changes the port needs
  • Verify nothing sensitive is leaked, including hints (the current history, tree, messages and authors were scanned and are clean; repeat before submitting): scan the final diff, every commit message and author, the changeset, docs, examples, test fixtures, the lockfile (registry URLs), config and this PR description for corporate data, internal names, hostnames, registries, tooling or infrastructure details
  • Final PR description with before and after screenshots, numbers (pages, build time, size), breaking changes and the migration guide

🤖 Generated with Claude Code

Render Redoc 3 in the browser, route its sub-paths by URL path, map old Redoc 2 `#tag/...` links to path links, and keep its color mode in step with Docusaurus.

Redoc 3 removes the Redoc 2 internals the theme was built on and routes by path instead of hash, so this is a port, not a version bump.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ramseydsilva ramseydsilva self-assigned this Nov 3, 2026
ramseydsilva and others added 7 commits November 3, 2026 17:33
Every tag and operation is rendered to its own static page, with one exact route each. Unknown paths below an API are a 404 and links to them are checked at build time. The `ssr` option is `true` by default; `'required'` fails the build if a page cannot be rendered, and `false` turns it off.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Resolve react-router for Redoc, fix the base path of an embedded API, and clean up lint, types and engines. Split the plugin entry.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…urus theme

Redoc 3 sends usage events unless `disableTelemetry` is set, so it is on by default here. Map the Docusaurus theme to Redoc's CSS variables (fonts, colors, light and dark), with `primaryColor`, `primaryColorDark` and a `cssVariables` option to override them.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Tests use Node's built-in runner. The downloadable spec is kept as written when operationIds are trimmed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…s in dev

The spec download uses Redoc 3's `downloadUrls`. An embedded API is stacked instead of squeezing three columns into a docs page. Exact routes are registered in the dev server and in other locales too. Document the network requests Redoc 3 makes. Declare react and react-dom as peers and add @redocly/config.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Everything that relies on Redoc's undocumented color mode behaviour is in one place, with a test that reads the installed Redoc. `syncColorMode: false` turns it off.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Reloading a link inside an embedded API returns a 404, because the page that embeds it has no route for the sub-path.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@displague
displague requested a balanced review from Copilot November 5, 2026 05:15

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

@displague

Copy link
Copy Markdown
Member

@claude review

ramseydsilva and others added 3 commits November 5, 2026 05:45
…adings on narrow screens

A relative download URL was read against the tag or operation page, so the link was a 404 there. On screens up to 600px the title and section headings use smaller sizes, so a word is not broken in the middle.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Path routing gives one static page per tag and operation. A hash router gives one page per spec and every link into it is flagged by the broken-anchor check.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Remounting Redoc on every mode change rebuilt the whole page: it scrolled to the top and its height changed. Click Redoc's own color mode switcher instead, which changes the mode in place, and keep the remount only as the fallback for when the switcher is not on the page. Add tests that check the installed Redoc still has the switcher and toggles dark and light.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants