Skip to content

feat(site): migrate documentation site from Docusaurus to VitePress - #2721

Merged
waynesun09 merged 1 commit into
fullsend-ai:docusaurus-migrationfrom
DaoDaoNoCode:migrate-docs-vitepress
Jun 27, 2026
Merged

feat(site): migrate documentation site from Docusaurus to VitePress#2721
waynesun09 merged 1 commit into
fullsend-ai:docusaurus-migrationfrom
DaoDaoNoCode:migrate-docs-vitepress

Conversation

@DaoDaoNoCode

Copy link
Copy Markdown
Contributor

Summary

  • Replaces Docusaurus with VitePress for the docs site at /docs/, reducing dependencies from 10 packages (React, MDX, Prism) to 2 (VitePress, Vue)
  • Preserves all visual styling: brand colors, gradient headings, frosted glass navbar, animated link underlines, reading progress bar, code block rounding, table hover effects, sidebar active indicator
  • No documentation content was modified — all 163 markdown files render as-is
  • CI workflow updated (website/build/website/dist/) for seamless deployment on existing Cloudflare Workers infra

What changed

Removed (Docusaurus):

  • website/docusaurus.config.ts, website/sidebars.ts
  • website/src/ (React components, CSS, theme overrides)
  • website/static/ (moved to docs/public/)

Added (VitePress):

  • website/.vitepress/config.ts — site config, sidebar, markdown preprocessing
  • website/.vitepress/theme/ — custom theme (CSS, ReadingProgress Vue component)
  • docs/index.md — redirect to Getting Started (replaces Docusaurus slug: /)
  • docs/public/img/ — favicon and logo

Modified:

  • website/package.json — Docusaurus deps → VitePress + Vue
  • website/tsconfig.json — removed @docusaurus/tsconfig extend
  • .github/workflows/site-build.ymlwebsite/build/website/dist/

Notable decisions

  • Markdown preprocessing: VitePress compiles markdown as Vue SFCs, so {{ }}, {x|y}, and <PLACEHOLDER> syntax in docs break Vue's template compiler. A preConfig hook escapes these before markdown-it processes them (same pattern Docusaurus used). Inline code gets v-pre per VitePress maintainer recommendation.
  • No footer on doc pages: VitePress's default theme hides the footer on sidebar pages by design. The landing page at fullsend.sh already has its own footer.
  • Separate sites: Landing page (/) and docs (/docs/) remain separate — no changes to the homepage.

Test plan

  • npm run build produces 163 HTML pages with no errors
  • All sidebar sections match the original Docusaurus sidebar
  • README.md files rewrite to index.html (clean URLs)
  • Static assets (favicon, logo) included in build output
  • Excluded paths (agents/icons/, testing/) not in build
  • site-build.yml copies website/dist/ to _bundle/public/docs/
  • CI build passes on this PR
  • Preview deployment renders correctly on Cloudflare Workers

@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Migrate docs site from Docusaurus to VitePress
✨ Enhancement ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

Description

• Replace Docusaurus docs site with VitePress while keeping docs content unchanged.
• Add custom VitePress theme and reading-progress UI to preserve existing styling.
• Update CI packaging to deploy website/dist/ instead of website/build/.
Diagram

graph TD
  A[".github/workflows/site-build.yml"] --> B(["VitePress build"]) --> C["website/dist/"] --> D["_bundle/public/docs/"]
  E["website/.vitepress/config.ts"] --> B
  F["website/.vitepress/theme/"] --> B
  G["docs/ (md + public)"] --> B
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Keep Docusaurus and reduce customization
  • ➕ Avoids introducing Vue/VitePress-specific markdown constraints and preprocessors
  • ➕ Retains existing Docusaurus ecosystem (plugins, MDX) if needed later
  • ➖ Heavier dependency footprint (React/MDX/Prism stack)
  • ➖ Harder to keep build/output parity if the goal is a leaner docs pipeline
2. Use an off-the-shelf docs theme (minimal custom CSS)
  • ➕ Less custom CSS/overrides to maintain across VitePress upgrades
  • ➕ Reduces risk of styling regressions in nav/sidebar/content
  • ➖ May not fully preserve the current brand look-and-feel
  • ➖ Still requires some customization for UI elements like reading progress
