Plugin API
The previous section introduced the basic plugin structure. This page explains the plugin APIs and what each one can extend.
globalStyles
Adds a global style file. Pass the absolute path of the style file:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
import path from 'path';
export function pluginForDoc(): RspressPlugin {
// style path
const stylePath = path.join(__dirname, 'some-style.css');
return {
// plugin name
name: 'plugin-name',
globalStyles: path.join(__dirname, 'global.css'),
};
}
For example, if you want to modify the theme color, you can do so by adding a global style:
global.css
:root {
--rp-c-brand: #ffa500;
--rp-c-brand-dark: #ffa500;
--rp-c-brand-darker: #c26c1d;
--rp-c-brand-light: #f2a65a;
--rp-c-brand-lighter: #f2a65a;
}
globalUIComponents
- Type:
(string | [string, object])[]
Adds global components. Pass an array where each item is the absolute path of a component:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
// component path
const componentPath = path.join(__dirname, 'foo.tsx');
return {
// plugin name
name: 'plugin-comp',
// Path to global components
globalUIComponents: [componentPath],
};
}
Each globalUIComponents item can be either a component file path string or a tuple. In the tuple form, the first item is the component file path and the second item is the component props. For example:
rspress.config.ts
import { defineConfig } from '@rspress/core';
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
// component path
const componentPath = path.join(__dirname, 'foo.tsx');
return {
// plugin name
name: 'plugin-comp',
globalUIComponents: [
[
path.join(__dirname, 'components', 'MyComponent.tsx'),
{
foo: 'bar',
},
],
],
};
}
When you register global components, Rspress automatically renders these React components in the theme without requiring manual imports.
Global components can implement many custom features, such as:
compUi.tsx
import React from 'react';
// Need a default export
// Props come from your config
export default function PluginUI(props?: { foo: string }) {
return <div>This is a global layout component</div>;
}
The component content is then rendered in the theme, for example to add a BackToTop button.
You can also use a global component to register side effects:
compSideEffect.tsx
import { useEffect } from 'react';
import { useLocation } from '@rspress/core/runtime';
// Need a default export
export default function PluginSideEffect() {
const { pathname } = useLocation();
useEffect(() => {
// Executed when the component renders for the first time
}, []);
useEffect(() => {
// Executed when the route changes
}, [pathname]);
return null;
}
The component side effects then run in the theme. For example, side effects are useful for:
- Redirecting specific page routes.
- Binding click events on page
img tags to implement image zoom.
- Reporting page view data when the route changes.
builderConfig
Rspress uses Rsbuild as its build tool. Configure Rsbuild through builderConfig. For specific configuration options, see Rsbuild.
To configure Rspack directly, use builderConfig.tools.rspack.
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(slug: string): RspressPlugin {
return {
name: 'plugin-name',
// Global variable definitions for build phase
builderConfig: {
source: {
define: {
SLUG: JSON.stringify(slug),
},
},
tools: {
rspack(options) {
// Modify rspack config
},
},
},
};
}
See Build Config for more details.
config
- Type:
(config: DocConfig, utils: ConfigUtils) => DocConfig | Promise<DocConfig>
The type of ConfigUtils is as follows:
interface ConfigUtils {
addPlugin: (plugin: RspressPlugin) => void;
removePlugin: (pluginName: string) => void;
}
Modifies or extends the Rspress config itself. For example, use config to change the site title:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
// Plugin name
name: 'plugin-name',
// Extend the Rspress config itself
config(config) {
return {
...config,
title: 'New Document Title',
};
},
};
}
To add or remove plugins, use addPlugin and removePlugin:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
// Plugin name
name: 'plugin-name',
// Extend the config of Rspress itself
config(config, utils) {
// Add a plugin
utils.addPlugin({
name: 'plugin-name',
// ... other config of the plugin
});
// Remove a plugin, pass in the name of the plugin
utils.removePlugin('plugin-name');
return config;
},
};
}
beforeBuild/afterBuild
- Type:
(config: DocConfig, isProd: boolean) => void | Promise<void>
Runs operations before or after the docs are built. The first parameter is the resolved docs config, and the second parameter indicates whether the current build is production:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
name: 'plugin-name',
// Hook to execute before build
async beforeBuild(config, isProd) {
// Do something here
},
// Hook to execute after build
async afterBuild(config, isProd) {
// Do something here
},
};
}
Tip
When beforeBuild runs, all plugins' config hooks have already been processed, so the config parameter represents the final docs configuration.
markdown
- Type:
{ remarkPlugins?: Plugin[]; rehypePlugins?: Plugin[] }
Extends Markdown/MDX compilation. Use markdown to add custom remark/rehype plugins or MDX globalComponents:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
name: 'plugin-name',
markdown: {
remarkPlugins: [
// Add custom remark plugin
],
rehypePlugins: [
// Add custom rehype plugin
],
globalComponents: [
// Register global components for MDX
],
},
};
}
extendPageData
- Type:
(pageData: PageData) => void | Promise<void>
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
name: 'plugin-name',
// Extend the page data
extendPageData(pageData, isProd) {
// You can add or modify properties on the pageData object
pageData.a = 1;
},
};
}
After extending the page data, you can access the page data through the usePageData hook in the theme.
import { usePageData } from '@rspress/core/runtime';
export function MyComponent() {
const { page } = usePageData();
// page.a === 1
return <div>{page.a}</div>;
}
addPages
- Type:
(config: UserConfig) => AdditionalPage[] | Promise<AdditionalPage[]>
The config parameter is the docs config from rspress.config.ts, and the AdditionalPage type is:
interface AdditionalPage {
routePath: string;
filepath?: string;
content?: string;
}
Adds additional pages. Return an array from addPages; each item is a page config. Use routePath to specify the page route, and use filepath or content to specify the page content. For example:
import path from 'path';
import type { RspressPlugin } from '@rspress/core';
export function docPluginDemo(): RspressPlugin {
return {
name: 'add-pages',
addPages(config, isProd) {
return [
// Supports the absolute path of a real file (`filepath`) and reads md(x) content from disk
{
routePath: '/filepath-route',
filepath: path.join(__dirname, 'blog', 'index.md'),
},
// Supports directly passing md(x) content through the `content` parameter
{
routePath: '/content-route',
content: '# Demo2',
},
];
},
};
}
addPages accepts two parameters: config is the current documentation site config, and isProd indicates whether the current build is production.
routeGenerated
- Type:
(routeMeta: RouteMeta[]) => void | Promise<void>
This hook receives all route metadata. Each route metadata item has the following structure:
export interface RouteMeta {
// route path
routePath: string;
// file absolute path
absolutePath: string;
// The page name, as part of the chunk filename
pageName: string;
// language of the current route
lang: string;
}
Example:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
// plugin name
name: 'plugin-routes',
// Hook to execute after route generated
async routeGenerated(routes, isProd) {
// Do something here
},
};
}
addRuntimeModules
- Type:
(config: UserConfig, isProd: boolean) => Record<string, string> | Promise<Record<string, string>>;
Adds additional runtime modules. For example, use addRuntimeModules to expose compile-time information to docs:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
// Plugin name
name: 'plugin-name',
// Add additional runtime modules
async addRuntimeModules(config, isProd) {
const fetchSomeData = async () => {
// Mock asynchronous request
return { a: 1 };
};
const data = await fetchSomeData();
return {
'virtual-foo': `export default ${JSON.stringify(data)}`,
};
},
};
}
You can then use the virtual-foo module in a runtime component:
import myData from 'virtual-foo';
export function MyComponent() {
return <div>{myData.a}</div>;
}
TIP
This hook is executed after the routeGenerated hook.
i18nSource
- Type:
(source: Record<string, Record<string, string>>) => Record<string, Record<string, string>> | Promise<Record<string, Record<string, string>>>
Adds or modifies internationalization (i18n) text data. Use this hook to extend or override the theme's i18n text.
The source parameter is an object with the following structure:
{
[textKey: string]: {
[locale: string]: string;
}
}
The first-level textKey is the text key, the second-level locale is the language code (for example, zh or en), and the value is the translated text for that language.
Usage example:
plugin.ts
import type { RspressPlugin } from '@rspress/core';
export function pluginForDoc(): RspressPlugin {
return {
// Plugin name
name: 'plugin-name',
// Add or modify i18n text
i18nSource(source) {
// Add new text
return {
...source,
customKey: {
zh: '自定义文案',
en: 'Custom Text',
},
anotherKey: {
zh: '另一个文案',
en: 'Another Text',
},
};
},
};
}
If your plugin also provides runtime components, read these texts with the useI18n hook:
import { useI18n } from '@rspress/core/runtime';
export function MyComponent() {
const t = useI18n();
return <div>{t('customKey')}</div>;
}