Skip to content

docs: migrate the website from Docusaurus to Fumadocs - #193

Merged
unadlib merged 35 commits into
mainfrom
docs/fumadocs
Oct 8, 2026
Merged

unadlib merged 35 commits into
mainfrom
docs/fumadocs

Conversation

@unadlib

@unadlib unadlib commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Summary

This migrates the website, mutative.js.org, from Docusaurus 3.3 to Fumadocs 16.16 on Next.js 16.3, React 19.3 and Tailwind CSS 4.3, exported as a static site for GitHub Pages as before. The docs content is moved with git mv, so its history follows the files, and its wording is unchanged apart from the conversions below. Every URL of the current site keeps working, including the ones that the library's production errors and development warnings print; only the template's example page, /markdown-page, is gone.

Changes

  1. Remove the Docusaurus translations and the example page: the zh-CN locale was disabled and held the Docusaurus tutorial, and /markdown-page was the template's example.
  2. Replace Docusaurus with a Fumadocs app: Next.js static export with trailingSlash, the docs in website/content/docs as MDX, the page H1 in the title frontmatter, meta.json files for the sidebar order and labels that sidebar_position and _category_.json gave, the static files in public, and a nested oxlint config so that the root pnpm lint checks the website with Next.js rules.
  3. Apply the Mutative orange (#ff8800, #fb931f in dark mode) of the Docusaurus theme to the Fumadocs colors.
  4. Convert the :::tip, :::warning and :::caution admonitions to <Callout>.
  5. Render blockquotes as notes: the typography preset shows them as italic quotations, while the docs use them for notes.
  6. Turn the npm2yarn code blocks into npm blocks, which show npm, pnpm, Yarn and Bun commands and remember the choice across pages.
  7. Describe pages without a description by their first paragraph, as Docusaurus did; 29 of the 30 meta descriptions are identical, and the TypeScript page now keeps Draft<T>, which Docusaurus dropped as HTML.
  8. Migrate the blog: the post, its images, the author, the reading time (6 min, as before), the tags and the index page.
  9. Keep the RSS and Atom feeds at /blog/rss.xml and /blog/atom.xml with the same item ids, so feed readers keep the posts they have seen, and their <link rel="alternate"> on every page.
  10. Add the footer to the home, blog and 404 pages.
  11. Show the v1.0 announcement in a dismissible banner.
  12. Add static search. The index is a .json file, so that GitHub Pages can serve it compressed: 789 kB, 152 kB with gzip.
  13. Show the edit link and the last update ("Last updated on … by …") of each docs page.
  14. Add an overview page for each docs section, like the Docusaurus category pages, with a card per page; the section labels in the sidebar link to them.
  15. Redirect the URLs that moved: /docs/category/* to the overview pages, /blog/archive/ and /blog/tags/* to /blog/, and /docs/ to /docs/intro/. Static exports cannot use Next.js redirects, so the build writes pages with a meta refresh, a canonical link and a script that keeps the hash.
  16. Generate sitemap.xml, now with the last update of each page.
  17. Add the 404 page.
  18. Publish llms.txt, llms-full.txt and the Markdown of each docs page, with buttons to copy it or open it in an AI assistant.
  19. Fail the build on links to missing pages or anchors, as onBrokenLinks: 'throw' did; the check reads the exported HTML, so it also covers the sidebar, the footer and the redirects.
  20. Deploy with gh-pages: pnpm publish:docs still builds the site and pushes it to the gh-pages branch over SSH, with the same commit message.
  21. Build the website in CI for pull requests and pushes to main that change it.
  22. Rewrite the website README for Fumadocs.
  23. Link each blog post to its source on GitHub, as the Docusaurus blog did.
  24. Add a "Who Uses Mutative" page: Appsmith, InstantDB, Notesnook and Plate, with the verbatim quotes of the pull requests and release notes in which they adopted Mutative, their context and dates, and Mol*, OpenRewrite and MSW Data. On October 9, 2026, each of them depended on Mutative directly on its default branch.
  25. Note on the Comparison with Immer page that Immer 11.0.0 ported the finalization callbacks of Mutative in Rewrite finalization system to use a callback approach instead of tree traversal immerjs/immer#1183, and that the measured Immer 11.1.18 includes them.

Home page

The home page is redesigned in ten commits, in both color modes and from 320 px wide:

  1. A hero with the tagline over a grid and a glow of the brand color, the benchmark result, the install command with a copy button, and the GitHub stars. The browser fetches the stars and keeps them for an hour, so the static build needs no network; when GitHub limits the requests, the count is left out. In light mode the orange words are darker, so that they keep a 3:1 contrast.
  2. The update of the introduction, written with spread syntax and with Mutative, side by side.
  3. The benchmark results of the performance page: 3.4x and 6.0x faster than Immer, and 93 workloads.
  4. Projects that replaced Immer with Mutative: Appsmith, InstantDB, Notesnook and Plate, each with a verbatim quote, its context, the source and the month, without logos or star counts, and Mol*, OpenRewrite and MSW Data in one line. The Notesnook quote leaves out its 10x figure, which describes the library rather than the app; the docs page quotes it in full with that note.
  5. The eight features of the introduction as cards, each linking to its docs.
  6. The twelve libraries of the ecosystem page as compact links; their descriptions stay on that page.
  7. A closing call to action with links to the getting started guide and the Immer migration guide.
  8. A footer that follows the color mode, with the logo, more docs links, npm and the license.
  9. Sections that alternate their backgrounds.

URL compatibility

  • Pages keep their URLs, such as /docs/getting-started/performance and /blog/releases/1.0. GitHub Pages redirects them to the trailing slash, as it did for the Docusaurus output.
  • All 70 heading ids of the docs pages are identical to the Docusaurus output, including the pages and anchors that the library and the README link to: /docs/api-reference/create#create-on-a-draft, /docs/api-reference/current, /docs/extra-topics/errors and /docs/advanced-guides/pathes#sets-of-objects.
  • website/static/img/ mutative.png stays where it is: the READMEs of the published npm packages load the logo from that path on main. Next.js copies the static directory into the export, so the site also serves it at /static/img/.

Differences from the Docusaurus site

  1. The feeds hold the first paragraph of each post instead of its full HTML, and only Atom names the author, since an RSS <author> must be an email address.
  2. The tag and archive pages of the blog redirect to the blog, which lists its single post.
  3. The navbar link "Tutorial" is now "Docs", and the footer link "Tutorial" is now "Introduction".
  4. The Shared References page keeps its sidebar title as its heading, "Shared References", since Fumadocs renders the title as the H1; the heading was "Shared References Behavior".
  5. The home page is redesigned as described above, and links use the text color with an orange underline, the Fumadocs style, instead of orange text, and dark code blocks use the GitHub Dark theme instead of Dracula.
  6. The site has search, llms.txt and the Markdown of each page, which it did not have.
  7. The last update of a docs page is the last commit that changed it, so once this pull request is merged, the pages show its date.

Verification

  • pnpm build in website generates 42 static routes and 8 redirect pages without warnings and checks the links of all 48 HTML files; a broken page link and a broken anchor added to a page made it fail.
  • Every Fumadocs commit of the branch, including the home page commits, installs with --frozen-lockfile, builds and passes the root pnpm lint in a fresh clone; the first commit, which still uses Docusaurus, builds with Docusaurus.
  • In Chrome, served by a server that behaves like GitHub Pages: client-side navigation from the sidebar and from links in the content, anchors, the redirects, search, the package manager tabs and their persistence, the banner and its dismissal, Copy Markdown, the copy button of the install command and the cached star count, and light, dark and mobile layouts; the home page does not scroll sideways at any width from 320 to 1440 px.
  • gh-pages --no-push produced the expected gh-pages tree, with .nojekyll and CNAME and without .DS_Store files; nothing was pushed, and the site has not been deployed.
  • The root pnpm lint, pnpm format --check and pnpm type-check pass; no library file changes.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Coverage after merging docs/fumadocs into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   apply.ts100%100%100%100%
   array.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   error.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Coverage after merging docs/fumadocs into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   apply.ts100%100%100%100%
   array.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   error.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown

Coverage after merging docs/fumadocs into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   apply.ts100%100%100%100%
   array.ts100%100%100%100%
   constant.ts100%100%100%100%
   create.ts100%100%100%100%
   current.ts100%100%100%100%
   draft.ts100%100%100%100%
   draftify.ts100%100%100%100%
   error.ts100%100%100%100%
   index.ts100%100%100%100%
   interface.ts100%100%100%100%
   internal.ts100%100%100%100%
   makeCreator.ts100%100%100%100%
   map.ts100%100%100%100%
   original.ts100%100%100%100%
   patch.ts100%100%100%100%
   rawReturn.ts100%100%100%100%
   set.ts100%100%100%100%
   unsafe.ts100%100%100%100%
src/utils
   cast.ts100%100%100%100%
   copy.ts100%100%100%100%
   deepFreeze.ts100%100%100%100%
   draft.ts100%100%100%100%
   finalize.ts100%100%100%100%
   forEach.ts100%100%100%100%
   index.ts100%100%100%100%
   mark.ts100%100%100%100%
   marker.ts100%100%100%100%
   proto.ts100%100%100%100%

@unadlib
unadlib merged commit a8655ea into main Oct 8, 2026
6 checks passed
@unadlib
unadlib deleted the docs/fumadocs branch October 8, 2026 16:29
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.

1 participant