插件 API

Modern.js 的 Runtime 插件允许您在应用程序的 React 代码运行时扩展和修改其行为。通过 Runtime 插件,您可以轻松地执行初始化任务、实现 React 高阶组件(HOC)封装等功能。

插件结构

一个典型的 Runtime 插件如下所示:

import type { RuntimePluginFuture } from '@modern-js/runtime';

const myRuntimePlugin = (): RuntimePluginFuture => ({
  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 对象作为参数,用于注册钩子。

API 概览

Runtime 插件 API 主要分为以下几类:

  • 信息获取:获取运行时配置和钩子函数。
  • 生命周期钩子:在应用渲染的不同阶段执行自定义逻辑。

信息获取

api.getRuntimeConfig

获取用户在 modern.runtime.ts 文件中定义的运行时配置。

  • 用法:
const config = api.getRuntimeConfig();
console.log(config.myCustomSetting);
WARNING

此方法返回的是用户配置的副本,修改返回值不会影响原始配置。

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; // 将数据添加到上下文中
    });
WARNING
  • 此钩子在每次渲染前都会执行,因此应避免执行耗时过长的操作。
  • 您可以在此钩子中修改 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;
    });
WARNING
  • 务必将 props 传递给原始的 App 组件,否则可能导致应用无法正常工作。
  • wrapRoot 返回的组件会在每次渲染时重新创建,因此应避免在其中定义复杂的逻辑或状态。

进阶用法

组合使用钩子

您可以组合使用多个钩子来实现更复杂的功能。例如,您可以使用 onBeforeRender 获取数据,然后使用 wrapRoot 将数据通过 Context 传递给整个应用:

api.onBeforeRender(async (context) => {
  const data = await fetchData(context.req);
  context.data = data;
});

api.wrapRoot((App) => {
  return (props) => (
    <DataContext.Provider value={props.data}>
      <App {...props} />
    </DataContext.Provider>
  );
});