Common Docusaurus v3/v4 development fixes and configuration tweaks. Use when: (1) Setting up or maintaining a Docusaurus site, (2) Seeing warnings about deprecated config options like onBrokenMarkdownLinks, (3) Getting "Module not found" errors for @docusaurus/theme-common or plugin-content-docs when swizzling with pnpm, (4) Docusaurus + pnpm errors like "Hook useDoc is called outside the DocProvider" or duplicate React instances, (5) Generated docs produce broken link warnings that should be suppressed, (6) Using autogenerated sidebar with category ordering, (7) Making docs the homepage, (8) Optimizing generated docs for hot reload, (9) Migrating Docusaurus from npm to pnpm, (10) User says 'docusaurus fix', 'docusaurus warnings', 'fix docusaurus config'.
Install
npx skillscat add takazudo/claude-resources/dev-docusaurus Install via the SkillsCat registry.
Docusaurus Development Fixes
Configuration tweaks and patterns for Docusaurus v3.x projects.
Fix 1: Suppress Broken Link Warnings for Generated Docs
When docs are auto-generated from external sources (e.g., Claude Code skills, API specs), they often contain internal references (references/foo.md) that don't resolve in Docusaurus. These warnings are noise.
In docusaurus.config.ts (or .js):
const config = {
// Suppress broken link errors for generated docs with internal references
onBrokenLinks: "ignore",
markdown: {
// v4-compatible location for onBrokenMarkdownLinks
hooks: {
onBrokenMarkdownLinks: "ignore",
},
},
};Important: Do NOT use the top-level onBrokenMarkdownLinks option — it is deprecated since Docusaurus v3.6+ and will be removed in v4. Always place it under markdown.hooks.onBrokenMarkdownLinks instead.
Fix 2: pnpm + Docusaurus Requires shamefully-hoist=true
Docusaurus relies on phantom dependencies (transitive deps hoisted to root node_modules by npm/yarn). pnpm's strict node_modules structure doesn't hoist these, causing duplicate React instances and runtime errors like:
Hook useDoc is called outside the <DocProvider>.Hook useSidebar is called outside the <SidebarProvider>.- Other "Hook X is called outside the Y" errors
Fix: Create .npmrc in the Docusaurus project root:
shamefully-hoist=trueThen reinstall:
rm -rf node_modules
pnpm installThis tells pnpm to hoist all packages to the root like npm does. This is the recommended approach for Docusaurus with pnpm.
Alternative: Explicit Dependencies (without shamefully-hoist)
If shamefully-hoist=true is undesirable, install missing transitive deps explicitly:
pnpm add @docusaurus/theme-common @docusaurus/plugin-content-docsThis fixes "Module not found" errors for swizzled components but may not resolve all duplicate-instance issues.
CI/CD: Installing pnpm via corepack
When migrating CI workflows from npm to pnpm, use corepack enable before pnpm install:
# GitHub Actions
- name: Build documentation
run: |
corepack enable
cd doc
pnpm install --frozen-lockfile
pnpm run build
# amplify.yml / buildspec.yml
commands:
- corepack enable
- cd doc && pnpm install --frozen-lockfile
- pnpm run buildNode.js 18+ includes corepack. For older Node.js, install pnpm via npm install -g pnpm.
Autogenerated Sidebar with Category Ordering
Use autogenerated sidebar instead of manually building sidebar JSON:
// sidebars.js
const sidebars = {
mySidebar: [{ type: 'autogenerated', dirName: 'my-docs' }],
};
module.exports = sidebars;Control category order with _category_.json files in each directory:
{ "position": 2, "label": "Getting Started" }Each category's index.mdx should have sidebar_position: 1 in frontmatter so it appears first within its category.
Important for generated docs: If your generation script has a removeStaleItems function that cleans up old files, make sure it preserves _category_.json:
expectedFiles.add("_category_.json");Making Docs the Homepage
To make a doc page the site's homepage (no separate landing page):
- Set
routeBasePath: "/"in the docs plugin config:
docs: {
routeBasePath: "/",
// ...other options
},- Add
slug: /to the doc's frontmatter:
---
slug: /
sidebar_position: 1
---- Remove or empty the navbar items if not needed:
navbar: {
items: [],
},- Delete
src/pages/index.tsx(or.js) and its CSS module — Docusaurus's pages plugin takes priority over docs for the root route, so the pages file must be removed.
Optimizing Generated Docs for Hot Reload
When a generation script produces docs that Docusaurus watches, writing ALL files on every run triggers a full webpack rebuild (~20-30s). Use a writeFileIfChanged helper to only write files with actual content changes:
function writeFileIfChanged(filePath, content) {
if (fs.existsSync(filePath)) {
const existing = fs.readFileSync(filePath, "utf8");
if (existing === content) return false;
}
fs.writeFileSync(filePath, content);
return true;
}This enables Docusaurus fast HMR for content-only changes. The distinction:
- Editing existing file content → only that
.mdxfile is rewritten → Docusaurus HMR (instant) - Adding/removing files → new routes → Docusaurus full webpack rebuild (~20-30s, unavoidable)
Stale File Cleanup: Write First, Delete After
When regenerating docs that a running dev server watches, write new files before deleting stale ones. If you delete first, the dev server sees missing files and throws "Module not found" errors.
// WRONG - delete first causes transient errors
cleanDir(outputDir);
writeFiles(outputDir, newFiles);
// CORRECT - write first, then remove only stale files
writeFiles(outputDir, newFiles);
removeStaleItems(outputDir, expectedFileSet);
function removeStaleItems(dir, expectedItems) {
for (const item of fs.readdirSync(dir)) {
if (!expectedItems.has(item)) {
const p = path.join(dir, item);
fs.statSync(p).isDirectory() ? fs.rmSync(p, { recursive: true }) : fs.unlinkSync(p);
}
}
}