Takazudo

dev-docusaurus

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'.

Takazudo 10 1 Updated 3mo ago
GitHub

Install

npx skillscat add takazudo/claude-resources/dev-docusaurus

Install via the SkillsCat registry.

SKILL.md

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=true

Then reinstall:

rm -rf node_modules
pnpm install

This 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-docs

This 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 build

Node.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):

  1. Set routeBasePath: "/" in the docs plugin config:
docs: {
  routeBasePath: "/",
  // ...other options
},
  1. Add slug: / to the doc's frontmatter:
---
slug: /
sidebar_position: 1
---
  1. Remove or empty the navbar items if not needed:
navbar: {
  items: [],
},
  1. 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 .mdx file 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);
    }
  }
}