logo
  • 指南
  • 配置
  • 插件
  • API
  • 示例
  • 社区
  • Modern.js 2.x 文档
  • 简体中文
    • 简体中文
    • English
    • 插件介绍
      插件系统
      CLI 插件
      插件 API
      生命周期
      插件迁移
      运行时插件
      插件 API
      生命周期
      插件迁移
      官方插件
      CLI 插件
      BFF 插件
      SSG 插件
      styled-components 插件
      📝 编辑此页面
      上一页插件迁移下一页生命周期

      #插件 API

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

      Info

      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 对象作为参数,用于注册钩子。

      #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 传递给整个应用:

      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>
                );
              };
            });
          },
        };
      };