Docship Theme Development Checklist

⚠️ Critical Rules

No Advertisements Policy

  • NEVER use any theme or plugin that contains ads

  • Some official themes (e.g., @vuepress/theme-vue) contain sponsor/advertisement content - DO NOT USE

  • Always check if theme contains ads, sponsor links, or donation prompts before using

  • When in doubt, use the framework’s default theme

Known themes/plugins with ads (DO NOT USE):

Framework

Theme/Plugin

Issue

VuePress

@vuepress/theme-vue

Contains sponsor/advertisement content

Recommended ad-free alternatives:

Framework

Recommended Theme

VuePress

Default theme (built-in @vuepress/theme-default)

User Content Respect

  • Never restrict user filenames (e.g., index.md, temp.md are all valid)

  • User markdown content must never break builds regardless of validity

  • Invalid image paths, links, etc. should be ignored, not cause errors

Markdown Compatibility

  • [ ] Use markdown.format: 'md' instead of MDX to avoid JSX parsing errors (Docusaurus)

    • Users may have ${}, <>, {} in their markdown content

    • MDX will treat these as JSX expressions and fail

  • [ ] VitePress is more lenient with ${} but double curly braces will be treated as Vue template

  • [ ] Don’t restrict filenames - users can use any name like temp.md

  • [ ] Handle files with special characters in content gracefully

Docusaurus Configuration

  • [ ] Don’t use navbar.logo without logo.src - it will throw validation error

  • [ ] Remove sidebarPath to let Docusaurus auto-generate sidebar from file structure

  • [ ] Use onBrokenLinks: 'ignore' to prevent build failures on broken links

  • [ ] Use markdown.hooks.onBrokenMarkdownLinks: 'ignore' (new location in v3.9+)

  • [ ] Don’t include deprecated options like root-level onBrokenMarkdownLinks

  • [ ] For local search, use @easyops-cn/docusaurus-search-local (no API key needed)

  • [ ] Algolia search requires API key - not suitable for generic themes

VitePress Configuration

  • [ ] Use ignoreDeadLinks: true to prevent build failures on broken/dead links

  • [ ] VitePress does NOT auto-generate sidebar - need custom script or manual config

  • [ ] sidebar: 'auto' does NOT work like Docusaurus - only shows current page headings

  • [ ] Output directory is .vitepress/dist (not build)

  • [ ] Use srcDir: 'docs' to specify source directory

  • [ ] Exclude node_modules in content backup

  • [ ] For local search, use search: { provider: 'local' } (built-in)

  • [ ] logo.link does NOT support external URLs - need custom theme to override

Homepage Selection Logic

Priority order:

  1. docs/index.md or content/index.md - explicit homepage

  2. docs/README.md or content/README.md - common convention

  3. First .md file (sorted alphabetically) - fallback

  • [ ] Always use sort before head -1 for consistent results

  • [ ] For Docusaurus: check if slug: / already exists before adding frontmatter

  • [ ] For VitePress: index.md is automatically the homepage, no frontmatter needed

GitHub Actions / Reusable Workflows

  • [ ] Reusable workflows MUST be in .github/workflows/ directory

  • [ ] Use on: workflow_call for workflows that should only be called by others

  • [ ] Caller workflow must declare permissions for the called workflow to use

  • [ ] Remove push and workflow_dispatch triggers if workflow should not run directly

Content Backup

  • [ ] Exclude README.md from root (usually not documentation)

  • [ ] Exclude hidden directories (.git, .github, etc.)

  • [ ] Exclude node_modules directory

  • [ ] Copy all user folders to preserve structure

  • [ ] Handle empty content directory - create default welcome page

Build & Deploy

  • [ ] GitHub Pages keeps old version online during build (atomic deployment)

  • [ ] First deployment shows blank page until complete - this is normal

  • [ ] Public repos have unlimited GitHub Actions minutes

  • [ ] Add npm cache to speed up builds: actions/cache@v4 with ~/.npm path

