Skip to content

Commit

Permalink
feat: add runtime modules hook in plugin system (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
sanyuan0704 authored Oct 20, 2023
1 parent 5acc0de commit 0687d48
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 15 deletions.
6 changes: 6 additions & 0 deletions .changeset/nine-carrots-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rspress/shared': minor
'@rspress/core': minor
---

feat: add runtime module hook
35 changes: 29 additions & 6 deletions packages/core/src/node/PluginDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,14 @@ export class PluginDriver {

for (const plugin of this.#plugins) {
if (typeof plugin.config === 'function') {
config = await plugin.config(config || {}, {
addPlugin: this.addPlugin.bind(this),
removePlugin: this.removePlugin.bind(this),
});
config = await plugin.config(
config || {},
{
addPlugin: this.addPlugin.bind(this),
removePlugin: this.removePlugin.bind(this),
},
this.#isProd,
);
}
}
this.#config = config;
Expand All @@ -124,11 +128,15 @@ export class PluginDriver {
async modifySearchIndexData(
pages: PageIndexInfo[],
): Promise<PageIndexInfo[]> {
return this._runParallelAsyncHook('modifySearchIndexData', pages);
return this._runParallelAsyncHook(
'modifySearchIndexData',
pages,
this.#isProd,
);
}

async extendPageData(pageData: PageIndexInfo) {
return this._runParallelAsyncHook('extendPageData', pageData);
return this._runParallelAsyncHook('extendPageData', pageData, this.#isProd);
}

async addPages() {
Expand All @@ -145,6 +153,21 @@ export class PluginDriver {
return this._runParallelAsyncHook('routeGenerated', routes);
}

async addRuntimeModules() {
const result: Record<string, string>[] = await this._runParallelAsyncHook(
'addRuntimeModules',
this.#config || {},
this.#isProd,
);

return result.reduce((prev, current) => {
return {
...prev,
...current,
};
}, {});
}

async addSSGRoutes() {
const result = await this._runParallelAsyncHook(
'addSSGRoutes',
Expand Down
12 changes: 12 additions & 0 deletions packages/core/src/node/runtimeModule/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,20 +61,32 @@ export const runtimeModuleFactory: RuntimeModuleFactory[] = [
export function builderDocVMPlugin(
factoryContext: Omit<FactoryContext, 'alias'>,
): BuilderPlugin {
const { pluginDriver } = factoryContext;
return {
name: 'vmBuilderPlugin',
setup(api) {
api.modifyBundlerChain(async bundlerChain => {
// The order should be sync
const alias = bundlerChain.resolve.alias.entries();
const runtimeModule: Record<string, string> = {};
// Add internal runtime module
for (const factory of runtimeModuleFactory) {
const moduleResult = await factory({
...factoryContext,
alias,
});
Object.assign(runtimeModule, moduleResult);
}
// Add runtime module from outer plugins
const modulesByPlugin = await pluginDriver.addRuntimeModules();
Object.keys(modulesByPlugin).forEach(key => {
if (runtimeModule[key]) {
throw new Error(
`The runtime module ${key} is duplicated, please check your plugin`,
);
}
runtimeModule[key] = modulesByPlugin[key];
});
bundlerChain
.plugin(`rspress-runtime-module`)
.use(
Expand Down
48 changes: 46 additions & 2 deletions packages/document/docs/en/plugin/system/plugin-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export function pluginForDoc(): RspressPlugin {
return {
name: 'plugin-name',
// Extend the page data
extendPageData(pageData) {
extendPageData(pageData, isProd) {
// You can add or modify properties on the pageData object
pageData.a = 1;
},
Expand Down Expand Up @@ -311,9 +311,53 @@ export function pluginForDoc(): RspressPlugin {
// plugin name
name: 'plugin-routes',
// Hook to execute after route generated
async routeGenerated(routes) {
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`:

```tsx title="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-xxx': `export default ${JSON.stringify(data)}`,
};
},
};
}
```

In this way, you can use the `virtual-xxx` module in the runtime component:

```jsx
import myData from 'virtual-xxx';

export function MyComponent() {
return <div>{myData.a}</div>;
}
```

:::tip TIP

This hook is executed after the `routeGenerated` hook.

:::
50 changes: 47 additions & 3 deletions packages/document/docs/zh/plugin/system/plugin-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function pluginForDoc(slug: string): RspressPlugin {

### config

- **类型**`(config: DocConfig, utils: ConfigUtils) => DocConfig | Promise<DocConfig>`
- **类型**`(config: DocConfig, utils: ConfigUtils, isProd: boolean) => DocConfig | Promise<DocConfig>`

其中,`ConfigUtils` 的类型定义如下:

Expand Down Expand Up @@ -253,7 +253,7 @@ export function pluginForDoc(): RspressPlugin {
// 插件名称
name: 'plugin-name',
// 扩展页面数据
extendPageData(pageData) {
extendPageData(pageData, isProd) {
// 你可以往 pageData 对象上添加或者修改属性
pageData.a = 1;
},
Expand Down Expand Up @@ -345,9 +345,53 @@ export function pluginForDoc(): RspressPlugin {
// 插件名称
name: 'plugin-routes',
// 在构建之后执行的钩子
async routeGenerated(routes) {
async routeGenerated(routes, isProd) {
// 这里可以拿到 routes 数组,执行一些操作
},
};
}
```

### addRuntimeModules

- **类型**`(config: UserConfig, isProd: boolean) => Record<string, string> | Promise<Record<string, string>>;`

用于添加额外的运行时模块,比如你想要在文档中使用到某些编译时的信息,可以通过 `addRuntimeModules` 来实现:

```tsx title="plugin.ts"
import { RspressPlugin } from '@rspress/shared';

export function pluginForDoc(): RspressPlugin {
return {
// 插件名称
name: 'plugin-name',
// 添加额外的运行时模块
async addRuntimeModules(config, isProd) {
const fetchSomeData = async () => {
// 模拟异步请求
return { a: 1 };
};
const data = await fetchSomeData();
return {
'virtual-xxx': `export default ${JSON.stringify(data)}`,
};
},
};
}
```

这样你就可以在运行时组件中使用 `virtual-xxx` 模块了:

```jsx
import myData from 'virtual-xxx';

export function MyComponent() {
return <div>{myData.a}</div>;
}
```

:::tip 提醒

该 hook 在 `routeGenerated` 之后执行。

:::
23 changes: 19 additions & 4 deletions packages/shared/src/types/Plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,22 +47,24 @@ export interface RspressPlugin {
addPlugin: (plugin: RspressPlugin) => void;
removePlugin: (pluginName: string) => void;
},
isProd: boolean,
) => UserConfig | Promise<UserConfig>;
/**
* Callback before build
*/
beforeBuild?: (config: UserConfig, isProd: boolean) => Promise<void>;
beforeBuild?: (config: UserConfig, isProd: boolean) => void | Promise<void>;
/**
* Callback after build
*/
afterBuild?: (config: UserConfig, isProd: boolean) => Promise<void>;
afterBuild?: (config: UserConfig, isProd: boolean) => void | Promise<void>;
/**
* Extend every page's data
*/
extendPageData?: (
pageData: PageIndexInfo & {
[key: string]: unknown;
},
isProd: boolean,
) => void | Promise<void>;
/**
* Add custom route
Expand All @@ -71,10 +73,20 @@ export interface RspressPlugin {
config: UserConfig,
isProd: boolean,
) => AdditionalPage[] | Promise<AdditionalPage[]>;
/**
* Add runtime modules
*/
addRuntimeModules?: (
config: UserConfig,
isProd: boolean,
) => Record<string, string> | Promise<Record<string, string>>;
/**
* Callback after route generated
*/
routeGenerated?: (routes: RouteMeta[]) => Promise<void> | void;
routeGenerated?: (
routes: RouteMeta[],
isProd: boolean,
) => Promise<void> | void;
/**
* Add addition ssg routes, for dynamic routes.
*/
Expand All @@ -86,5 +98,8 @@ export interface RspressPlugin {
* @private
* Modify search index data.
*/
modifySearchIndexData?: (data: PageIndexInfo[]) => void | Promise<void>;
modifySearchIndexData?: (
data: PageIndexInfo[],
isProd: boolean,
) => void | Promise<void>;
}

0 comments on commit 0687d48

Please sign in to comment.