3. Fix problematic markdown patterns in-content instead of preprocessing
  • ➕ Eliminates a build-time transformation layer (simpler mental model)
  • ➕ Less chance of escaping affecting edge-case rendering
  • ➖ Touches many documentation files and increases churn
  • ➖ Harder to guarantee no semantic changes to docs content

Recommendation: The chosen approach (VitePress + targeted markdown preprocessing + custom theme) is the best fit given the explicit goals: reduce dependencies, preserve styling, and avoid modifying docs content. The preprocessor is justified as a compatibility shim for existing brace/tag patterns that would otherwise break Vue SFC compilation; alternatives either increase content churn or sacrifice the dependency reduction objective.

Files changed (8) +576 / -36

Enhancement (4) +550 / -0
config.tsAdd VitePress site config, sidebar, and markdown escaping hooks +296/-0

Add VitePress site config, sidebar, and markdown escaping hooks

• Define VitePress configuration (base URL, rewrites, head tags, exclusions, nav/sidebar) including dynamic sidebar generation by scanning markdown files. Add markdown preprocessing to escape Vue-incompatible syntax outside code fences and force 'v-pre' on inline code spans to prevent template compilation errors.

website/.vitepress/config.ts

ReadingProgress.vueImplement reading progress bar in Vue +23/-0

Implement reading progress bar in Vue

• Port the reading progress UI from the former React component to a Vue component using scroll listeners and a reactive width percentage.

website/.vitepress/theme/components/ReadingProgress.vue

custom.cssRecreate Fullsend docs styling in VitePress theme CSS +217/-0

Recreate Fullsend docs styling in VitePress theme CSS

• Add brand color variables and typography overrides, plus custom styling for navbar translucency, animated link underlines, code block rounding, table hover effects, sidebar active indicator, and the reading progress bar.

website/.vitepress/theme/custom.css

index.tsWire custom theme and inject ReadingProgress into layout +14/-0

Wire custom theme and inject ReadingProgress into layout

• Extend the default VitePress theme, load custom CSS, and render the ReadingProgress component in the layout top slot.

website/.vitepress/theme/index.ts

Documentation (1) +6 / -0
index.mdAdd docs root redirect page +6/-0

Add docs root redirect page

• Introduce a docs landing page that immediately redirects to the Getting Started guide, replacing the prior root routing behavior from Docusaurus.

docs/index.md

Other (3) +20 / -36
site-build.ymlDeploy docs from VitePress output directory +1/-1

Deploy docs from VitePress output directory

• Switch the bundled docs artifact path from 'website/build/' (Docusaurus) to 'website/dist/' (VitePress). Keeps the existing Cloudflare deploy bundling flow intact.

.github/workflows/site-build.yml

package.jsonReplace Docusaurus dependencies and scripts with VitePress + Vue +6/-32

Replace Docusaurus dependencies and scripts with VitePress + Vue

• Remove Docusaurus/React/MDX dependencies and CLI scripts, add VitePress/Vue dependencies, and update scripts to 'vitepress dev/build/preview'. Mark the package as ESM via 'type: module'.

website/package.json

tsconfig.jsonReplace Docusaurus tsconfig extension with VitePress-compatible TS config +13/-3

Replace Docusaurus tsconfig extension with VitePress-compatible TS config

• Drop the '@docusaurus/tsconfig' extension and define explicit compiler options suitable for Vite/VitePress. Limit TS include paths to '.vitepress' sources (TS + Vue SFCs).

website/tsconfig.json

@waynesun09
waynesun09 force-pushed the docusaurus-migration branch from ca03958 to a722f0e Compare June 27, 2026 17:55
@DaoDaoNoCode
DaoDaoNoCode force-pushed the migrate-docs-vitepress branch from c17cf18 to fe2e0e2 Compare June 27, 2026 17:56
@qodo-code-review

qodo-code-review Bot commented Jun 27, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 51 rules

Grey Divider


Action required