Shell Script Best Practices (GitHub Actions)

  • [ ] Don’t use sed -i '1s/^/...\n.../' - \n may not work on all systems

  • [ ] Don’t use heredoc (<< EOF) inside YAML run: blocks - causes syntax errors

  • [ ] Use printf '%s\n' 'line1' 'line2' for multi-line content

  • [ ] Use temp files + cat + mv to prepend content to files

  • [ ] Always quote variables: "$TARGET" not $TARGET

Logo & Branding

  • [ ] Use https://github.com/USERNAME.png to get user/org avatar

  • [ ] VitePress: need custom theme (enhanceApp) to make logo link to external URL

  • [ ] Docusaurus: logo.href + logo.target: '_blank' works for external links

  • [ ] Set favicon with head: [['link', { rel: 'icon', href: '...' }]] (VitePress)

  • [ ] Docusaurus favicon can be external URL directly

Testing Scenarios

Before releasing a theme, test with:

  • [ ] Empty repository (no markdown files)

  • [ ] Single markdown file

  • [ ] Nested folder structure

  • [ ] Files with ${} syntax in content

  • [ ] Files with JSX-like syntax <Component />

  • [ ] Files with curly braces {}

  • [ ] Files with Vue template syntax (VitePress specific)

  • [ ] Unicode/special characters in filenames

  • [ ] Very long filenames

  • [ ] Files starting with _ (usually ignored by default)

  • [ ] Files containing localhost URLs (dead link check)

  • [ ] Repository without index.md (homepage fallback logic)

Starlight (Astro) Configuration

  • [ ] Use npm create astro@latest -- --template starlight for correct project structure

  • [ ] Starlight v0.33.0+ changed social config from object to array format

    • Old: social: { github: 'url' }

    • New: social: [{ icon: 'github', label: 'GitHub', href: 'url' }]

  • [ ] Every .md file MUST have title in frontmatter - Starlight will fail without it

  • [ ] Sidebar slug must be lowercase - uppercase will cause “slug does not exist” error

  • [ ] autogenerate: { directory: '.' } doesn’t work well - use specific directory names

  • [ ] Content goes in src/content/docs/ directory

  • [ ] Output directory is dist

  • [ ] Use .mdx extension for index file if needed

Rspress Configuration

  • [ ] Public assets go in docs/public/ (not project root public/)

  • [ ] Sidebar items must be an array, not 'auto' string

  • [ ] Output directory is doc_build

  • [ ] Exclude public directory from sidebar generation

  • [ ] Config file is rspress.config.ts (TypeScript)

Common Errors & Solutions

Error

Cause

Solution

navbar.logo.src is required

Using logo without src

Remove logo or add src

Could not parse expression with acorn

MDX parsing ${} as JSX

Use markdown.format: 'md'

workflow is not reusable

Missing workflow_call trigger

Add on: workflow_call

requesting pages: write but only allowed none

Caller missing permissions

Add permissions to caller

onBrokenMarkdownLinks deprecated

Old config location

Move to markdown.hooks

Found dead link (VitePress)

Broken links in markdown

Use ignoreDeadLinks: true

sidebar: 'auto' not working

VitePress doesn’t auto-generate

Write custom sidebar script

Page Not Found on homepage

Missing slug: / frontmatter

Add frontmatter to first doc

here-document delimited by end-of-file

Heredoc in YAML run block

Use printf instead

social: Expected array, received object

Starlight v0.33.0+ API change

Use array format for social links

title: Required (Starlight)

Missing frontmatter title

Auto-add title from filename

slug does not exist (Starlight)

Uppercase slug in sidebar

Convert slug to lowercase

Entry docs 404 was not found

No valid index page

Ensure index.md/mdx exists with frontmatter

item.items.map is not a function

Rspress sidebar items: 'auto'

Use array of items, not string

Failed to read favicon (Rspress)

Wrong public directory path

Put assets in docs/public/

Module not found: Can't resolve './assets/...'

