Modern.js 的 Runtime 插件允许您在应用程序的 React 代码运行时扩展和修改其行为。通过 Runtime 插件,您可以轻松地执行初始化任务、实现 React 高阶组件(HOC)封装等功能。
Runtime 插件需要通过 src/modern.runtime.ts 中的 plugins 字段配置。
一个典型的 Runtime 插件如下所示:
import type { RuntimePlugin } from '@modern-js/runtime';
const myRuntimePlugin = (): RuntimePlugin => ({
name: 'my-runtime-plugin',
setup: api => {
// 使用 api 注册钩子
api.onBeforeRender(context => {
console.log('Before rendering:', context);
});
api.wrapRoot(App => {
return props => (
<MyContextProvider>
<App {...props} />
</MyContextProvider>
);
});
},
});
export default myRuntimePlugin;name: 插件的唯一标识符。setup: 插件的主要逻辑,接收一个 api 对象作为参数,用于注册钩子。Runtime 插件 API 主要分为以下几类:
api.getRuntimeConfig获取用户在 modern.runtime.ts 文件中定义的运行时配置。
const config = api.getRuntimeConfig();
console.log(config.myCustomSetting);此方法返回的是用户配置的副本,修改返回值不会影响原始配置。
api.getHooks获取可用于手动触发的钩子函数。
() => {
onBeforeRender: {
call: (context: any) => Promise<void>;
}
// 其他钩子...
};const hooks = api.getHooks();
await hooks.onBeforeRender.call(myContext);api.onBeforeRender在应用渲染(包括服务器端渲染和客户端渲染)之前执行。您可以在此钩子中执行数据预取、修改渲染上下文等操作。
类型:
type OnBeforeRenderFn<RuntimeContext> = (
context: RuntimeContext,
) => Promise<void> | void;RuntimeContext 包含当前请求的上下文信息,如请求对象、响应对象等。
用法:
api.onBeforeRender(async context => {
const data = await fetchData(context.req);
context.data = data; // 将数据添加到上下文中
});context 对象,并将修改后的 context 传递给后续的渲染过程。api.wrapRoot允许您使用自定义的 React 组件包裹应用的根组件。常用于添加全局的 Provider、布局组件等。
类型:
type WrapRootFn = (App: React.ComponentType<any>) => React.ComponentType<any>;用法:
api.wrapRoot(App => {
const AppWrapper = props => {
return (
<MyGlobalProvider>
<Layout>
<App {...props} /> {/* 确保传递 props */}
</Layout>
</MyGlobalProvider>
);
};
return AppWrapper;
});props 传递给原始的 App 组件,否则可能导致应用无法正常工作。wrapRoot 返回的组件会在每次渲染时重新创建,因此应避免在其中定义复杂的逻辑或状态。您可以组合使用多个钩子来实现更复杂的功能。例如,您可以使用 onBeforeRender 获取数据,然后使用 wrapRoot 将数据通过 Context 传递给整个应用:
import { RuntimePlugin, RuntimeContext } from '@modern-js/runtime';
import { useContext, createContext } from 'react';
export const ThemeContext = createContext<{ theme: string } | null>(null);
export const themePlugin = (): RuntimePlugin => {
return {
name: 'theme-plugin',
setup: api => {
api.onBeforeRender(async context => {
const userPreference = await fetch('/api/user/theme-settings').then(
res => res.json(),
);
context.data = {
theme: userPreference.theme,
};
});
api.wrapRoot(App => {
return props => {
const context = useContext(RuntimeContext);
return (
<ThemeContext.Provider value={context.data}>
<App {...props} />
</ThemeContext.Provider>
);
};
});
},
};
};