1. Indented fences corrupted 🐞 Bug ≡ Correctness
Description
escapeVueSyntax() only detects fenced code blocks when the fence starts at column 0, so indented
fences (common inside lists) are treated as normal text and get {} escaped. This corrupts code
blocks (e.g., JSON snippets) by rendering &#123; literally in <code> output instead of {.
Code

website/.vitepress/config.ts[R29-47]

+function escapeVueSyntax(src: string): string {
+  const lines = src.split('\n')
+  let fenceLen = 0
+  return lines.map(line => {
+    const fenceMatch = line.match(/^(`{3,})/)
+    if (fenceMatch) {
+      if (fenceLen === 0) {
+        fenceLen = fenceMatch[1].length
+        return line
+      }
+      if (fenceMatch[1].length >= fenceLen && line.trim() === fenceMatch[0]) {
+        fenceLen = 0
+        return line
+      }
+      return line
+    }
+    if (fenceLen > 0) return line
+    return escapeLine(line)
+  }).join('\n')
Relevance

⭐⭐ Medium

No historical evidence for indented-fence handling/escapeVueSyntax; VitePress site code is new in
this repo.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The preprocessor uses a start-of-line-only fence regex, but the docs include indented fenced code
blocks containing braces (JSON). Those braces will be escaped because the fence isn’t recognized as
a fence, and in code blocks the & in &#123; will be HTML-escaped, causing literal &#123; to
appear.

website/.vitepress/config.ts[29-47]
docs/guides/infrastructure/infrastructure-reference.md[100-115]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`escapeVueSyntax()` fails to detect indented fenced code blocks (e.g. list-item code fences like `  ```json`). As a result, code-block contents are passed through `escapeLine()`, which replaces `{`/`}` with HTML entities. Inside fenced code blocks, markdown-it typically escapes `&` to `&amp;`, so the docs render the entity text (e.g. `&#123;`) instead of braces.

### Issue Context
- Many docs contain indented fences and JSON bodies.
- Fix should follow CommonMark: fenced blocks may be indented up to 3 spaces.

### Fix Focus Areas
- website/.vitepress/config.ts[29-47]

### Suggested fix approach
- Update fence detection to allow up to 3 leading spaces: e.g. `line.match(/^\s{0,3}(`{3,})/)`.
- When closing a fence, allow leading/trailing whitespace and allow fence length >= opening fence length.
- Consider also supporting `~~~` fences if they might exist in future (optional).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Sidebar misses nested READMEs 🐞 Bug ⚙ Maintainability
Description
getMarkdownFiles() only lists non-README .md files in a single directory and does not recurse, but
it is used for sections that contain README-only nested directories. This results in empty or
incomplete sidebar sections (e.g., Experiments), making those pages undiscoverable via navigation.
Code

website/.vitepress/config.ts[R9-24]

+function getMarkdownFiles(dir: string, base: string): { text: string; link: string }[] {
+  const fullDir = path.resolve(docsDir, dir)
+  if (!fs.existsSync(fullDir)) return []
+  return fs.readdirSync(fullDir)
+    .filter(f => f.endsWith('.md') && f !== 'README.md')
+    .sort()
+    .map(f => {
+      const slug = f.replace(/\.md$/, '')
+      const filePath = path.resolve(fullDir, f)
+      const content = fs.readFileSync(filePath, 'utf-8')
+      const fmTitleMatch = content.match(/^title:\s*["']?(.+?)["']?\s*$/m)
+      const titleMatch = content.match(/^#\s+(.+)$/m)
+      const text = fmTitleMatch?.[1] || titleMatch?.[1] || slug
+      return { text, link: `/${base}/${slug}` }
+    })
+}
Relevance

⭐⭐ Medium

No repo history for VitePress config path; only indirect evidence team tweaks sidebar generation
behavior (PR #2666).

PR-#2666

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The generator explicitly filters out README.md and never traverses subdirectories, but the repo
contains nested README-only doc sections that would therefore produce no sidebar entries even though
the pages exist.

website/.vitepress/config.ts[9-24]
website/.vitepress/config.ts[212-246]
docs/superpowers/experiments/oauth-localhost-part-b/README.md[1-25]
docs/problems/applied/README.md[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`getMarkdownFiles()` only reads one directory level and excludes `README.md`. For doc sections organized as directories with `README.md` (and sometimes deeper nesting), this yields empty or incomplete sidebar item lists.

### Issue Context
Examples in this repo:
- `docs/superpowers/experiments/` contains only a subdirectory with `README.md`.
- `docs/problems/applied/` is a nested README-only section.

### Fix Focus Areas
- website/.vitepress/config.ts[9-24]
- website/.vitepress/config.ts[212-246]

### Suggested fix approach
- Make `getMarkdownFiles()` recursive using `fs.readdirSync(fullDir, { withFileTypes: true })`.
- Include directories by detecting `README.md` and mapping it to the directory index route (e.g. `/superpowers/experiments/oauth-localhost-part-b/`).
- Optionally construct nested `items` groups for subdirectories so the sidebar preserves hierarchy.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Deployment doc now stale ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The build artifact now copies docs from website/dist, but docs/site-deployment.md still documents
Docusaurus and website/build as the output and copy source. This will mislead anyone following the
documented local deploy/build steps.
Code

.github/workflows/site-build.yml[R49-52]

          mkdir -p _bundle/public/admin
          cp -a web/dist/admin/. _bundle/public/admin/
          mkdir -p _bundle/public/docs
-          cp -a website/build/. _bundle/public/docs/
+          cp -a website/dist/. _bundle/public/docs/
Relevance

⭐⭐⭐ High

Team often fixes doc drift when build/deploy layout changes (accepted similar updates in PR #242,
#1936).

PR-#242
PR-#1936

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
CI now bundles website/dist, while the deployment guide still instructs users to copy from
website/build and refers to Docusaurus, which no longer exists in website/package.json
scripts/dependencies.

.github/workflows/site-build.yml[37-54]
docs/site-deployment.md[5-83]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`docs/site-deployment.md` still describes the docs site as Docusaurus-built outputting to `website/build/`, but the repo now builds with VitePress and outputs to `website/dist/`.

### Issue Context
This PR changes the CI bundle copy step to use `website/dist`, but the deployment guide still references `website/build` (including a copy command).

### Fix Focus Areas
- .github/workflows/site-build.yml[49-52]
- docs/site-deployment.md[5-83]

### Suggested fix approach
- Replace Docusaurus mentions with VitePress.
- Replace `website/build/` references and copy commands with `website/dist/`.
- Ensure the local preview instructions match the new `website/package.json` scripts (`vitepress dev/build/preview`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment on lines +29 to +47
function escapeVueSyntax(src: string): string {
const lines = src.split('\n')
let fenceLen = 0
return lines.map(line => {
const fenceMatch = line.match(/^(`{3,})/)
if (fenceMatch) {
if (fenceLen === 0) {
fenceLen = fenceMatch[1].length
return line
}
if (fenceMatch[1].length >= fenceLen && line.trim() === fenceMatch[0]) {
fenceLen = 0
return line
}
return line
}
if (fenceLen > 0) return line
return escapeLine(line)
}).join('\n')

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Indented fences corrupted 🐞 Bug ≡ Correctness

