@modern-js/main-doc 2.35.1 → 2.36.0
Sign up to get free protection for your applications and to get access to all the features.
- package/docs/en/apis/app/hooks/src/routes.mdx +1 -1
- package/docs/en/components/debug-app.mdx +1 -1
- package/docs/en/components/turtorials-example-list.mdx +2 -0
- package/docs/en/configure/app/source/entries.mdx +7 -6
- package/docs/en/guides/advanced-features/bff/sdk.mdx +119 -0
- package/docs/en/guides/advanced-features/rspack-start.mdx +1 -1
- package/docs/en/guides/advanced-features/ssr.mdx +17 -17
- package/docs/en/guides/basic-features/data/_category_.json +4 -0
- package/docs/en/guides/basic-features/{data-fetch.mdx → data/data-fetch.mdx} +35 -27
- package/docs/en/guides/basic-features/data/data-write.mdx +241 -0
- package/docs/en/guides/basic-features/routes.mdx +7 -7
- package/docs/en/guides/concept/entries.mdx +31 -30
- package/docs/en/guides/get-started/quick-start.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/extend.mdx +0 -1
- package/docs/en/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
- package/docs/en/guides/topic-detail/framework-plugin/hook.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/implement.mdx +1 -2
- package/docs/en/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
- package/docs/en/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
- package/docs/en/guides/topic-detail/framework-plugin/relationship.mdx +2 -2
- package/docs/en/guides/topic-detail/generator/new/config.md +0 -5
- package/docs/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
- package/docs/en/tutorials/first-app/c05-loader.mdx +2 -2
- package/docs/en/tutorials/first-app/c06-model.mdx +4 -4
- package/docs/en/tutorials/first-app/c07-container.mdx +3 -3
- package/docs/en/tutorials/foundations/introduction.mdx +3 -2
- package/docs/zh/apis/app/hooks/src/routes.mdx +1 -1
- package/docs/zh/components/debug-app.mdx +1 -1
- package/docs/zh/components/micro-runtime-config.mdx +2 -2
- package/docs/zh/components/turtorials-example-list.mdx +2 -0
- package/docs/zh/configure/app/source/entries.mdx +7 -6
- package/docs/zh/guides/advanced-features/bff/sdk.mdx +119 -0
- package/docs/zh/guides/advanced-features/rspack-start.mdx +1 -1
- package/docs/zh/guides/advanced-features/ssr.mdx +16 -16
- package/docs/zh/guides/basic-features/data/_category_.json +4 -0
- package/docs/zh/guides/basic-features/{data-fetch.mdx → data/data-fetch.md} +31 -27
- package/docs/zh/guides/basic-features/data/data-write.mdx +236 -0
- package/docs/zh/guides/basic-features/routes.mdx +7 -7
- package/docs/zh/guides/concept/entries.mdx +34 -32
- package/docs/zh/guides/get-started/quick-start.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/extend.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/hook.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/implement.mdx +0 -1
- package/docs/zh/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
- package/docs/zh/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
- package/docs/zh/guides/topic-detail/framework-plugin/relationship.mdx +1 -1
- package/docs/zh/guides/topic-detail/generator/new/config.md +0 -5
- package/docs/zh/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
- package/docs/zh/guides/topic-detail/monorepo/create-sub-project.mdx +0 -14
- package/docs/zh/guides/topic-detail/monorepo/sub-project-interface.mdx +7 -43
- package/docs/zh/tutorials/first-app/c05-loader.mdx +2 -2
- package/docs/zh/tutorials/first-app/c06-model.mdx +3 -3
- package/docs/zh/tutorials/first-app/c07-container.mdx +3 -3
- package/docs/zh/tutorials/foundations/introduction.mdx +3 -2
- package/package.json +7 -7
@@ -0,0 +1,241 @@
|
|
1
|
+
---
|
2
|
+
title: Data writing
|
3
|
+
sidebar_position: 4
|
4
|
+
---
|
5
|
+
|
6
|
+
# Data writing
|
7
|
+
|
8
|
+
In the Data Loader chapter, the way Modern.js fetch data is introduced. You may encounter two problems.:
|
9
|
+
1. How to update the data in Data Loader?
|
10
|
+
2. How to write new data to the server?
|
11
|
+
|
12
|
+
EdenX's solution for this is DataAction.
|
13
|
+
|
14
|
+
## Basic Example
|
15
|
+
|
16
|
+
Data Action, like Data Loader, is also based on convention routing. Through Modern.js's [nested routing](/guides/basic-features/routes#routing-file-convention), each routing component (`layout.ts`, `page.ts` or `$.tsx`) can have a `data` file with the same name, and a function named `action` can be exported in the `data` file.
|
17
|
+
```bash
|
18
|
+
.
|
19
|
+
└── routes
|
20
|
+
└── user
|
21
|
+
├── layout.tsx
|
22
|
+
└── layout.data.ts
|
23
|
+
```
|
24
|
+
Define the following code in the file:
|
25
|
+
```ts title="routes/user/layout.data.ts"
|
26
|
+
import type { ActionFunction } from '@modern-js/runtime/router';
|
27
|
+
|
28
|
+
export const action: ActionFunction = ({ request }) => {
|
29
|
+
const newUser = await request.json();
|
30
|
+
const name = newUser.name;
|
31
|
+
return updateUserProfile(name);
|
32
|
+
}
|
33
|
+
```
|
34
|
+
|
35
|
+
```tsx title="routes/user/layout.tsx"
|
36
|
+
import {
|
37
|
+
useFetcher,
|
38
|
+
useLoaderData,
|
39
|
+
useParams,
|
40
|
+
Outlet
|
41
|
+
} from '@modern-js/runtime/router';
|
42
|
+
|
43
|
+
export default () => {
|
44
|
+
const userInfo = useLoaderData();
|
45
|
+
const { submit } = useFetcher();
|
46
|
+
const editUser = () => {
|
47
|
+
const newUser = {
|
48
|
+
name: 'Modern.js'
|
49
|
+
}
|
50
|
+
return submit(newUser, {
|
51
|
+
method: 'post',
|
52
|
+
encType: 'application/json',
|
53
|
+
})
|
54
|
+
}
|
55
|
+
return (
|
56
|
+
<div>
|
57
|
+
<button onClick={editUser}>edit user</button>
|
58
|
+
<div className="user-profile">
|
59
|
+
{userInfo}
|
60
|
+
</div>
|
61
|
+
<Outlet context={userInfo}></Outlet>
|
62
|
+
</div>
|
63
|
+
)
|
64
|
+
}
|
65
|
+
```
|
66
|
+
|
67
|
+
Here, when the submit is executed, the defined action function will be triggered; in the action function, the submitted data can be obtained through request (request.json, request.formData, etc.), and the data can be obtained, and then the data can be sent to the server.
|
68
|
+
|
69
|
+
After the action function is executed, the loader function code will be executed and the corresponding data and views will be updated.
|
70
|
+
|
71
|
+

