@modern-js/main-doc 2.65.5 → 2.66.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/en/community/blog/v2-release-note.mdx +1 -1
- package/docs/en/configure/app/plugins.mdx +2 -2
- package/docs/en/configure/app/tools/esbuild.mdx +1 -1
- package/docs/en/configure/app/tools/swc.mdx +1 -1
- package/docs/en/plugin/_meta.json +8 -7
- package/docs/en/plugin/cli-plugins/_meta.json +1 -1
- package/docs/en/plugin/cli-plugins/api.mdx +617 -0
- package/docs/en/plugin/cli-plugins/life-cycle.mdx +139 -0
- package/docs/en/plugin/cli-plugins/migration.mdx +98 -0
- package/docs/en/plugin/introduction.mdx +119 -47
- package/docs/en/plugin/official/_meta.json +12 -0
- package/docs/en/plugin/official/cli-plugins/_meta.json +1 -0
- package/docs/en/plugin/official/cli-plugins.mdx +6 -0
- package/docs/en/plugin/official/rsbuild-plugins.mdx +3 -0
- package/docs/en/plugin/plugin-system.mdx +237 -0
- package/docs/en/plugin/runtime-plugins/_meta.json +1 -0
- package/docs/en/plugin/runtime-plugins/api.mdx +165 -0
- package/docs/en/plugin/runtime-plugins/life-cycle.mdx +29 -0
- package/docs/en/plugin/runtime-plugins/migration.mdx +101 -0
- package/docs/en/plugin/server-plugins/api.mdx +3 -0
- package/docs/en/plugin/server-plugins/life-cycle.mdx +3 -0
- package/docs/zh/community/blog/v2-release-note.mdx +1 -1
- package/docs/zh/configure/app/plugins.mdx +2 -2
- package/docs/zh/configure/app/tools/esbuild.mdx +1 -1
- package/docs/zh/configure/app/tools/swc.mdx +1 -1
- package/docs/zh/plugin/_meta.json +8 -7
- package/docs/zh/plugin/cli-plugins/_meta.json +1 -1
- package/docs/zh/plugin/cli-plugins/api.mdx +617 -0
- package/docs/zh/plugin/cli-plugins/life-cycle.mdx +139 -0
- package/docs/zh/plugin/cli-plugins/migration.mdx +98 -0
- package/docs/zh/plugin/introduction.mdx +92 -20
- package/docs/zh/plugin/official/_meta.json +12 -0
- package/docs/zh/plugin/official/cli-plugins/_meta.json +1 -0
- package/docs/zh/plugin/official/cli-plugins.mdx +6 -0
- package/docs/zh/plugin/official/rsbuild-plugins.mdx +3 -0
- package/docs/zh/plugin/plugin-system.mdx +239 -0
- package/docs/zh/plugin/runtime-plugins/_meta.json +1 -0
- package/docs/zh/plugin/runtime-plugins/api.mdx +166 -0
- package/docs/zh/plugin/runtime-plugins/life-cycle.mdx +29 -0
- package/docs/zh/plugin/runtime-plugins/migration.mdx +101 -0
- package/docs/zh/plugin/server-plugins/api.mdx +3 -0
- package/docs/zh/plugin/server-plugins/life-cycle.mdx +3 -0
- package/i18n.json +4 -0
- package/package.json +3 -2
- package/src/components/Footer/index.tsx +1 -1
- package/src/components/Mermaid/index.tsx +60 -0
- package/src/components/Mermaid/style.scss +221 -0
- package/docs/en/plugin/cli-plugins.mdx +0 -6
- package/docs/en/plugin/plugin-system/_meta.json +0 -10
- package/docs/en/plugin/plugin-system/extend.mdx +0 -163
- package/docs/en/plugin/plugin-system/hook-list.mdx +0 -711
- package/docs/en/plugin/plugin-system/hook.mdx +0 -188
- package/docs/en/plugin/plugin-system/implement.mdx +0 -243
- package/docs/en/plugin/plugin-system/introduction.mdx +0 -95
- package/docs/en/plugin/plugin-system/lifecycle.mdx +0 -16
- package/docs/en/plugin/plugin-system/plugin-api.mdx +0 -138
- package/docs/en/plugin/plugin-system/relationship.mdx +0 -119
- package/docs/en/plugin/rsbuild-plugins.mdx +0 -3
- package/docs/zh/plugin/cli-plugins.mdx +0 -6
- package/docs/zh/plugin/plugin-system/_meta.json +0 -10
- package/docs/zh/plugin/plugin-system/extend.mdx +0 -163
- package/docs/zh/plugin/plugin-system/hook-list.mdx +0 -715
- package/docs/zh/plugin/plugin-system/hook.mdx +0 -173
- package/docs/zh/plugin/plugin-system/implement.mdx +0 -250
- package/docs/zh/plugin/plugin-system/introduction.mdx +0 -94
- package/docs/zh/plugin/plugin-system/lifecycle.mdx +0 -16
- package/docs/zh/plugin/plugin-system/plugin-api.mdx +0 -138
- package/docs/zh/plugin/plugin-system/relationship.mdx +0 -119
- package/docs/zh/plugin/rsbuild-plugins.mdx +0 -4
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-bff.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-ssg.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-swc.mdx +0 -0
- /package/docs/en/plugin/{cli-plugins → official/cli-plugins}/plugin-tailwind.mdx +0 -0
- /package/docs/en/plugin/{rsbuild-plugins → official/rsbuild-plugins}/_meta.json +0 -0
- /package/docs/en/plugin/{rsbuild-plugins → official/rsbuild-plugins}/plugin-esbuild.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-bff.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-ssg.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-swc.mdx +0 -0
- /package/docs/zh/plugin/{cli-plugins → official/cli-plugins}/plugin-tailwind.mdx +0 -0
- /package/docs/zh/plugin/{rsbuild-plugins → official/rsbuild-plugins}/_meta.json +0 -0
- /package/docs/zh/plugin/{rsbuild-plugins → official/rsbuild-plugins}/plugin-esbuild.mdx +0 -0
@@ -0,0 +1,237 @@
|
|
1
|
+
# Plugin System
|
2
|
+
|
3
|
+
Modern.js adopts a highly extensible, plugin-based architecture, where its core functionalities and extended capabilities are implemented through plugins. The plugin system not only ensures the framework's flexibility but also provides developers with powerful customization options. This document focuses on how to write Modern.js plugins, helping you quickly get started with plugin development.
|
4
|
+
|
5
|
+
## Core Concept: Everything is a Plugin
|
6
|
+
|
7
|
+
Modern.js adheres to the design philosophy of "everything is a plugin," modularizing the framework's various functional components and assembling and extending them through plugins. This design brings several advantages, including:
|
8
|
+
|
9
|
+
- **High Cohesion, Low Coupling:** Each functional module is independently developed, tested, and maintained, reducing system complexity.
|
10
|
+
- **Flexible and Extensible:** Users can easily customize the framework's behavior by writing or combining plugins without modifying the core code.
|
11
|
+
- **Easy to Reuse:** Plugins can be shared across projects, improving development efficiency.
|
12
|
+
- **Progressive Enhancement:** Plugins are introduced on demand, without the complexity of carrying all functionalities from the start.
|
13
|
+
|
14
|
+
## Plugin Types and Use Cases
|
15
|
+
|
16
|
+
Modern.js provides three main plugin types, corresponding to different stages of application development:
|
17
|
+
|
18
|
+
**CLI Plugins:**
|
19
|
+
- **Active Stage:** Build time (when executing the `modern` command).
|
20
|
+
- **Typical Scenarios:**
|
21
|
+
- Extending command-line tools.
|
22
|
+
- Modifying build configurations.
|
23
|
+
- Listening for file changes.
|
24
|
+
- Controlling the build process.
|
25
|
+
- **Configuration Method:** The `plugins` field in `modern.config.ts`.
|
26
|
+
|
27
|
+
**Runtime Plugins:**
|
28
|
+
- **Active Stage:** Application runtime (browser/Node.js environment).
|
29
|
+
- **Typical Scenarios:**
|
30
|
+
- Initializing global state or services.
|
31
|
+
- Encapsulating React Higher-Order Components (HOCs).
|
32
|
+
- Intercepting or modifying routing behavior.
|
33
|
+
- Controlling the rendering process.
|
34
|
+
- **Configuration Method:** The `plugins` field in `src/modern.runtime.ts`.
|
35
|
+
|
36
|
+
{/* **Server Plugins:**
|
37
|
+
- **Active Stage:** Server request processing stage.
|
38
|
+
- **Typical Scenarios:**
|
39
|
+
- Adding custom middleware.
|
40
|
+
- Extending server-side APIs.
|
41
|
+
- Customizing SSR logic.
|
42
|
+
- Integrating with backend frameworks.
|
43
|
+
- **Configuration Method:** The `plugins` field in `server/modern.server.ts`. */}
|
44
|
+
|
45
|
+
## Plugin Structure
|
46
|
+
|
47
|
+
A typical Modern.js plugin consists of the following key parts:
|
48
|
+
|
49
|
+
```ts
|
50
|
+
import type { Plugin } from '@modern-js/plugin-v2';
|
51
|
+
|
52
|
+
const myPlugin: Plugin = {
|
53
|
+
name: 'my-awesome-plugin', // The unique identifier of the plugin (required)
|
54
|
+
|
55
|
+
// Plugin dependencies and execution order (optional)
|
56
|
+
pre: [], // List of plugin names to execute before this plugin, defaults to an empty array
|
57
|
+
post: [], // List of plugin names to execute after this plugin, defaults to an empty array
|
58
|
+
required: [],// List of required plugins; if a dependent plugin is not registered, an error will be thrown, defaults to an empty array
|
59
|
+
usePlugins: [], // List of plugin instances used internally, defaults to an empty array
|
60
|
+
|
61
|
+
// Register new Hooks (optional)
|
62
|
+
registryHook: {},
|
63
|
+
|
64
|
+
// The entry function of the plugin (required)
|
65
|
+
setup(api) {
|
66
|
+
// The core logic of the plugin, calling plugin APIs through the api object
|
67
|
+
api.modifyWebpackConfig(config => { /* ... */ });
|
68
|
+
api.onPrepare(() => { /* ... */ });
|
69
|
+
// ... Other API calls
|
70
|
+
},
|
71
|
+
};
|
72
|
+
|
73
|
+
export default myPlugin;
|
74
|
+
```
|
75
|
+
|
76
|
+
**Field Descriptions:**
|
77
|
+
|
78
|
+
##### `name`
|
79
|
+
|
80
|
+
- Type: `string`
|
81
|
+
- Description: Identifies the name of the plugin. This name must be unique within the plugin system; otherwise, the plugin will fail to load.
|
82
|
+
|
83
|
+
:::info
|
84
|
+
The plugin names declared in `pre`, `post`, and `required` refer to this `name` field.
|
85
|
+
:::
|
86
|
+
|
87
|
+
##### `setup`
|
88
|
+
|
89
|
+
- Type: `(api: PluginAPI) => MaybePromise<void>`
|
90
|
+
- Description: The main entry point for the plugin's logic.
|
91
|
+
|
92
|
+
###### `api`
|
93
|
+
|
94
|
+
- Type: `PluginAPI`
|
95
|
+
- Description: The plugin's API, containing the Hooks and utility functions supported by the plugin.
|
96
|
+
|
97
|
+
##### `pre`
|
98
|
+
|
99
|
+
- Type: `string[]`
|
100
|
+
- Description: Used to insert the plugin execution order. Plugins declared in `pre` will be executed before this plugin.
|
101
|
+
|
102
|
+
##### `post`
|
103
|
+
|
104
|
+
- Type: `string[]`
|
105
|
+
- Description: Used to determine the plugin execution order. Plugins declared in `post` will be executed after this plugin.
|
106
|
+
|
107
|
+
##### `required`
|
108
|
+
|
109
|
+
- Type: `string[]`
|
110
|
+
- Description: Other plugins that this plugin depends on. Before running, it will check if the dependent plugins are registered.
|
111
|
+
|
112
|
+
:::info
|
113
|
+
If unregistered plugin names are configured in `pre` or `post`, these plugin names will be **automatically ignored** and will not affect the execution of other plugins.
|
114
|
+
|
115
|
+
If you need to explicitly declare that the plugins that the current plugin depends on must exist, you need to use the `required` field.
|
116
|
+
:::
|
117
|
+
|
118
|
+
##### `usePlugins`
|
119
|
+
|
120
|
+
- Type: `Plugin`
|
121
|
+
- Description: Actively register other plugins of the same type within the plugin.
|
122
|
+
|
123
|
+
:::info
|
124
|
+
Plugins declared in `usePlugins` are executed before the current plugin by default. To execute them after, use the `post` declaration.
|
125
|
+
:::
|
126
|
+
##### `registryHooks`
|
127
|
+
|
128
|
+
- Type: `Record<string, PluginHook<(...args: any[]) => any>>`
|
129
|
+
- Description: Extend the currently supported Hook functions to implement custom functionality.
|
130
|
+
|
131
|
+
## Plugin Hook Model
|
132
|
+
|
133
|
+
The core of the Modern.js plugin system is its Hook model, which defines the communication mechanism between plugins. Modern.js mainly provides two types of Hooks:
|
134
|
+
|
135
|
+
### Async Hook
|
136
|
+
|
137
|
+
- **Characteristics:**
|
138
|
+
- Hook functions are executed asynchronously, supporting `async/await`.
|
139
|
+
- The return value of the previous Hook function is passed as the first argument to the next Hook function.
|
140
|
+
- Finally returns the return value of the last Hook function.
|
141
|
+
- **Use Cases:** Scenarios involving asynchronous operations (such as network requests, file reading/writing, etc.).
|
142
|
+
- **Creation Method:** Created using `createAsyncHook`.
|
143
|
+
|
144
|
+
Example:
|
145
|
+
|
146
|
+
```ts
|
147
|
+
// Define Hooks
|
148
|
+
import { createAsyncHook } from '@modern-js/plugin-v2';
|
149
|
+
|
150
|
+
export type AfterPrepareFn = () => Promise<void> | void;
|
151
|
+
export const onAfterPrepare = createAsyncHook<AfterPrepareFn>();
|
152
|
+
|
153
|
+
// Register Hooks in the plugin
|
154
|
+
const myPlugin = () => ({
|
155
|
+
name: "my-plugin",
|
156
|
+
registryHooks: {
|
157
|
+
onAfterPrepare,
|
158
|
+
},
|
159
|
+
setup: (api) => {
|
160
|
+
api.onPrepare(async () => {
|
161
|
+
// Use the registered Hooks in the plugin
|
162
|
+
const hooks = api.getHooks();
|
163
|
+
await hooks.onAfterPrepare.call();
|
164
|
+
});
|
165
|
+
}
|
166
|
+
});
|
167
|
+
|
168
|
+
// Use Hook in other plugins
|
169
|
+
const myPlugin2 = () => ({
|
170
|
+
name: "my-plugin-2",
|
171
|
+
setup: (api) => {
|
172
|
+
api.onAfterPrepare(async () => {
|
173
|
+
// TODO
|
174
|
+
});
|
175
|
+
}
|
176
|
+
})
|
177
|
+
```
|
178
|
+
|
179
|
+
### Sync Hook (Synchronous Hook)
|
180
|
+
|
181
|
+
- **Characteristics:**
|
182
|
+
- Hook functions are executed synchronously.
|
183
|
+
- The return value of the previous Hook function is passed as the first argument to the next Hook function.
|
184
|
+
- Finally returns the return value of the last Hook function.
|
185
|
+
- **Use Cases:** Scenarios where data needs to be modified synchronously (such as modifying configurations, routes, etc.).
|
186
|
+
- **Creation Method:** Created using `createSyncHook`.
|
187
|
+
|
188
|
+
Example:
|
189
|
+
|
190
|
+
```ts
|
191
|
+
// Define Hooks
|
192
|
+
import { createSyncHook } from '@modern-js/plugin-v2';
|
193
|
+
|
194
|
+
type RouteObject = {/** TODO **/};
|
195
|
+
const modifyRoutes = createSyncHook<(routes: RouteObject[]) => RouteObject[]>();
|
196
|
+
|
197
|
+
// Register Hooks in the plugin
|
198
|
+
const myPlugin = () => ({
|
199
|
+
name: "my-plugin",
|
200
|
+
registryHooks: {
|
201
|
+
modifyRoutes,
|
202
|
+
},
|
203
|
+
setup: (api) => {
|
204
|
+
api.onPrepare(async () => {
|
205
|
+
const routes = {};
|
206
|
+
// Use registered Hooks in the plugin
|
207
|
+
const hooks = api.getHooks();
|
208
|
+
const routesResult = hooks.modifyRoutes.call(routes);
|
209
|
+
});
|
210
|
+
}
|
211
|
+
});
|
212
|
+
|
213
|
+
// Other plugins use Hooks
|
214
|
+
const myPlugin2 = () => ({
|
215
|
+
name: "my-plugin",
|
216
|
+
setup: (api) => {
|
217
|
+
api.modifyRoutes(async (routes) => {
|
218
|
+
// Modify routes
|
219
|
+
return routes;
|
220
|
+
});
|
221
|
+
}
|
222
|
+
});
|
223
|
+
```
|
224
|
+
|
225
|
+
## Plugin Development Best Practices
|
226
|
+
|
227
|
+
- **Single Responsibility:** Each plugin should focus on implementing a specific, cohesive function. Avoid creating plugins with complex functionalities and unclear responsibilities.
|
228
|
+
- **Naming Conventions:** Plugin names should be clear, concise, and follow certain naming conventions (such as `plugin-xxx` or `@scope/plugin-xxx`).
|
229
|
+
- **Type Safety:** Make full use of TypeScript's type system to ensure the type safety of the plugin API and reduce runtime errors.
|
230
|
+
- **Comprehensive Documentation:** Write clear documentation for the plugin, including API descriptions, usage examples, configuration explanations, and change logs.
|
231
|
+
- **Thorough Testing:** Conduct unit tests and integration tests on the plugin to ensure its stability, reliability, and compatibility in various scenarios.
|
232
|
+
- **Minimize Side Effects:** Plugins should minimize modifications to the external environment (such as global variables, file systems, etc.) to maintain the plugin's independence and portability.
|
233
|
+
- **Error Handling:** Plugins should properly handle potential errors to prevent the entire application from crashing due to plugin exceptions.
|
234
|
+
- **Performance Optimization:** Pay attention to the performance impact of the plugin, avoid unnecessary calculations and resource consumption, especially in loops or frequently called Hooks.
|
235
|
+
- **Version Control:** Follow Semantic Versioning (SemVer) to ensure the backward compatibility of the plugin and facilitate user upgrades.
|
236
|
+
|
237
|
+
Following these best practices can help you develop high-quality, easy-to-maintain, and easy-to-use Modern.js plugins.
|
@@ -0,0 +1 @@
|
|
1
|
+
["api", "life-cycle", "migration"]
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# Plugin API
|
2
|
+
|
3
|
+
Modern.js's Runtime Plugins allow you to extend and modify the behavior of your application during its React code execution. With Runtime Plugins, you can easily perform initialization tasks, implement React Higher-Order Component (HOC) wrapping, and more.
|
4
|
+
|
5
|
+
## Plugin Structure
|
6
|
+
|
7
|
+
A typical Runtime Plugin looks like this:
|
8
|
+
|
9
|
+
```ts
|
10
|
+
import type { RuntimePluginFuture } from '@modern-js/runtime';
|
11
|
+
|
12
|
+
const myRuntimePlugin = (): RuntimePluginFuture => ({
|
13
|
+
name: 'my-runtime-plugin',
|
14
|
+
setup: (api) => {
|
15
|
+
// Use the api to register hooks
|
16
|
+
api.onBeforeRender((context) => {
|
17
|
+
console.log('Before rendering:', context);
|
18
|
+
});
|
19
|
+
|
20
|
+
api.wrapRoot((App) => {
|
21
|
+
return (props) => (
|
22
|
+
<MyContextProvider>
|
23
|
+
<App {...props} />
|
24
|
+
</MyContextProvider>
|
25
|
+
);
|
26
|
+
});
|
27
|
+
},
|
28
|
+
});
|
29
|
+
|
30
|
+
export default myRuntimePlugin;
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
- `name`: A unique identifier for the plugin.
|
35
|
+
- `setup`: The main logic of the plugin, which receives an `api` object as a parameter. This `api` object is used to register hooks.
|
36
|
+
|
37
|
+
## API Overview
|
38
|
+
|
39
|
+
The Runtime Plugin API is primarily divided into the following categories:
|
40
|
+
|
41
|
+
- **Information Retrieval**: Getting runtime configuration and hook functions.
|
42
|
+
- **Lifecycle Hooks**: Executing custom logic at different stages of the application's rendering process.
|
43
|
+
|
44
|
+
### Information Retrieval
|
45
|
+
|
46
|
+
#### `api.getRuntimeConfig`
|
47
|
+
|
48
|
+
Gets the runtime configuration defined by the user in the `modern.runtime.ts` file.
|
49
|
+
|
50
|
+
- **Usage**:
|
51
|
+
|
52
|
+
```ts
|
53
|
+
const config = api.getRuntimeConfig();
|
54
|
+
console.log(config.myCustomSetting);
|
55
|
+
```
|
56
|
+
|
57
|
+
:::warning
|
58
|
+
|
59
|
+
This method returns a *copy* of the user's configuration. Modifying the returned value will not affect the original configuration.
|
60
|
+
:::
|
61
|
+
|
62
|
+
#### `api.getHooks`
|
63
|
+
|
64
|
+
Gets the hook functions that can be triggered manually.
|
65
|
+
|
66
|
+
- **Type:**
|
67
|
+
|
68
|
+
```ts
|
69
|
+
() => {
|
70
|
+
onBeforeRender: { call: (context: any) => Promise<void> };
|
71
|
+
// Other hooks...
|
72
|
+
};
|
73
|
+
```
|
74
|
+
|
75
|
+
- **Usage:**
|
76
|
+
|
77
|
+
```ts
|
78
|
+
const hooks = api.getHooks();
|
79
|
+
await hooks.onBeforeRender.call(myContext);
|
80
|
+
```
|
81
|
+
|
82
|
+
### Lifecycle Hooks
|
83
|
+
|
84
|
+
#### `api.onBeforeRender`
|
85
|
+
|
86
|
+
Executes before the application renders (including both server-side rendering and client-side rendering). You can use this hook to perform data prefetching, modify the rendering context, etc.
|
87
|
+
|
88
|
+
- **Type:**
|
89
|
+
|
90
|
+
```ts
|
91
|
+
type OnBeforeRenderFn<RuntimeContext> = (context: RuntimeContext) => Promise<void> | void;
|
92
|
+
```
|
93
|
+
`RuntimeContext` contains contextual information about the current request, such as the request object, response object, etc.
|
94
|
+
|
95
|
+
- **Usage:**
|
96
|
+
|
97
|
+
```ts
|
98
|
+
api.onBeforeRender(async (context) => {
|
99
|
+
const data = await fetchData(context.req);
|
100
|
+
context.data = data; // Add the data to the context
|
101
|
+
});
|
102
|
+
```
|
103
|
+
|
104
|
+
:::warning
|
105
|
+
|
106
|
+
- This hook executes before *every* render, so avoid performing long-running operations.
|
107
|
+
- You can modify the `context` object in this hook, and the modified `context` will be passed to subsequent rendering processes.
|
108
|
+
|
109
|
+
:::
|
110
|
+
|
111
|
+
#### `api.wrapRoot`
|
112
|
+
|
113
|
+
Allows you to wrap the application's root component with a custom React component. This is commonly used to add global Providers, layout components, etc.
|
114
|
+
|
115
|
+
- **Type:**
|
116
|
+
|
117
|
+
```ts
|
118
|
+
type WrapRootFn = (
|
119
|
+
App: React.ComponentType<any>
|
120
|
+
) => React.ComponentType<any>;
|
121
|
+
```
|
122
|
+
|
123
|
+
- **Usage:**
|
124
|
+
|
125
|
+
```ts
|
126
|
+
api.wrapRoot((App) => {
|
127
|
+
const AppWrapper = (props) => {
|
128
|
+
return (
|
129
|
+
<MyGlobalProvider>
|
130
|
+
<Layout>
|
131
|
+
<App {...props} /> {/* Make sure to pass props */}
|
132
|
+
</Layout>
|
133
|
+
</MyGlobalProvider>
|
134
|
+
);
|
135
|
+
};
|
136
|
+
return AppWrapper;
|
137
|
+
});
|
138
|
+
```
|
139
|
+
:::warning
|
140
|
+
|
141
|
+
- **It is crucial to pass the `props` to the original `App` component**, otherwise, the application may not function correctly.
|
142
|
+
- The component returned by `wrapRoot` is recreated on every render, so avoid defining complex logic or state within it.
|
143
|
+
|
144
|
+
:::
|
145
|
+
|
146
|
+
## Advanced Usage
|
147
|
+
|
148
|
+
### Combining Hooks
|
149
|
+
|
150
|
+
You can combine multiple hooks to implement more complex functionality. For example, you can use `onBeforeRender` to fetch data and then use `wrapRoot` to pass the data to the entire application via Context:
|
151
|
+
|
152
|
+
```ts
|
153
|
+
api.onBeforeRender(async (context) => {
|
154
|
+
const data = await fetchData(context.req);
|
155
|
+
context.data = data;
|
156
|
+
});
|
157
|
+
|
158
|
+
api.wrapRoot((App) => {
|
159
|
+
return (props) => (
|
160
|
+
<DataContext.Provider value={props.data}>
|
161
|
+
<App {...props} />
|
162
|
+
</DataContext.Provider>
|
163
|
+
);
|
164
|
+
});
|
165
|
+
```
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Life Cycle
|
2
|
+
|
3
|
+
import Mermaid from '@site/src/components/Mermaid';
|
4
|
+
|
5
|
+
<Mermaid>
|
6
|
+
{`
|
7
|
+
flowchart TD
|
8
|
+
init{{"Runtime Initialization"}}
|
9
|
+
load_config(Load User Configuration File)
|
10
|
+
runtime_plugin(Load Runtime Plugins<br><sub>Plugins registered in the configuration file<br>Runtime plugins registered by CLI<br>Plugins used within plugins</sub>)
|
11
|
+
registry_hooks(Register Hooks Functions<br><sub>Execute the plugin setup function, register hooks defined in the plugin, and the logic in the plugin setup will also be executed here</sub>)
|
12
|
+
|
13
|
+
wrapRoot(wrapRoot<br><sub>The logic returned in wrapRoot will be executed when the component is rendered</sub>)
|
14
|
+
onBeforeRender(onBeforeRender)
|
15
|
+
|
16
|
+
init --> load_config
|
17
|
+
load_config --> runtime_plugin
|
18
|
+
runtime_plugin --> registry_hooks
|
19
|
+
registry_hooks --> wrapRoot
|
20
|
+
wrapRoot --> onBeforeRender
|
21
|
+
|
22
|
+
style init fill:#FDE68A,font-size:10px;
|
23
|
+
style load_config stroke-dasharray:5 5,fill:#86EFAC,font-size:10px;
|
24
|
+
style runtime_plugin stroke-dasharray:5 5,fill:#86EFAC,font-size:10px;
|
25
|
+
style registry_hooks stroke-dasharray:5 5,fill:#9CA3AF,font-size:10px;
|
26
|
+
style wrapRoot font-size:10px;
|
27
|
+
style onBeforeRender font-size:10px;
|
28
|
+
`}
|
29
|
+
</Mermaid>
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Plugin Migration
|
2
|
+
|
3
|
+
### Migration Background
|
4
|
+
|
5
|
+
The Modern.js plugin system is constantly evolving. To provide a clearer API and more powerful features, we've optimized the definition and usage of Runtime plugins. While the old plugin syntax is still partially compatible, we strongly recommend migrating according to this guide to take full advantage of the new plugin system.
|
6
|
+
|
7
|
+
### Migration Steps Overview
|
8
|
+
|
9
|
+
1. **Update Plugin Type Definition:** Replace the `Plugin` type with `RuntimePluginFuture`.
|
10
|
+
2. **Adjust Hook Invocation:** Migrate from the `return hooks` pattern to direct `api.xxx` calls.
|
11
|
+
3. **Replace Changed APIs:** Refer to the detailed API mapping table and update your code.
|
12
|
+
|
13
|
+
### Detailed Migration Steps
|
14
|
+
|
15
|
+
#### Update Plugin Type Definition
|
16
|
+
|
17
|
+
This is the first and most crucial step. It ensures that your plugin interacts correctly with the new plugin system.
|
18
|
+
|
19
|
+
```typescript
|
20
|
+
// Old Syntax
|
21
|
+
import type { Plugin } from '@modern-js/runtime';
|
22
|
+
|
23
|
+
const plugin: Plugin = { ... };
|
24
|
+
|
25
|
+
// New Syntax
|
26
|
+
import type { RuntimePluginFuture } from '@modern-js/runtime';
|
27
|
+
|
28
|
+
const plugin: RuntimePluginFuture = { ... };
|
29
|
+
```
|
30
|
+
|
31
|
+
**Explanation:** The `RuntimePluginFuture` type is the standard definition for new plugins. It provides better type inference and a clearer API structure.
|
32
|
+
|
33
|
+
#### Adjust Hook Invocation
|
34
|
+
|
35
|
+
The new plugin system recommends using the `api` object to directly call Hooks. This approach is more intuitive and easier to maintain.
|
36
|
+
|
37
|
+
```typescript
|
38
|
+
// Old Syntax (return hooks)
|
39
|
+
{
|
40
|
+
setup: () => ({
|
41
|
+
beforeRender({ req, res }) { /*...*/ }
|
42
|
+
})
|
43
|
+
}
|
44
|
+
|
45
|
+
// New Syntax (api.xxx)
|
46
|
+
{
|
47
|
+
setup: api => {
|
48
|
+
api.onBeforeRender(({ req, res }) => { /*...*/ })
|
49
|
+
}
|
50
|
+
}
|
51
|
+
```
|
52
|
+
|
53
|
+
**Explanation:** The `api` object provides all available Hooks and utility methods.
|
54
|
+
|
55
|
+
#### Replace Changed APIs
|
56
|
+
|
57
|
+
To maintain API consistency and clarity, we've adjusted the names of some APIs. Additionally, the `hoc` and `init` Hooks have been removed. Please use the new Hooks as replacements. The table below lists all changed APIs and their old and new counterparts:
|
58
|
+
|
59
|
+
| Old API | New API | Description |
|
60
|
+
| :------------ | :---------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
61
|
+
| `beforeRender` | `onBeforeRender` | Executed before application rendering. |
|
62
|
+
| `hoc` | `wrapRoot` | **Important Change:** Used to wrap the root component, achieving the functionality of a Higher-Order Component (HOC). Make sure to pass props to the original component. |
|
63
|
+
| `init` | `onBeforeRender` | **Important Change:** Execute initialization logic before application rendering. This replaces the previous `init` hook. Use `onBeforeRender` to perform any setup or initialization tasks that were previously done in `init`. This provides a single, consistent point for pre-rendering logic. |
|
64
|
+
|
65
|
+
**Explanation:**
|
66
|
+
- `onBeforeRender` replaces both the original `beforeRender` and `init`, used for pre-rendering logic and initialization, respectively.
|
67
|
+
- `wrapRoot` replaces `hoc` and is used to implement higher-order component functionality. It's crucial to pass props correctly when using `wrapRoot`.
|
68
|
+
|
69
|
+
**`wrapRoot` Usage Example:**
|
70
|
+
|
71
|
+
```typescript
|
72
|
+
{
|
73
|
+
setup: api => {
|
74
|
+
api.wrapRoot((App) => {
|
75
|
+
const AppWrapper = (props) => {
|
76
|
+
// Ensure props are passed to the original component
|
77
|
+
return <Provider value={xx}><App {...props}/></Provider>;
|
78
|
+
};
|
79
|
+
return AppWrapper;
|
80
|
+
});
|
81
|
+
}
|
82
|
+
}
|
83
|
+
```
|
84
|
+
|
85
|
+
### Frequently Asked Questions
|
86
|
+
|
87
|
+
**Q: Will my plugin still work correctly after migration?**
|
88
|
+
|
89
|
+
A: As long as you've correctly completed all the steps in this guide, your plugin should function properly. If you encounter any issues, please refer to the official Modern.js documentation or seek community support.
|
90
|
+
|
91
|
+
**Q: Do I have to migrate my plugin immediately?**
|
92
|
+
|
93
|
+
A: While the old plugin syntax remains partially compatible, we strongly recommend migrating as soon as possible. The new plugin system offers improved performance and richer functionality, making migration worthwhile in the long run.
|
94
|
+
|
95
|
+
**Q: Where can I find more information about the new plugin system?**
|
96
|
+
|
97
|
+
A: Please consult the official Modern.js documentation, especially the section on the plugin system. You can also refer to examples of other migrated plugins to understand best practices.
|
98
|
+
|
99
|
+
### Summary
|
100
|
+
|
101
|
+
With this detailed migration guide, we hope to help you smoothly transition your Runtime plugins to the new Modern.js plugin system. If you encounter any problems during the migration process, please don't hesitate to ask for assistance.
|
@@ -132,7 +132,7 @@ Modern.js 可以划分为三个核心部分:**CLI 工具、服务端和运行
|
|
132
132
|
|
133
133
|
在字节跳动内部,我们借助这些插件 API,结合公司内的基建和平台,封装出内部的企业级框架。如果你需要对 Modern.js 框架进行深度定制,也可以借助这些插件 API 来完成。
|
134
134
|
|
135
|
-
> 如果你对 Modern.js 的插件系统感兴趣,请阅读 [「Modern.js - 自定义插件」](https://modernjs.dev/plugin/plugin-system
|
135
|
+
> 如果你对 Modern.js 的插件系统感兴趣,请阅读 [「Modern.js - 自定义插件」](https://modernjs.dev/plugin/plugin-system.html)文档。
|
136
136
|
|
137
137
|
### 嵌套路由
|
138
138
|
|
@@ -9,7 +9,7 @@ sidebar_position: 9
|
|
9
9
|
|
10
10
|
用于配置自定义的 Modern.js 框架插件。
|
11
11
|
|
12
|
-
自定义插件的编写方式请参考 [如何编写插件](/plugin/plugin-system
|
12
|
+
自定义插件的编写方式请参考 [如何编写插件](/plugin/plugin-system)。
|
13
13
|
|
14
14
|
## 注意事项
|
15
15
|
|
@@ -33,7 +33,7 @@ Modern.js 中内置了三种不同的框架插件:
|
|
33
33
|
|
34
34
|
默认情况下,自定义插件会按照 `plugins` 数组的顺序依次执行,Modern.js 内置插件的执行时机早于自定义插件。
|
35
35
|
|
36
|
-
当插件内部使用了控制顺序的相关字段,比如 `pre`、`post` 时,会基于声明的字段对执行顺序进行调整,详见 [
|
36
|
+
当插件内部使用了控制顺序的相关字段,比如 `pre`、`post` 时,会基于声明的字段对执行顺序进行调整,详见 [插件结构](/plugin/plugin-system)。
|
37
37
|
|
38
38
|
## 示例
|
39
39
|
|
@@ -1,19 +1,20 @@
|
|
1
1
|
[
|
2
2
|
"introduction",
|
3
|
+
"plugin-system",
|
3
4
|
{
|
4
5
|
"type": "dir",
|
5
|
-
"name": "
|
6
|
-
"label": "
|
7
|
-
"collapsed": true
|
6
|
+
"name": "cli-plugins",
|
7
|
+
"label": "cli-plugins"
|
8
8
|
},
|
9
9
|
{
|
10
10
|
"type": "dir",
|
11
|
-
"name": "
|
12
|
-
"label": "
|
11
|
+
"name": "runtime-plugins",
|
12
|
+
"label": "runtime-plugins"
|
13
13
|
},
|
14
14
|
{
|
15
15
|
"type": "dir",
|
16
|
-
"name": "
|
17
|
-
"label": "
|
16
|
+
"name": "official",
|
17
|
+
"label": "official-plugins",
|
18
|
+
"collapsed": true
|
18
19
|
}
|
19
20
|
]
|
@@ -1 +1 @@
|
|
1
|
-
["
|
1
|
+
["api", "life-cycle", "migration"]
|