escapeVueSyntax() only detects fenced code blocks when the fence starts at column 0, so indented
fences (common inside lists) are treated as normal text and get {} escaped. This corrupts code
blocks (e.g., JSON snippets) by rendering &#123; literally in <code> output instead of {.
Agent Prompt
### Issue description
`escapeVueSyntax()` fails to detect indented fenced code blocks (e.g. list-item code fences like `  ```json`). As a result, code-block contents are passed through `escapeLine()`, which replaces `{`/`}` with HTML entities. Inside fenced code blocks, markdown-it typically escapes `&` to `&amp;`, so the docs render the entity text (e.g. `&#123;`) instead of braces.

### Issue Context
- Many docs contain indented fences and JSON bodies.
- Fix should follow CommonMark: fenced blocks may be indented up to 3 spaces.

### Fix Focus Areas
- website/.vitepress/config.ts[29-47]

### Suggested fix approach
- Update fence detection to allow up to 3 leading spaces: e.g. `line.match(/^\s{0,3}(`{3,})/)`.
- When closing a fence, allow leading/trailing whitespace and allow fence length >= opening fence length.
- Consider also supporting `~~~` fences if they might exist in future (optional).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch, fixed. Updated the regex to /^ {0,3}({3,}|~{3,})/` so it handles indented fences (up to 3 spaces per CommonMark) and tilde fences. Also tracks the fence character type so a backtick fence can only be closed by backticks, not tildes.