|
72
|
+
|
73
|
+
|
74
|
+
|
75
|
+
## Why provide Data Action?
|
76
|
+
|
77
|
+
Data Action is mainly provided in Modern.js to keep the state of the UI and the server in sync, which can reduce the burden of state management.
|
78
|
+
|
79
|
+
The traditional state management method will hold the state on the client side and remotely respectively::
|
80
|
+
|
81
|
+

|
82
|
+
|
83
|
+
In Modern.js, we hope to help developers automatically synchronize the state of the client and server through Loader and Action::
|
84
|
+
|
85
|
+

|
86
|
+
|
87
|
+
If the data shared by the components in the project are the state of the main server, there is no need to introduce a client state management library in the project, request data through Data Loader, through [`useRouteLoaderData`](/guides/basic-fe Atures/data/data-fetch.md) shares data in subcomponents,
|
88
|
+
|
89
|
+
Modify and synchronize the state of the server through Data Action.
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
## `action` function
|
94
|
+
|
95
|
+
Like the `loader` function, the `action` function has two parameters, `params` and `request`:
|
96
|
+
|
97
|
+
### `params`
|
98
|
+
|
99
|
+
When the routing file passes through `[]`, it will be used as [dynamic routing](/guides/basic-features/routes#dynamic routing), and the dynamic routing fragment will be passed into the `action` function as a parameter::
|
100
|
+
|
101
|
+
```tsx
|
102
|
+
// routes/user/[id]/page.data.ts
|
103
|
+
import { ActionFunctionArgs } from '@modern-js/runtime/router';
|
104
|
+
|
105
|
+
export const action = async ({ params }: ActionFunctionArgs) => {
|
106
|
+
const { id } = params;
|
107
|
+
const res = await fetch(`https://api/user/${id}`);
|
108
|
+
return res.json();
|
109
|
+
};
|
110
|
+
```
|
111
|
+
|
112
|
+
When accessing `/user/123`, the parameter of the `action` function is `{ params: { id: '123' } }`.
|
113
|
+
|
114
|
+
|
115
|
+
### `request`
|
116
|
+
|
117
|
+
Through `request`, you can fetch data submitted by the client in the action function, such as `request.json()`, `request.formData()`, `request.json()`, etc.
|
118
|
+
|
119
|
+
For the specific API, please refer to [data type] (#data-type).
|
120
|
+
|
121
|
+
```tsx
|
122
|
+
// routes/user/[id]/page.data.ts
|
123
|
+
import { ActionFunctionArgs } from '@modern-js/runtime/router';
|
124
|
+
|
125
|
+
export const action = async ({ request }: ActionFunctionArgs) => {
|
126
|
+
const newUser = await request.json();
|
127
|
+
return updateUser(newUser);
|
128
|
+
};
|
129
|
+
```
|
130
|
+
|
131
|
+
### Return Value
|
132
|
+
|
133
|
+
The return value of the `action` function can be any serializable value or a [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) instance,
|
134
|
+
|
135
|
+
The data in the response can be accessed through [`useActionData`](https://reactrouter.com/en/main/hooks/use-action-data).
|
136
|
+
|
137
|
+
|
138
|
+
## useSubmit 和 useFetcher
|
139
|
+
|
140
|
+
### Differences
|
141
|
+
|
142
|
+
You can use [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit) or [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher) calls action, and the difference between them is through
|
143
|
+
|
144
|
+
`useSubmit` calls action, which will trigger the browser's navigation, and `useFetcher` will not trigger the browser's navigation.
|
145
|
+
|
146
|
+
useSubmit:
|
147
|
+
|
148
|
+
```ts
|
149
|
+
const submit = useSubmit();
|
150
|
+
submit(null, { method: "post", action: "/logout" });
|
151
|
+
```
|
152
|
+
|
153
|
+
useFetcher:
|
154
|
+
```ts
|
155
|
+
const { submit } = useFetcher();
|
156
|
+
submit(null, { method: "post", action: "/logout" });
|
157
|
+
```
|
158
|
+
|
159
|
+
The `submit` function has two input parameters, `method` and `action`. `method` is equivalent to `method` at the time of form submission. In most scenarios where data is written,the `method` can be passed into `post`.
|
160
|
+
|
161
|
+
`action` is used to specify which routing component `action` is triggered. If the `action` parameter is not passed in, the action of the current routing component will be triggered by default, that is,
|
162
|
+
the execution of submit in the `user/page.tsx` component or subcomponent will trigger the action defined in `user/page.data.ts`.
|
163
|
+
|
164
|
+
|
165
|
+
:::info
|
166
|
+
For more information about these two APIs, please refer to the relevant documents:
|
167
|
+
- [`useSubmit`](https://reactrouter.com/en/main/hooks/use-submit)
|
168
|
+
- [`useFetcher`](https://reactrouter.com/en/main/hooks/use-fetcher)
|
169
|
+
|
170
|
+
:::
|
171
|
+
|
172
|
+
|
173
|
+
### Type of data
|
174
|
+
|
175
|
+
The first parameter of the `submit` function can accept different types of values.
|
176
|
+
Such as `FormData`:
|
177
|
+
```ts
|
178
|
+
let formData = new FormData();
|
179
|
+
formData.append("cheese", "gouda");
|
180
|
+
submit(formData);
|
181
|
+
// In the action, you can get the data by request.json
|
182
|
+
```
|
183
|
+
|
184
|
+
Or the value of type `URLSearchParams`:
|
185
|
+
```ts
|
186
|
+
let searchParams = new URLSearchParams();
|
187
|
+
searchParams.append("cheese", "gouda");
|
188
|
+
submit(searchParams);
|
189
|
+
// In the action, you can get the data by request.json
|
190
|
+
```
|
191
|
+
|
192
|
+
Or any acceptable value of the `URLSearchParams` constructor:
|
193
|
+
```ts
|
194
|
+
submit("cheese=gouda&toasted=yes");
|
195
|
+
submit([
|
196
|
+
["cheese", "gouda"],
|
197
|
+
["toasted", "yes"],
|
198
|
+
]);
|
199
|
+
// In the action, you can get the data by request.json
|
200
|
+
```
|
201
|
+
|
202
|
+
By default, if the first parameter in the `submit` function is an object, the corresponding data will be encoded as `formData`:
|
203
|
+
|
204
|
+
```ts
|
205
|
+
submit(
|
206
|
+
{ key: "value" },
|
207
|
+
{
|
208
|
+
method: "post",
|
209
|
+
encType: "application/x-www-form-urlencoded",
|
210
|
+
}
|
211
|
+
);
|
212
|
+
|
213
|
+
// In the action, you can get the data by request.formData
|
214
|
+
```
|
215
|
+
|
216
|
+
it can also be specified as json encoding:
|
217
|
+
|
218
|
+
```tsx
|
219
|
+
submit(
|
220
|
+
{ key: "value" },
|
221
|
+
{ method: "post", encType: "application/json" }
|
222
|
+
);
|
223
|
+
|
224
|
+
submit('{"key":"value"}', {
|
225
|
+
method: "post",
|
226
|
+
encType: "application/json",
|
227
|
+
});
|
228
|
+
|
229
|
+
// In the action, you can get the data by request.json
|
230
|
+
```
|
231
|
+
|
232
|
+
or submit plain text:
|
233
|
+
```ts
|
234
|
+
submit("value", { method: "post", encType: "text/plain" });
|
235
|
+
// In the action, you can get the data by request.text
|
236
|
+
```
|
237
|
+
|
238
|
+
|
239
|
+
## CSR 和 SSR
|
240
|
+
|
241
|
+
Like Data Loader, in the SSR project, Data Action is executed on the server (the framework will automatically send a request to trigger Data Action), while in the CSR project, Data Action is executed on the client.
|
@@ -161,7 +161,7 @@ These properties as defined are available via the [`useMatches`](https://reactro
|
|
161
161
|
|
162
162
|
```ts title="routes/layout.ts"
|
163
163
|
export default () => {
|
164
|
-
const matches = useMatches;
|
164
|
+
const matches = useMatches();
|
165
165
|
const breadcrumbs = matches.map(
|
166
166
|
matchedRoute => matchedRoute?.handle?.breadcrumbName,
|
167
167
|
);
|
@@ -186,7 +186,7 @@ The `routes/[id]/page.tsx` file will be converted to the `/:id` route. Except fo
|
|
186
186
|
|
187
187
|
In the component, you can use [useParams](/apis/app/runtime/router/router#useparams) to get the corresponding named parameter.
|
188
188
|
|
189
|
-
In the loader, params will be passed as the input parameter of the [loader function](/guides/basic-features/data-fetch#loader-function), and you can get the parameter value through `params.xxx`.
|
189
|
+
In the loader, params will be passed as the input parameter of the [loader function](/guides/basic-features/data/data-fetch#loader-function), and you can get the parameter value through `params.xxx`.
|
190
190
|
|
191
191
|
### Dynamic Optional Routing
|
192
192
|
|
@@ -206,7 +206,7 @@ The `routes/user/[id$]/page.tsx` file will be converted to the `/user/:id?` rout
|
|
206
206
|
|
207
207
|
In the component, you can use [useParams](/apis/app/runtime/router/router#useparams) to get the corresponding named parameter.
|
208
208
|
|
209
|
-
In the loader, params will be passed as the input parameter of the [loader function](/guides/basic-features/data-fetch#loader-function), and you can get the parameter value through `params.xxx`.
|
209
|
+
In the loader, params will be passed as the input parameter of the [loader function](/guides/basic-features/data/data-fetch#loader-function), and you can get the parameter value through `params.xxx`.
|
210
210
|
|
211
211
|
### Catch-all Routing
|
212
212
|
|
@@ -351,12 +351,12 @@ Similarly, when the route jumps from `/` or `/blog` to `/blog/123`, if the JS Ch
|
|
351
351
|
|
352
352
|
### Redirect
|
353
353
|
|
354
|
-
You can use a [Data Loader](/guides/basic-features/data-fetch) file to redirect a route. For example, if you have a `routes/user/page.tsx` file and want to redirect the corresponding route, you can create a `routes/user/page.
|
354
|
+
You can use a [Data Loader](/guides/basic-features/data/data-fetch) file to redirect a route. For example, if you have a `routes/user/page.tsx` file and want to redirect the corresponding route, you can create a `routes/user/page.data.ts` file:
|
355
355
|
|
356
|
-
```ts title="routes/user/page.
|
356
|
+
```ts title="routes/user/page.data.ts"
|
357
357
|
import { redirect } from '@modern-js/runtime/router';
|
358
358
|
|
359
|
-
export
|
359
|
+
export const loader = () => {
|
360
360
|
const user = await getUser();
|
361
361
|
if (!user) {
|
362
362
|
return redirect('/login');
|
@@ -502,7 +502,7 @@ To further improve the user experience and reduce loading time, Modern.js suppor
|
|
502
502
|
:::info
|
503
503
|
|
504
504
|
- This feature is currently only supported in Webpack projects and not yet supported in Rspack projects.
|
505
|
-
- Preloading data currently only preloads the data returned by the [Data Loader](/guides/basic-features/data-fetch) in SSR projects.
|
505
|
+
- Preloading data currently only preloads the data returned by the [Data Loader](/guides/basic-features/data/data-fetch) in SSR projects.
|
506
506
|
|
507
507
|
:::
|
508
508
|
|
@@ -32,7 +32,7 @@ The project initialized by Modern.js is a single entry (SPA) project, with the f
|
|
32
32
|
|
33
33
|
In a Modern.js project, you can easily switch from single entry to multiple entries by running `pnpm run new` in the project directory and creating an entry:
|
34
34
|
|
35
|
-
```
|
35
|
+
```text
|
36
36
|
? Please select the operation you want: Create Element
|
37
37
|
? Please select the type of element to create: New "entry"
|
38
38
|
? Please fill in the entry name: new-entry
|
@@ -56,7 +56,7 @@ After running the command, Modern.js will automatically generate a new entry dir
|
|
56
56
|
|
57
57
|
The original entry code has been moved to a directory with the same name as the `name` field in `package.json`, and a `new-entry` entry directory has been created.
|
58
58
|
|
59
|
-
|
59
|
+
You can run `pnpm run dev` to start the development server. At this point, you will see a new route named `/new-entry` added, and the existing page routes remain unchanged.
|
60
60
|
|
61
61
|
:::tip
|
62
62
|
Modern.js will use the entry with the same name as the `name` field in `package.json` as the main entry. The route of the main entry is `/`, and the route of other entries is `/{entryName}`.
|
@@ -76,7 +76,9 @@ import EntryMode from '@site-docs-en/components/entry-mode.mdx';
|
|
76
76
|
By default, Modern.js scans the files under `src/` before starting the project, identifies the entry, and generates the corresponding server-side route.
|
77
77
|
|
78
78
|
:::tip
|
79
|
-
|
79
|
+
|
80
|
+
- You can custom the recognition directory for page entries by using [source.entriesDir](/configure/app/source/entries-dir).
|
81
|
+
- If you need to customize the entry points, please refer to [Custom Entries](#custom-entries).
|
80
82
|
|
81
83
|
:::
|
82
84
|
|
@@ -98,7 +100,7 @@ When the project is not a single entry application, Modern.js will further look
|
|
98
100
|
|
99
101
|
### Framework Mode Entry
|
100
102
|
|
101
|
-
|
103
|
+
The framework mode refers to the need to use the framework capabilities of Modern.js, such as nested routing, SSR, and integrated BFF, etc. Under this kind of entry convention, the entry defined by the developer is not the actual compilation entry. When Modern.js is launched, it generates a wrapped entry, and the real entry can be found at `node_modules/.modern/[entryName]/index.js`.
|
102
104
|
|
103
105
|
#### Conventional Routing
|
104
106
|
|
@@ -146,7 +148,7 @@ export default (App: React.ComponentType, bootstrap: () => void) => {
|
|
146
148
|
// do something before bootstrap...
|
147
149
|
initSomething().then(() => {
|
148
150
|
bootstrap();
|
149
|
-
})
|
151
|
+
});
|
150
152
|
};
|
151
153
|
```
|
152
154
|
|
@@ -181,9 +183,11 @@ export default AppWrapper;
|
|
181
183
|
|
182
184
|
### Build Mode Entry
|
183
185
|
|
184
|
-
Build mode refers to
|
186
|
+
Build mode refers to the mode where the entry point of the page is not automatically generated by Modern.js, but is fully defined by the developers themselves.
|
187
|
+
|
188
|
+
When there is an `index.[jt]sx` file in the entry directory and it is not exported as a function using `export default`, this type of file will be recognized as the entry module for webpack or Rspack.
|
185
189
|
|
186
|
-
|
190
|
+
In this case, Modern.js will not generate the entry code automatically. Therefore, you need to manually mount the component to the DOM node, for example:
|
187
191
|
|
188
192
|
```js title=src/index.jsx
|
189
193
|
import React from 'react';
|
@@ -193,42 +197,39 @@ import App from './App';
|
|
193
197
|
ReactDOM.render(<App />, document.getElementById('root'));
|
194
198
|
```
|
195
199
|
|
196
|
-
Modern.js
|
200
|
+
This approach is equivalent to enabling the [source.entries.disableMount](/configure/app/source/entries) option in Modern.js. When you use this approach, **you will not be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the modern.config.js file will no longer take effect.
|
197
201
|
|
198
|
-
##
|
202
|
+
## Custom Entries
|
199
203
|
|
200
|
-
|
204
|
+
In some cases, you may need to customize the entry configuration instead of using the entry conventions provided by Modern.js.
|
201
205
|
|
202
|
-
|
206
|
+
For example, if you want to migrate a non-Modern.js project to Modern.js and it is not structured according to Modern.js directory structure, there might be some migration costs involved in changing it to the conventional structure. In such cases, you can custom the entries.
|
203
207
|
|
204
|
-
|
205
|
-
export default defineConfig({
|
206
|
-
source: {
|
207
|
-
entries: {
|
208
|
-
// Specify a new entry named entry_customize
|
209
|
-
entry_customize: './src/home/test/index.ts',
|
210
|
-
},
|
211
|
-
// Disable default ingress scanning
|
212
|
-
disableDefaultEntries: true,
|
213
|
-
},
|
214
|
-
});
|
215
|
-
```
|
208
|
+
Modern.js provides the following configuration options that you can set in [modern.config.ts](/configure/app/usage):
|
216
209
|
|
217
|
-
|
210
|
+
- [source.entries](/configure/app/source/entries): Used to set custom entry objects.
|
211
|
+
- [source.disableDefaultEntries](/configure/app/source/disable-default-entries): Used to disable Modern.js's default entry scanning behavior. When you use custom entries, parts of your project structure might coincidentally match the Modern.js conventional directory structure, but you may not want Modern.js to generate entry configurations for them. Enabling this option can help avoid this issue.
|
218
212
|
|
219
|
-
|
213
|
+
### Example
|
220
214
|
|
221
|
-
|
215
|
+
Here is an example of a custom entry point. You can also refer to the documentation of the corresponding configuration options for more usage.
|
222
216
|
|
223
217
|
```ts title="modern.config.ts"
|
224
218
|
export default defineConfig({
|
225
219
|
source: {
|
220
|
+
entries: {
|
221
|
+
// Specify an entry named 'my-entry'
|
222
|
+
'my-entry': {
|
223
|
+
// Path to the entry module
|
224
|
+
entry: './src/my-page/index.tsx',
|
225
|
+
// Disable automatic generation of entry code by Modern.js
|
226
|
+
disableMount: true,
|
227
|
+
},
|
228
|
+
},
|
229
|
+
// Disable entry scanning behavior
|
226
230
|
disableDefaultEntries: true,
|
227
231
|
},
|
228
232
|
});
|
229
233
|
```
|
230
234
|
|
231
|
-
|
232
|
-
For detailed usage, please refer to [source.entries](/configure/app/source/entries) and [source.disableDefaultEntries](/configure/app/source/disable-default-entries).
|
233
|
-
|
234
|
-
:::
|
235
|
+
Note that when you enable `disableMount`, **you won't be able to use the runtime capabilities of the Modern.js framework**, such as the `runtime` configuration in the modern.config.ts file.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
title: Hook Model
|
3
2
|
sidebar_position: 2
|
4
3
|
---
|
4
|
+
|
5
5
|
# Hook Model
|
6
6
|
|
7
7
|
First, let's introduce some content about the basic plugin system in Modern.js, including the working mode of the Hook model, the operating mode of each Hook model, and the working mode of the Manager.
|
@@ -1,5 +1,4 @@
|
|
1
1
|
---
|
2
|
-
title: Plugin API
|
3
2
|
sidebar_position: 6
|
4
3
|
---
|
5
4
|
|
@@ -79,26 +78,43 @@ Used to retrieve the runtime context of the application.
|
|
79
78
|
const useAppContext: () => IAppContext;
|
80
79
|
|
81
80
|
interface IAppContext {
|
81
|
+
/** Root directory of the current project */
|
82
82
|
appDirectory: string;
|
83
|
+
/** Source code directory */
|
84
|
+
srcDirectory: string;
|
85
|
+
/** Directory for output files */
|
86
|
+
distDirectory: string;
|
87
|
+
/** Directory for shared modules */
|
88
|
+
sharedDirectory: string;
|
89
|
+
/** Directory for framework temp files */
|
90
|
+
internalDirectory: string;
|
91
|
+
/** node_modules directory */
|
92
|
+
nodeModulesDirectory: string;
|
93
|
+
/** Path to the configuration file */
|
83
94
|
configFile: string | false;
|
95
|
+
/** IPv4 address of the current machine */
|
84
96
|
ip?: string;
|
97
|
+
/** Port number of the development server */
|
85
98
|
port?: number;
|
86
|
-
|
99
|
+
/** Name of the current project's package.json */
|
87
100
|
packageName: string;
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
internalDirectory: string;
|
92
|
-
plugins: {
|
93
|
-
cli?: any;
|
94
|
-
server?: any;
|
95
|
-
}[];
|
101
|
+
/** Currently registered plugins */
|
102
|
+
plugins: any[];
|
103
|
+
/** Information for entry points */
|
96
104
|
entrypoints: Entrypoint[];
|
105
|
+
/** Information for server routes */
|
97
106
|
serverRoutes: ServerRoute[];
|
98
|
-
|
107
|
+
/** Tools type of the current project */
|
108
|
+
toolsType?: 'app-tools' | 'module-tools' | 'monorepo-tools';
|
109
|
+
/** Type of the bundler being used */
|
110
|
+
bundlerType?: 'webpack' | 'rspack' | 'esbuild';
|
99
111
|
}
|
100
112
|
```
|
101
113
|
|
114
|
+
:::tip
|
115
|
+
Some fields in the AppContext are dynamically set and will change as the program runs. Therefore, when plugins read these fields at different times, they may get different values.
|
116
|
+
:::
|
117
|
+
|
102
118
|
### useHookRunners
|
103
119
|
|
104
120
|
Used to retrieve the executor of Hooks and trigger the execution of specific Hooks.
|
@@ -116,3 +132,7 @@ export const myPlugin = (): CliPlugin => ({
|
|
116
132
|
},
|
117
133
|
});
|
118
134
|
```
|
135
|
+
|
136
|
+
:::tip
|
137
|
+
Please avoid executing the built-in hooks, as it may break the internal execution logic of the framework.
|
138
|
+
:::
|
@@ -1,8 +1,8 @@
|
|
1
1
|
---
|
2
|
-
title: Relationship
|
3
2
|
sidebar_position: 4
|
4
3
|
---
|
5
|
-
|
4
|
+
|
5
|
+
# Relationship
|
6
6
|
|
7
7
|
The plugin configuration object in Modern.js provides a series of fields to control plugin order, mutual exclusion, and other capabilities. The available fields are as follows:
|
8
8
|
|
@@ -129,13 +129,8 @@ Question: Please select the type of project you want to create.
|
|
129
129
|
Options:
|
130
130
|
|
131
131
|
- Web App -- mwa
|
132
|
-
|
133
|
-
- Web App (Test)-- mwa_test
|
134
|
-
|
135
132
|
- Npm Module -- module
|
136
133
|
|
137
|
-
- Npm Module (Inner) -- inner_module
|
138
|
-
|
139
134
|
### packageName
|
140
135
|
|
141
136
|
Question: Please fill in the project name
|
@@ -44,12 +44,12 @@ defineConfig(App, {
|
|
44
44
|
return [
|
45
45
|
{
|
46
46
|
name: 'Table',
|
47
|
-
entry: 'http://localhost:
|
47
|
+
entry: 'http://localhost:8081',
|
48
48
|
// activeWhen: '/table'
|
49
49
|
},
|
50
50
|
{
|
51
51
|
name: 'Dashboard',
|
52
|
-
entry: 'http://localhost:
|
52
|
+
entry: 'http://localhost:8082',
|
53
53
|
// activeWhen: '/dashboard'
|
54
54
|
},
|
55
55
|
];
|
@@ -18,7 +18,7 @@ pnpm add faker@5
|
|
18
18
|
pnpm add @types/faker@5 -D
|
19
19
|
```
|
20
20
|
|
21
|
-
Create `src/routes/page.
|
21
|
+
Create `src/routes/page.data.ts`:
|
22
22
|
|
23
23
|
```tsx
|
24
24
|
import { name, internet } from 'faker';
|
@@ -32,7 +32,7 @@ type LoaderData = {
|
|
32
32
|
}[];
|
33
33
|
};
|
34
34
|
|
35
|
-
export
|
35
|
+
export const loader = async (): Promise<LoaderData> => {
|
36
36
|
const data = new Array(20).fill(0).map(() => {
|
37
37
|
const firstName = name.firstName();
|
38
38
|
return {
|
@@ -195,9 +195,9 @@ const Item = ({
|
|
195
195
|
export default Item;
|
196
196
|
```
|
197
197
|
|
198
|
-
Next, we add `src/routes.page.
|
198
|
+
Next, we add `src/routes.page.data` and modify `src/routes/page.tsx` to pass more parameters to the `<Item>` component:
|
199
199
|
|
200
|
-
```tsx title="src/routes/page.
|
200
|
+
```tsx title="src/routes/page.data.ts"
|
201
201
|
export type LoaderData = {
|
202
202
|
code: number;
|
203
203
|
data: {
|
@@ -207,7 +207,7 @@ export type LoaderData = {
|
|
207
207
|
}[];
|
208
208
|
};
|
209
209
|
|
210
|
-
export
|
210
|
+
export const loader = async (): Promise<LoaderData> => {
|
211
211
|
const data = new Array(20).fill(0).map(() => {
|
212
212
|
const firstName = name.firstName();
|
213
213
|
return {
|
@@ -233,7 +233,7 @@ import { List } from 'antd';
|
|
233
233
|
import { name, internet } from 'faker';
|
234
234
|
import Item from '../components/Item';
|
235
235
|
import contacts from '../models/contacts';
|
236
|
-
import type { LoaderData } from './page.
|
236
|
+
import type { LoaderData } from './page.data';
|
237
237
|
|
238
238
|
function Index() {
|
239
239
|
const { data } = useLoaderData() as LoaderData;
|