Invalid image path in markdown

Set remarkImageOptions: false (Fumadocs) or staticImage: false (Nextra)

Unrecognized keys: "theme", "themeConfig"

Nextra v4 API changed

Use new nextra() config format

Export doesn't exist in target module

Simplified source.ts missing exports

Delete files that depend on removed exports (e.g., app/og, app/llms-full.txt)

fatal: No url found for submodule path

Downloaded repo folder treated as submodule

Add folder to .gitignore or git rm -r --cached folder

shallow cloned, latest modified time not presented

GitHub Actions shallow clone

Warning only, can ignore or use fetch-depth: 0

InvalidTocFile: not a valid TOC File (DocFX)

Empty or malformed toc.yml

Delete invalid toc.yml from subdirectories

Logo/favicon not showing (DocFX)

External URL in _appLogoPath/_appFaviconPath

Use custom template JS to inject external URLs

Homepage 404 (VuePress)

Using index.md instead of README.md

Rename index.md to README.md

sidebar: 'auto' not showing files (VuePress)

VuePress auto only shows headings

Generate sidebar config via Node.js script

Theme has ads/sponsors (VuePress)

Using @vuepress/theme-vue

Use default theme (built-in, no ads)

Prerendered 5 routes only (Docus)

Nuxt can’t crawl to doc pages

Add routes to nitro.prerender.routes

404 on /docs/CHECKLIST (Docus)

Uppercase filename in route

Convert routes to lowercase

Blank page on root (Docus)

index file without .html

Create index.html redirect after build

@nuxtjs/mcp-toolkit not compatible (Docus)

MCP needs server

Warning only, can ignore

robots.txt with base URL error (Docus)

robots module conflict

Set robots: { robotsTxt: false }

No sidebar on homepage (Docus)

content/index.md is landing page

Put docs in content/1.docs/ subdirectory

