Plugin API
In the previous section, we introduced the basic structure of the plugin. In this section, we will introduce the API of the plugin to help you understand the abilities of the plugin in more detail.
TIP
In order to get better type hints, you can install @rspress/shared
in the project, and then import the RspressPlugin
type through import { RspressPlugin } from '@rspress/shared'
.
globalStyles
It is used to add a global style, and the absolute path of a style file is passed in, and the usage is as follows:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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])[]
It is used to add global components, passing in an array, each item in the array is the absolute path of a component, the usage is as follows:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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],
};
}
The item of globalUIComponents
can be a string, which is the path of the component file, or an array, the first item is the path of the component file, and the second item is the component props, for example:
rspress.config.ts
import { defineConfig } from 'rspress/config';
import { RspressPlugin } from '@rspress/shared';
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, the framework will automatically render these React components in the theme without manually importing and using them.
Through global components, you can complete many custom functions, such as:
compUi.tsx
import React from 'react';
// Need a default export
// The props comes from your config
export default function PluginUI(props?: { foo: string }) {
return <div>This is a global layout component</div>;
}
In this way, the content of the component will be rendered in the theme page, such as adding BackToTop button.
In the meanwhile, you can also use the global component to register some side effects, such as:
compSideEffect.tsx
import { useEffect } from 'react';
import { useLocation } from 'rspress/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;
}
This way, side effects of components are executed in the theme page. For example, some of the following scenarios require side effects:
-
Redirect for certain page routes.
-
Bind click event on the img tag of the page to implement the image zoom function.
-
When the route changes, the PV data of different pages are reported.
-
......
builderConfig
The bottom layer of Rspress is based Rsbuild for document build process. The Rsbuild can be configured through builderConfig
. For specific configuration options, please refer to [Rsbuild(https://rsbuild.dev/config/).
Of course, if you want to configure Rspack directly, you can also configure it through buildConfig.tools.rspack
.
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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
},
},
},
};
}
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;
}
It is used to modify/extend the configuration of Rspress itself. For example, if you want to modify the title of the document, you can do it through config
:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
export function pluginForDoc(): RspressPlugin {
return {
// Plugin name
name: 'plugin-name',
// Extend the config of the Rspress itself
config(config) {
return {
...config,
title: 'New Document Title',
};
},
};
}
If it involves adding and removing a plugin, you need to implement it through addPlugin
and removePlugin
:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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>
It is used to perform some operations before/after the document is built. The first parameter is the config of the document, and the second parameter is whether it is currently a production environment. The usage is as follows:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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 the beforeBuild
hook is executed, the config
plugins of all plugins have been processed, so the config parameter already represents the final document configuration.
markdown
- Type:
{ remarkPlugins?: Plugin[]; rehypePlugins?: Plugin[] }
It is used to extend the compilation ability of Markdown/MDX. If you want to add custom remark/rehype plugins or MDX globalComponents, you can use markdown
options to achieve:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
export function pluginForDoc(): RspressPlugin {
return {
name: 'plugin-name',
markdown: {
// Use js version compiler to support plugins
mdxRs: false,
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 { RspressPlugin } from '@rspress/shared';
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';
export function MyComponent() {
const { page } = usePageData();
// page.a === 1
return <div>{page.a}</div>;
}
addPages
- Type:
(config: UserConfig) => AddtionalPage[] | Promise<AddtionalPage[]>
The config
parameter is the doc
config of rspress.config.ts
, and the AddtionalPage
type is defined as follows:
interface AddtionalPage {
routePath: string;
filepath?: string;
content?: string;
}
Used to add additional pages, you can return an array in the addPages
function, each item in the array is a page config, you can specify the route of the page through routePath
, through filepath
or content
to specify the content of the page. For example:
import path from 'path';
import { RspressPlugin } from '@rspress/shared';
export function docPluginDemo(): RspressPlugin {
return {
name: 'add-pages',
addPages(config, isProd) {
return [
// Support the absolute path of the real file (filepath), which will read the content of md(x) in the disk
{
routePath: '/filepath-route',
filepath: path.join(__dirname, 'blog', 'index.md'),
},
// Support to directly pass in the content of md(x) through the content parameter
{
routePath: '/content-route',
content: '# Demo2',
},
];
},
};
}
addPages
accepts two parameters, config
is the config of the current document site, isProd
indicates whether it is a production environment.
routeGenerated
- Type:
(routeMeta: RouteMeta[]) => void | Promise<void>
In this hook, you can get all the route meta information. The structure of each route meta information is as follows
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 current route
lang: string;
}
例子:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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>>;
Used to add additional runtime modules. For example, if you want to use some compile-time information in the document, you can achieve this through addRuntimeModules
:
plugin.ts
import { RspressPlugin } from '@rspress/shared';
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)}`,
};
},
};
}
In this way, you can use the virtual-foo
module in the runtime component:
import myData from 'virtual-foo';
export function MyComponent() {
return <div>{myData.a}</div>;
}
TIP
This hook is executed after the routeGenerated
hook.