Skip to main content

Plugin API Reference

Complete reference documentation for creating Doom plugins.

RspressPlugin Interface

All Doom plugins implement the RspressPlugin interface from @rspress/core:
import type { RspressPlugin } from '@rspress/core'

export interface RspressPlugin {
  name: string
  config?(config: UserConfig, utils: ConfigUtils): UserConfig | Promise<UserConfig>
  markdown?: MarkdownOptions
  addRuntimeModules?(config: UserConfig, isProd: boolean): Record<string, string> | Promise<Record<string, string>>
  addPages?(config: UserConfig): PageOptions[] | Promise<PageOptions[]>
  globalStyles?: string
  globalUIComponents?: string[]
}

Properties

name

Type: string Required: Yes Unique identifier for the plugin. Used for plugin management and debugging.
name: 'my-plugin'

config

Type: (config: UserConfig, utils: ConfigUtils) => UserConfig | Promise<UserConfig> Required: No Modify the user configuration before the build starts. Parameters:
  • config - The current configuration object
  • utils - Utilities for config manipulation
    • removePlugin(name: string) - Remove a plugin by name
Example:
config(config, utils) {
  // Modify config
  config.title = 'My Documentation'
  
  // Remove conflicting plugin
  utils.removePlugin('auto-nav-sidebar')
  
  return config
}

markdown

Type: MarkdownOptions Required: No Configure markdown processing.
interface MarkdownOptions {
  remarkPlugins?: (Plugin | [Plugin, any])[]
  rehypePlugins?: (Plugin | [Plugin, any])[]
  globalComponents?: string[]
}
Example:
markdown: {
  remarkPlugins: [
    remarkPlugin,
    [remarkPluginWithOptions, { option: true }]
  ],
  rehypePlugins: [
    rehypePlugin
  ],
  globalComponents: [
    path.resolve(__dirname, './components/MyComponent.tsx')
  ]
}

addRuntimeModules

Type: (config: UserConfig, isProd: boolean) => Record<string, string> | Promise<Record<string, string>> Required: No Create virtual modules that can be imported at runtime. Parameters:
  • config - The user configuration
  • isProd - Whether this is a production build
Returns: Object mapping module names to their content Example:
addRuntimeModules(config, isProd) {
  return {
    'my-plugin-data': `export default ${JSON.stringify({
      version: '1.0.0',
      isProd
    }, null, isProd ? 0 : 2)}`,
    
    'my-plugin-config': `export const config = ${JSON.stringify(config.myPlugin)}`
  }
}
Usage in components:
import data from 'my-plugin-data'
import { config } from 'my-plugin-config'

addPages

Type: (config: UserConfig) => PageOptions[] | Promise<PageOptions[]> Required: No Add custom pages to the site.
interface PageOptions {
  routePath: string
  filepath: string
}
Example:
addPages(config) {
  return [
    {
      routePath: '/custom-page',
      filepath: path.resolve(__dirname, './pages/CustomPage.tsx')
    },
    {
      routePath: '/another-page',
      filepath: path.resolve(__dirname, './pages/AnotherPage.tsx')
    }
  ]
}

globalStyles

Type: string Required: No Path to a CSS or SCSS file to include globally. Example:
globalStyles: path.resolve(__dirname, './styles/global.scss')

globalUIComponents

Type: string[] Required: No Array of component paths to render on every page. Example:
globalUIComponents: [
  path.resolve(__dirname, './components/GlobalHeader.tsx'),
  path.resolve(__dirname, './components/GlobalFooter.tsx')
]

Remark Plugin API

Remark plugins transform the markdown AST.

Plugin Signature

import type { Root } from 'mdast'
import type { Plugin } from 'unified'

export const remarkMyPlugin: Plugin<[Options], Root> = function (options) {
  return (root, file) => {
    // Transform the AST
  }
}

AST Node Types

Common markdown AST node types:
interface Root {
  type: 'root'
  children: Content[]
}

interface Heading {
  type: 'heading'
  depth: 1 | 2 | 3 | 4 | 5 | 6
  children: PhrasingContent[]
}

interface Paragraph {
  type: 'paragraph'
  children: PhrasingContent[]
}

interface Code {
  type: 'code'
  lang?: string
  meta?: string
  value: string
}

interface Text {
  type: 'text'
  value: string
}

Visiting Nodes

Use unist-util-visit to traverse the AST:
import { visit } from 'unist-util-visit'

export const remarkMyPlugin: Plugin<[], Root> = function () {
  return (root) => {
    visit(root, 'heading', (node, index, parent) => {
      // node: Heading
      // index: number (position in parent)
      // parent: Root | Content
    })
  }
}

Creating JSX Elements

Convert markdown to JSX elements:
parent.children[index] = {
  type: 'mdxJsxFlowElement',
  name: 'MyComponent',
  attributes: [
    {
      type: 'mdxJsxAttribute',
      name: 'prop',
      value: 'value'
    },
    {
      type: 'mdxJsxAttribute',
      name: 'numProp',
      value: {
        type: 'mdxJsxAttributeValueExpression',
        value: '42',
        data: {
          estree: {
            type: 'Program',
            body: [{
              type: 'ExpressionStatement',
              expression: {
                type: 'Literal',
                value: 42
              }
            }]
          }
        }
      }
    }
  ],
  children: []
}

Adding Imports

Use the shared utility to add imports:
import { getASTNodeImport } from '@alauda/doom/plugins/shared'

// Add default import
root.children.unshift(
  getASTNodeImport('Component', './Component')
)

// Add named imports
root.children.unshift(
  getASTNodeImport(
    { useHook: 'useHook', Component: 'Component' },
    '@alauda/doom/runtime'
  )
)

UserConfig Type

The user configuration object:
interface UserConfig {
  root?: string
  base?: string
  title?: string
  description?: string
  icon?: string
  logo?: string
  lang?: string
  locales?: LocaleConfig[]
  themeConfig?: ThemeConfig
  plugins?: RspressPlugin[]
  markdown?: MarkdownConfig
  route?: RouteConfig
  multiVersion?: MultiVersionConfig
  builderConfig?: BuilderConfig
  
  // Doom-specific
  api?: ApiConfig
  permission?: PermissionConfig
  sites?: DoomSite[]
  export?: ExportItem[]
}

Helper Functions

generateRuntimeModule

Load and process data files at build time:
import { generateRuntimeModule } from '@alauda/doom/utils'

const modules = await generateRuntimeModule(
  config.myPlugin?.files,     // Glob patterns
  'my-plugin-data',           // Module name prefix
  config.root!,               // Root directory
  localBasePath,              // Base path for resolving
  isProd,                     // Production mode
  (data) => transform(data)   // Optional transform function
)

// Returns: { 'doom-@my-plugin-data': '...' }

getASTNodeImport

Create import statement nodes:
import { getASTNodeImport } from '@alauda/doom/plugins/shared'

// Default import
const node1 = getASTNodeImport('Component', './Component')
// import Component from './Component'

// Named imports
const node2 = getASTNodeImport(
  { hook: 'useHook', Component: null },
  '@alauda/doom/runtime'
)
// import { hook as useHook, Component } from '@alauda/doom/runtime'

Plugin Examples

See the built-in plugins for complete examples:

TypeScript Support

For full type support, install the required dependencies:
yarn add -D @rspress/core @rspress/shared
yarn add -D @types/mdast mdast unified unist-util-visit
Import types:
import type { RspressPlugin } from '@rspress/core'
import type { UserConfig } from '@rspress/shared'
import type { Root, Heading, Code } from 'mdast'
import type { Plugin } from 'unified'

Build docs developers (and LLMs) love