@DaoDaoNoCode
DaoDaoNoCode force-pushed the migrate-docs-vitepress branch 2 times, most recently from 71c738f to c04335e Compare June 27, 2026 18:03
@waynesun09

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Jun 27, 2026

Copy link
Copy Markdown

🤖 Finished Review · ❌ Failure · Started 6:07 PM UTC · Completed 6:08 PM UTC
Commit: 7f5ce3c · View workflow run →

@DaoDaoNoCode
DaoDaoNoCode force-pushed the migrate-docs-vitepress branch from c04335e to a6d0a34 Compare June 27, 2026 18:09
@DaoDaoNoCode

Copy link
Copy Markdown
Contributor Author

/fs-review

@DaoDaoNoCode
DaoDaoNoCode force-pushed the migrate-docs-vitepress branch 3 times, most recently from 949fa06 to bcc1648 Compare June 27, 2026 18:21
@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown

Site preview

Preview: https://7d28eabc-site.fullsend-ai.workers.dev

Commit: 7f59e9c6c7b5efa7eed17edec2b21a301a1de0b0

Replace Docusaurus with VitePress for the docs site at /docs/.

- VitePress config with full sidebar matching the original structure
- Dynamic sidebar generation for ADRs, specs, plans, and experiments
- Custom theme preserving all visual styling (brand colors, gradient
  headings, frosted navbar, animated links, code block rounding,
  reading progress bar)
- ReadingProgress component migrated from React to Vue
- Markdown preprocessor to escape Vue-incompatible syntax ({}, {{}},
  <PLACEHOLDER> tags) in docs without modifying content files
- Inline code v-pre fix per VitePress maintainer recommendation
- README.md to index.md rewrites for clean URLs
- CI workflow updated: website/build to website/dist
- Static assets moved to docs/public/img/
- Updated site-deployment.md references

No documentation content was modified.

Signed-off-by: Juntao Wang <juntwang@redhat.com>
@DaoDaoNoCode
DaoDaoNoCode force-pushed the migrate-docs-vitepress branch from ce5b80a to 7f59e9c Compare June 27, 2026 18:48
@waynesun09
waynesun09 merged commit 6e09255 into fullsend-ai:docusaurus-migration Jun 27, 2026
8 checks passed
@fullsend-ai-retro

fullsend-ai-retro Bot commented Jun 27, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 7:05 PM UTC · Completed 7:12 PM UTC
Commit: 7f59e9c · View workflow run →

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #2721 — Docusaurus to VitePress migration

Timeline: Human-authored PR by DaoDaoNoCode migrating the docs site from Docusaurus to VitePress (~576 lines changed + lockfile). qodo-code-review[bot] reviewed at 17:59Z and caught two real bugs (indented fence detection, nested README sidebar). waynesun09 invoked /fs-review at 18:04Z; the review agent dispatched but failed at step 11 after ~4 minutes (run 28297397224). DaoDaoNoCode then invoked /fs-review again at 18:10Z, but no dispatch occurred and no feedback was posted — the request was silently dropped. The PR was merged at 19:01Z with only qodo and human review.

What went well:

  • qodo-code-review caught a legitimate bug (indented fence handling) that the author fixed promptly
  • The review failure on the first attempt was surfaced clearly via the bot status comment
  • The PR was well-structured with a thorough description and test plan

Proposals: 1 filed (see below). Several other potential improvements were already covered by existing issues:

  • Auto re-dispatch after failure: #2711
  • Two-pass strategy for large PRs: #2096
  • Filter vendor/generated diffs: #2171
  • Skip retro for human PRs with no agent involvement: #2708
  • Dispatch shim feedback for /fs-fix: #1920 (related but scoped to /fs-fix only)

Proposals filed

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.

2 participants