Fumadocs Configuration

  • [ ] Fumadocs is based on Next.js - requires output: 'export' for static build

  • [ ] Use basePath for GitHub Pages deployment (e.g., /${REPO_NAME})

  • [ ] Set images: { unoptimized: true } for static export

  • [ ] Content goes in content/docs/ directory

  • [ ] Output directory is out (Next.js static export default)

  • [ ] Every .mdx file should have frontmatter with title and description

  • [ ] Use create-fumadocs-app with --template +next+fuma-docs-mdx+static for static export

  • [ ] Fumadocs MDX is the official content source

  • [ ] Config file is next.config.mjs (ESM)

  • [ ] Requires fumadocs-mdx/next plugin wrapper

  • [ ] Set remarkImageOptions: false in source.config.ts to prevent build failures from invalid image paths

  • [ ] Delete app/llms-full.txt and app/og directories (they depend on exports not in simplified source.ts)

  • [ ] Clear template’s default content/docs/* before copying user content (removes Hello World page)

Nextra Configuration

  • [ ] Nextra v4 uses App Router - structure is src/app/ and src/content/

  • [ ] Requires output: 'export' and images: { unoptimized: true } for static build

  • [ ] Use basePath via environment variable for GitHub Pages

  • [ ] Content goes in src/content/ directory

  • [ ] Output directory is out

  • [ ] Need mdx-components.js at project root for MDX components

  • [ ] Use nextra-theme-docs for documentation theme

  • [ ] Config uses nextra() wrapper with contentDirBasePath option

  • [ ] Homepage redirect to /docs since content is under /docs route

  • [ ] Nextra uses MDX - user content with ${}, <>, {} may cause JSX parsing errors

  • [ ] Set staticImage: false to prevent build failures from invalid image paths

VuePress Configuration

  • [ ] VuePress 1.x is Vue 2 based - use vuepress@^1.9.10

  • [ ] ⚠️ DO NOT USE @vuepress/theme-vue - it contains sponsor/advertisement content

  • [ ] Use default theme @vuepress/theme-default (built-in, no ads)

  • [ ] Content goes in docs/ directory

  • [ ] Output directory is docs/.vuepress/dist

  • [ ] Config file is docs/.vuepress/config.js

  • [ ] Use base: '/${REPO_NAME}/' for GitHub Pages subdirectory

  • [ ] themeConfig.logo supports external URLs directly

  • [ ] themeConfig.sidebar: 'auto' only shows current page headings - need Node.js script for full sidebar

  • [ ] Homepage is docs/README.md (not index.md) - must rename index.md to README.md

  • [ ] Use themeConfig.repo for GitHub link in navbar

  • [ ] Custom styles go in docs/.vuepress/styles/index.styl (Stylus)

  • [ ] Use enhanceApp.js for client-side customizations (e.g., footer injection)

  • [ ] Favicon via head: [['link', { rel: 'icon', href: 'URL' }]] - supports external URLs

  • [ ] VuePress uses Vue template syntax - double curly braces in markdown will be parsed as Vue expressions

  • [ ] Use @vuepress/plugin-back-to-top for back-to-top button (built-in plugin)

  • [ ] VuePress 1.x does NOT have native dark mode toggle - custom implementation is complex

  • [ ] Green scrollbar: apply only to .sidebar selector, not whole page

DocFX Configuration

  • [ ] DocFX is a .NET-based documentation framework - uses dotnet tool install -g docfx

  • [ ] Content goes in docs/ directory

  • [ ] Output directory is _site

  • [ ] Config file is docfx.json

  • [ ] Uses toc.yml for navigation structure (root for navbar, docs/ for sidebar)

  • [ ] _appLogoPath and _appFaviconPath do NOT support external URLs - need custom template

  • [ ] Use custom template with JavaScript to inject external avatar as logo/favicon

  • [ ] Remove root toc.yml to hide navbar tabs (e.g., “Docs” tab) when only one section

  • [ ] Use redirect_url frontmatter in index.md to redirect homepage to docs

  • [ ] Set _disableContribution: true to hide “Edit this page” link

  • [ ] Set _appFooter to customize or remove footer

  • [ ] Sidebar toc.yml format: - name: Title + href: file.md

  • [ ] Delete invalid toc.yml files from user content subdirectories

  • [ ] Exclude framework source folders in backup (fumadocs/, nextra/, docute/, etc.)

Docute Configuration

  • [ ] Docute is a pure frontend framework - no build process needed

  • [ ] Only needs index.html + markdown files

  • [ ] Uses CDN for docute.js and docute.css (unpkg.com/docute@4)

  • [ ] URL routing: / => /README.md, /foo => /foo.md, /foo/ => /foo/README.md

  • [ ] Sidebar must be manually configured or auto-generated via script

  • [ ] Logo is a Vue template string - use <span> wrapper with flex layout for avatar + text

  • [ ] Use darkThemeToggler: true for dark mode toggle

  • [ ] No npm cache needed since no build process

mdBook Configuration

  • [ ] mdBook is a Rust-based documentation tool - install via pre-built binary or cargo install mdbook

  • [ ] Content goes in src/ directory

  • [ ] Output directory is book/

  • [ ] Config file is book.toml (TOML format)

  • [ ] Requires src/SUMMARY.md to define table of contents structure

  • [ ] Homepage is src/README.md (linked as [Introduction](README.md) in SUMMARY.md)

  • [ ] SUMMARY.md format: - [Title](path/to/file.md) for chapters

  • [ ] Use # headers in SUMMARY.md to create section separators

  • [ ] [output.html] section in book.toml for HTML output settings

  • [ ] site-url in book.toml for base path (GitHub Pages subdirectory)

  • [ ] Custom theme via theme/ directory - can override index.hbs, head.hbs, CSS files

  • [ ] Favicon and logo require custom theme modifications (no direct config option)

  • [ ] Built-in themes: light, rust, coal, navy, ayu

  • [ ] default-theme and preferred-dark-theme in [output.html] section

  • [ ] Supports MathJax via mathjax-support = true

  • [ ] Built-in search functionality (no additional config needed)

Eleventy Configuration

  • [ ] Eleventy (11ty) is a JavaScript-based static site generator

  • [ ] Install via npm install @11ty/eleventy

  • [ ] Config file is eleventy.config.js or .eleventy.js

  • [ ] Default input directory is . (project root)

  • [ ] Default output directory is _site

  • [ ] Supports multiple template languages: Liquid, Nunjucks, Markdown, HTML, JavaScript

  • [ ] Use dir.input and dir.output in config to customize directories

  • [ ] Use pathPrefix for GitHub Pages subdirectory deployment

  • [ ] Layouts go in _includes/ directory by default

  • [ ] Data files go in _data/ directory (JSON, JS, or YAML)

  • [ ] Use frontmatter layout to specify template layout

  • [ ] Collections are auto-generated from tags or can be custom defined

  • [ ] Use eleventyConfig.addPassthroughCopy() for static assets

  • [ ] Markdown files need frontmatter with layout to use templates

  • [ ] No built-in theme - requires custom CSS/layout

Sphinx Configuration

  • [ ] Sphinx is a Python-based documentation generator

  • [ ] Install via pip install sphinx furo myst-parser

  • [ ] Config file is conf.py (Python)

  • [ ] Default source directory is docs/ or project root

  • [ ] Default output directory is _build/html/

  • [ ] Use myst-parser extension to support Markdown (default is reStructuredText)

  • [ ] Furo is a modern, clean theme (BSD license)

  • [ ] Use toctree directive to define navigation structure

  • [ ] html_theme = 'furo' to use Furo theme

  • [ ] html_logo and html_favicon for branding

  • [ ] html_theme_options for theme customization

  • [ ] Custom CSS goes in _static/ directory

  • [ ] Build with sphinx-build -b html docs docs/_build/html

  • [ ] License is BSD (Sphinx) + MIT (Furo) - very permissive

Docus Configuration

  • [ ] Docus is a Nuxt 4-based documentation framework (MIT license)

  • [ ] Install via npm install docus nuxt better-sqlite3

  • [ ] Config file is nuxt.config.ts with extends: ['docus']

  • [ ] Content goes in content/ directory with number prefixes for ordering (e.g., 1.docs/, 2.guide/)

  • [ ] Output directory is .output/public/

  • [ ] Use nuxt generate for static build

  • [ ] Homepage is special - content/index.md renders as landing page without sidebar

  • [ ] Documentation pages need subdirectory - put docs in content/1.docs/ to get sidebar layout

  • [ ] Number prefixes in filenames control order: 1.index.md, 2.guide.md/index, /guide

  • [ ] Use .navigation.yml in directories to set section titles

  • [ ] Frontmatter title is required for each page

  • [ ] app.config.ts goes in app/ directory for theme configuration

  • [ ] header.title and header.logo for branding

  • [ ] socials.github for GitHub link in header

  • [ ] Custom components override defaults - put in app/components/app/

  • [ ] AppHeaderLogo.vue - customize logo + title display

  • [ ] AppFooterLeft.vue - customize footer left (attribution)

  • [ ] AppFooterRight.vue - customize footer right (social icons, theme toggle)

  • [ ] Set empty AppFooterRight.vue to remove duplicate theme toggle

  • [ ] Logo click should link to /docs not / (override AppHeaderLogo.vue with <NuxtLink to="/docs">)

  • [ ] Favicon via app.head.link in nuxt.config.ts

  • [ ] Prerendering issue: Nuxt only prerenders routes it can crawl from homepage

  • [ ] Must explicitly list routes in nitro.prerender.routes or generate dynamically

  • [ ] Convert filenames to lowercase for routes (uppercase causes 404)

  • [ ] Create index.html redirect after build for root → /docs

  • [ ] robots: { robotsTxt: false } to avoid base URL error

  • [ ] @nuxtjs/mcp-toolkit warning is normal - not compatible with static generate

General Lessons Learned

Framework Categories

  1. Build-required frameworks (need npm install + build):

    • Docusaurus, VitePress, Starlight, Rspress, Fumadocs, Nextra

    • Need npm cache for faster builds

    • Output to specific directories (build/, dist/, out/, doc_build/)

  2. Pure frontend frameworks (no build, CDN-based):

    • Docsify, Docute

    • Just HTML + markdown files

    • Faster deployment, simpler setup

  3. Next.js-based frameworks:

    • Fumadocs, Nextra

    • Require output: 'export' for static build

    • Require images: { unoptimized: true } for static export

    • Use basePath for GitHub Pages subdirectory

Common Pitfalls

  • [ ] Image handling: MDX/Next.js frameworks try to import images - disable with remarkImageOptions: false or staticImage: false

  • [ ] Template default content: Many templates include “Hello World” or demo content - clear before copying user content

  • [ ] CLI argument changes: Framework CLIs change frequently - check latest docs (e.g., create-fumadocs-app changed from --name --template --src to --template +next+fuma-docs-mdx+static)

  • [ ] API version changes: Check for breaking changes (e.g., Starlight social config changed from object to array)

  • [ ] Sidebar in sidebar: Some frameworks show index page in sidebar - use index: true frontmatter to hide it

Branding Consistency

For all frameworks, implement:

  • [ ] Logo: User avatar + username/reponame in top-left

  • [ ] Favicon: User’s GitHub avatar (https://github.com/USERNAME.png)

  • [ ] GitHub link: Icon or text link to repository (right side of navbar)

  • [ ] Title: username/reponame in browser tab

  • [ ] Footer: Powered by NekoTick · {Framework} with links to both projects

Logo Implementation Patterns

Framework

Logo Config

Docusaurus

navbar.logo.src + navbar.title

VitePress

themeConfig.logo + themeConfig.siteTitle

Fumadocs

nav.title as JSX with <img> + <span>

Nextra

Navbar logo prop as JSX

Docute

logo as Vue template string

DocFX

Custom template JS to replace #logo element

VuePress

themeConfig.logo (external URL supported)

Starlight

logo.src + title

Docus

Custom AppHeaderLogo.vue with <NuxtLink> + <UColorModeImage> + <span>

Hugo

params.BookLogo in hugo.yaml (external URL supported)

Testing Checklist (Updated)

  • [ ] Files with invalid image paths (should not break build)

  • [ ] Files with special markdown syntax (${}, <>, {})

  • [ ] Empty repository (should show welcome page)

  • [ ] Nested folder structure (should generate proper sidebar)

  • [ ] Repository without index.md (should use first doc as homepage)

Multi-Language Support

  • [ ] VitePress/Docusaurus i18n is static - requires manual translation files

  • [ ] No automatic translation built-in

  • [ ] Options: browser translation, or integrate translation API (costs money)

  • [ ] Structure: docs/en/, docs/zh/ etc. for each language

Adding New Framework

When adding a new documentation framework to Docship:

1. Create Workflow File

  • [ ] Create .github/workflows/{framework}.yml

  • [ ] Use on: workflow_call with base_path_suffix and deploy inputs

  • [ ] Follow existing workflow structure for consistency

3. Update Showcase

  • [ ] Add build job in showcase.yml with name: {framework}

  • [ ] Add to needs array in combine job

  • [ ] Add build result env variable (e.g., BUILD_FRAMEWORK)

  • [ ] Add to RESULTS array in combine step

  • [ ] Add entry in showcase/frameworks.json with GitHub link(s)

frameworks.json format:

{
  "framework-name": {
    "links": ["https://github.com/org/repo"]
  },
  "framework-with-theme": {
    "links": ["https://github.com/org/framework", "https://github.com/org/theme"]
  }
}

4. Update Documentation

  • [ ] Add framework to README.md supported frameworks table

  • [ ] Add framework-specific notes to CHECKLIST.md if needed