@modern-js/main-doc 0.0.0-next-20221227040741 → 0.0.0-next-20221227140603
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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +20 -22
- package/en/docusaurus-plugin-content-docs/current/apis/app/hooks/src/index_.md +1 -1
- package/en/docusaurus-plugin-content-docs/current/apis/app/hooks/src/pages.md +1 -1
- package/en/docusaurus-plugin-content-docs/current/apis/app/hooks/src/routes.md +86 -0
- package/en/docusaurus-plugin-content-docs/current/configure/app/dev/with-master-app.md +31 -0
- package/en/docusaurus-plugin-content-docs/current/configure/app/tools/tailwindcss.md +16 -22
- package/en/docusaurus-plugin-content-docs/current/guides/advanced-features/code-split.md +27 -22
- package/en/docusaurus-plugin-content-docs/current/guides/basic-features/css/tailwindcss.md +30 -35
- package/en/docusaurus-plugin-content-docs/current/guides/basic-features/data-fetch.md +399 -0
- package/en/docusaurus-plugin-content-docs/current/guides/basic-features/html.md +5 -5
- package/package.json +3 -3
- package/zh/apis/app/hooks/src/index_.md +1 -1
- package/zh/apis/app/hooks/src/pages.md +1 -1
- package/zh/apis/app/hooks/src/routes.md +89 -0
- package/zh/configure/app/dev/with-master-app.md +32 -0
- package/zh/configure/app/runtime/master-app.md +16 -2
- package/zh/configure/app/tools/tailwindcss.md +16 -23
- package/zh/guides/advanced-features/bff/function.md +24 -2
- package/zh/guides/advanced-features/code-split.md +26 -22
- package/zh/guides/basic-features/css/tailwindcss.md +31 -35
- package/zh/guides/basic-features/data-fetch.md +6 -6
- package/zh/guides/basic-features/html.md +5 -5
- package/zh/guides/basic-features/routes.md +37 -3
- package/zh/guides/topic-detail/framework-plugin/implement.md +54 -6
- package/zh/components/micro-master-manifest-config.md +0 -15
@@ -7,6 +7,405 @@ Modern.js provides out of the box fetching data capabilities, developers can use
|
|
7
7
|
|
8
8
|
It should be noted that these APIs do not help applications to initiate requests, but help developers better manage the relationship between data and routing.
|
9
9
|
|
10
|
+
## Data loader(recommend)
|
11
|
+
|
12
|
+
Modern.js recommends the use of conventional routing for route management. With Modern.js' [conventional (nested) routing](/docs/guides/basic-features/routes#conventional-routing), each routing component (`layout.ts` or `page.ts`) can export a function `loader` that can be executed before the component renders, providing data to the routing component.
|
13
|
+
|
14
|
+
:::info
|
15
|
+
Modern.js v1 supports getting data by [useLoader](#useloaderold), which is no longer the recommended usage and it is not recommended to mix both except for migration process.
|
16
|
+
:::
|
17
|
+
|
18
|
+
### Basic example
|
19
|
+
|
20
|
+
Each routing component can export a `loader` function and get the data via the `useLoaderData` function:
|
21
|
+
|
22
|
+
```ts
|
23
|
+
// routes/user/page.tsx
|
24
|
+
import { useLoaderData } from '@modern-js/runtime/router';
|
25
|
+
|
26
|
+
export const loader = async(): ProfileData => {
|
27
|
+
const res = await fetch('https://api/user/profile');
|
28
|
+
return await res.json();
|
29
|
+
}
|
30
|
+
|
31
|
+
export default function UserPage() {
|
32
|
+
const profileData = useLoaderData() as ProfileData;
|
33
|
+
return <div>{profileData}</div>;
|
34
|
+
}
|
35
|
+
```
|
36
|
+
|
37
|
+
In a CSR environment, the `loader` function is executed on the client side, and the browser API can be used within the `loader` function (but it is usually not needed and not recommended).
|
38
|
+
|
39
|
+
In an SSR environment, the `loader` function will only be executed on the server side, regardless of the first screen or the navigation on the client side, where any Node.js API can be called, and any dependencies and code used here will not be included in the client bundle.
|
40
|
+
|
41
|
+
:::info
|
42
|
+
In later versions, Modern.js may support `loader` functions running on the server side as well in CSR environments to improve performance and security, so here it is recommended to keep the loader as pure as possible and only do data fetching scenarios.
|
43
|
+
:::
|
44
|
+
|
45
|
+
When navigating on the client side, all loader functions under `/user` and `/user/profile` are executed (requested) in parallel based on Modern.js's [conventional routing](/docs/guides/basic-features/routes), i.e. when accessing `/user/profile`, the loader functions under `/user` and `/user/profile` are executed (requested) in parallel to improve client-side performance.
|
46
|
+
|
47
|
+
### Loader is defined in a separate file
|
48
|
+
|
49
|
+
In addition to supporting the export of `loader` functions from front-end components, Modern.js also supports placing `loader` functions in a separate file, by defining the `loader` function in a separate file, there is no need to pay attention to [side effect](#side-effects) related considerations, but it is important to note that routing components such as `layout.ts` and the loader file `layout.loader.ts` cannot introduce each other's code, if you need the related types you can use `import type`, you can see the following example:
|
50
|
+
|
51
|
+
```
|
52
|
+
.
|
53
|
+
└── routes
|
54
|
+
├── layout.tsx
|
55
|
+
└── user
|
56
|
+
├── layout.tsx
|
57
|
+
├── layout.loader.ts
|
58
|
+
├── page.tsx
|
59
|
+
└── page.loader.ts
|
60
|
+
```
|
61
|
+
|
62
|
+
For example, `loader` in [basic example](#basic-example) can be replaced with the following code:
|
63
|
+
|
64
|
+
```tsx
|
65
|
+
// routes/user/page.loader.tsx
|
66
|
+
type ProfileData = { /* some type declarations */ }
|
67
|
+
|
68
|
+
export const loader = async(): ProfileData => {
|
69
|
+
const res = await fetch('https://api/user/profile');
|
70
|
+
return await res.json();
|
71
|
+
}
|
72
|
+
|
73
|
+
// routes/user/page.tsx
|
74
|
+
import { useLoaderData } from '@modern-js/runtime/router';
|
75
|
+
// here you can only use import type
|
76
|
+
import type { ProfileData } from './page.loader';
|
77
|
+
|
78
|
+
export default function UserPage() {
|
79
|
+
const profileData = useLoaderData() as ProfileData;
|
80
|
+
return <div>{profileData}</div>;
|
81
|
+
}
|
82
|
+
```
|
83
|
+
|
84
|
+
### `loader` function
|
85
|
+
|
86
|
+
The `loader` function has two input parameters:
|
87
|
+
|
88
|
+
##### `Params`
|
89
|
+
|
90
|
+
When a routing file is passed through `[]`, it is passed as a [dynamic route](/docs/guides/basic-features/routes#dynamic-route) and the dynamic route fragment is passed as an argument to the loader function:
|
91
|
+
|
92
|
+
```tsx
|
93
|
+
// routes/user/[id]/page.tsx
|
94
|
+
import { LoaderArgs } from '@modern-js/runtime/router';
|
95
|
+
|
96
|
+
export const loader = async({ params }: LoaderArgs) => {
|
97
|
+
const { id } = params;
|
98
|
+
const res = await fetch(`https://api/user/${id}`);
|
99
|
+
return res.json();
|
100
|
+
}
|
101
|
+
```
|
102
|
+
|
103
|
+
当访问 `/user/123` 时,`loader` 函数的参数为 `{ params: { id: '123' } }`。
|
104
|
+
|
105
|
+
#### `request`
|
106
|
+
|
107
|
+
`request` is a [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) instance.
|
108
|
+
|
109
|
+
A common usage scenario is to obtain query parameters via `request`:
|
110
|
+
```tsx
|
111
|
+
// routes/user/[id]/page.tsx
|
112
|
+
import { LoaderArgs } from '@modern-js/runtime/router';
|
113
|
+
|
114
|
+
export const loader = async({ request }: LoaderArgs) => {
|
115
|
+
const url = new URL(request.url);
|
116
|
+
const userId = url.searchParams.get("id");
|
117
|
+
return queryUser(userId);
|
118
|
+
}
|
119
|
+
```
|
120
|
+
|
121
|
+
#### Return value
|
122
|
+
|
123
|
+
`loader` 函数的返回值可以是任何可序列化的内容,也可以是一个 [Fetch Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) 实例:
|
124
|
+
|
125
|
+
```tsx
|
126
|
+
export const loader = async(): ProfileData => {
|
127
|
+
return {
|
128
|
+
message: 'hello world',
|
129
|
+
}
|
130
|
+
}
|
131
|
+
```
|
132
|
+
|
133
|
+
By default, the response `Content-type` returned by `loader` is `application/json` and `status` is 200, which you can set by customizing `Response`:
|
134
|
+
|
135
|
+
```tsx
|
136
|
+
export const loader = async(): ProfileData => {
|
137
|
+
const data = {message: 'hello world'};
|
138
|
+
return new Response(JSON.stringify(data), {
|
139
|
+
status: 200,
|
140
|
+
headers: {
|
141
|
+
"Content-Type": "application/json; utf-8",
|
142
|
+
},
|
143
|
+
});
|
144
|
+
}
|
145
|
+
```
|
146
|
+
|
147
|
+
### Request API
|
148
|
+
|
149
|
+
Modern.js does a polyfill of the `fetch` API to initiate requests, which is consistent with the browser's `fetch` API, but can also be used on the server side to initiate requests, meaning that both CSRs and SSRs can use the unified `fetch` API for data fetching:
|
150
|
+
|
151
|
+
```tsx
|
152
|
+
export async function loader(){
|
153
|
+
const res = await fetch('https://api/user/profile');
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
### Error handling
|
158
|
+
|
159
|
+
In the `loader` function, errors can be handled by `throw error` or `throw response`. When an error is thrown in the `loader` function, Modern.js will stop executing the code in the current loader and switch the front-end UI to the defined [`ErrorBoundary`](/docs/guides/basic-features/routes#errorboundary) component.
|
160
|
+
|
161
|
+
```tsx
|
162
|
+
// routes/user/profile/page.tsx
|
163
|
+
export async function loader(){
|
164
|
+
const res = await fetch('https://api/user/profile');
|
165
|
+
if(!res.ok){
|
166
|
+
throw res;
|
167
|
+
}
|
168
|
+
return res.json();
|
169
|
+
}
|
170
|
+
|
171
|
+
// routes/user/profile/error.tsx
|
172
|
+
import { useRouteError } from '@modern-js/runtime/router';
|
173
|
+
const ErrorBoundary = () => {
|
174
|
+
const error = useRouteError() as Response;
|
175
|
+
return (
|
176
|
+
<div>
|
177
|
+
<h1>{error.status}</h1>
|
178
|
+
<h2>{error.statusText}</h2>
|
179
|
+
</div>
|
180
|
+
);
|
181
|
+
};
|
182
|
+
|
183
|
+
export default ErrorBoundary;
|
184
|
+
```
|
185
|
+
|
186
|
+
### Get data from upper level components
|
187
|
+
|
188
|
+
In many cases, the child component needs to access the data in the ancestor's loader, and you can easily access the ancestor's data with `useRouteLoaderData`: `useRouteLoaderData`:
|
189
|
+
|
190
|
+
```tsx
|
191
|
+
// routes/user/profile/page.tsx
|
192
|
+
import { useRouteLoaderData } from '@modern-js/runtime/router';
|
193
|
+
|
194
|
+
export default function UserLayout() {
|
195
|
+
// Get the data returned by the loader in routes/user/layout.tsx
|
196
|
+
const data = useRouteLoaderData('user/layout');
|
197
|
+
return (
|
198
|
+
<div>
|
199
|
+
<h1>{data.name}</h1>
|
200
|
+
<h2>{data.age}</h2>
|
201
|
+
</div>
|
202
|
+
);
|
203
|
+
}
|
204
|
+
```
|
205
|
+
|
206
|
+
`userRouteLoaderData` takes one parameter `routeId`,When using conventional routing, Modern.js will automatically generate `routeId` for you. The value of `routeId` is the path of the corresponding component relative to `src/routes`, as in the example above, the child component wants to get the data returned by the loader in `routes/user/layout.tsx`, the value of `routeId` is `user/layout`.
|
207
|
+
|
208
|
+
In a multi-entry (MPA) scenario, the value of `routeId` needs to be added to the name of the corresponding entry, and the entry name is usually the entry directory name if not specified, such as the following directory structure:
|
209
|
+
```bash
|
210
|
+
.
|
211
|
+
└── src
|
212
|
+
├── entry1
|
213
|
+
│ ├── layout.tsx
|
214
|
+
└── entry2
|
215
|
+
└── layout.tsx
|
216
|
+
```
|
217
|
+
|
218
|
+
If you want to get the data returned by the loader in `entry1/layout.tsx`, the value of `routeId` is `entry1_layout`.
|
219
|
+
|
220
|
+
### (WIP)Loading UI
|
221
|
+
|
222
|
+
:::info
|
223
|
+
This feature is currently experimental and the API may be adjusted in the future.
|
224
|
+
Currently, only CSR is supported, so stay tuned for Streaming SSR.
|
225
|
+
:::
|
226
|
+
|
227
|
+
Because fetching data is asynchronous, it is often necessary to display a loading UI before the data fetching is complete, and the following is a basic example, assuming the following directory structure:
|
228
|
+
|
229
|
+
```bash
|
230
|
+
.
|
231
|
+
└── routes
|
232
|
+
├── layout.tsx
|
233
|
+
└── user
|
234
|
+
├── layout.tsx
|
235
|
+
└── page.ts
|
236
|
+
```
|
237
|
+
|
238
|
+
We get the user's detailed data in `user/layout.tsx` and want to show a loading UI before getting the data.
|
239
|
+
|
240
|
+
First, add a `loading.tsx` component to the `routes` directory in your project, which will take effect for all routes in the subdirectory (e.g. user):
|
241
|
+
```bash
|
242
|
+
.
|
243
|
+
└── routes
|
244
|
+
├── layout.tsx
|
245
|
+
└── user
|
246
|
+
├── layout.tsx
|
247
|
+
└── page.ts
|
248
|
+
```
|
249
|
+
|
250
|
+
:::info
|
251
|
+
For specific usage of the loading component, see [loading](/docs/guides/basic-features/routes#loading)
|
252
|
+
:::
|
253
|
+
|
254
|
+
Then, add the following code to `user/layout.tsx`:
|
255
|
+
|
256
|
+
```tsx title="routes/user/layout.tsx"
|
257
|
+
import {
|
258
|
+
Await,
|
259
|
+
defer,
|
260
|
+
useLoaderData,
|
261
|
+
Outlet
|
262
|
+
} from '@modern-js/runtime/router';
|
263
|
+
|
264
|
+
export const loader = () => {
|
265
|
+
return defer({
|
266
|
+
// fetchUserInfo 是一个异步函数,返回用户信息
|
267
|
+
userInfo: fetchUserInfo(),
|
268
|
+
})
|
269
|
+
}
|
270
|
+
|
271
|
+
export default function UserLayout() {
|
272
|
+
const { userInfo } = useLoaderData() as {userInfo: Promise<UserInfo>};
|
273
|
+
return (
|
274
|
+
<div>
|
275
|
+
<Await resolve={userInfo} children={userInfo => (
|
276
|
+
<div>
|
277
|
+
<span>{userInfo.name}</span>
|
278
|
+
<span>{userInfo.age}</span>
|
279
|
+
<Outlet>
|
280
|
+
</div>
|
281
|
+
)}>
|
282
|
+
</Await>
|
283
|
+
</div>
|
284
|
+
);
|
285
|
+
}
|
286
|
+
```
|
287
|
+
|
288
|
+
:::info
|
289
|
+
For specific usage of the Await component, see [Await](/docs/guides/basic-features/routes#await)
|
290
|
+
|
291
|
+
For specific usage of the defer function, see[defer](https://reactrouter.com/en/main/guides/deferred)
|
292
|
+
:::
|
293
|
+
|
294
|
+
### Side Effects
|
295
|
+
|
296
|
+
As mentioned above, Modern.js removes the server-side code `loader` from the client bundle, there are some things you need to be aware of, if you don't want to suffer from side effects, you can define `loader` in a [separate file](#loader-is-defined-in-a-separate-file).
|
297
|
+
|
298
|
+
:::info
|
299
|
+
In CSR scenarios, the side effects usually have less impact on the project, but you are still expected to follow the following conventions.
|
300
|
+
:::
|
301
|
+
|
302
|
+
Side effects of a module can be thought of as code that is executed when the module is loaded, such as:
|
303
|
+
|
304
|
+
```tsx
|
305
|
+
// routes/user/page.tsx
|
306
|
+
import { useLoaderData } from '@modern-js/runtime/router';
|
307
|
+
// highlight-next-line
|
308
|
+
import { transformProfile } from "./utils";
|
309
|
+
// highlight-next-line
|
310
|
+
console.log(transformProfile);
|
311
|
+
|
312
|
+
export const loader = async(): ProfileData => {
|
313
|
+
const res = await fetch('https://api/user/profile');
|
314
|
+
const data = await res.json();
|
315
|
+
return transformProfile(data);
|
316
|
+
}
|
317
|
+
|
318
|
+
export default function UserPage() {
|
319
|
+
const profileData = useLoaderData() as ProfileData;
|
320
|
+
return <div>{profileData}</div>;
|
321
|
+
}
|
322
|
+
```
|
323
|
+
|
324
|
+
Since `console.log` is executed when `routes/user/page.tsx` is loaded, the compiler does not remove it and `transformProfile` is bundled into the client bundle.
|
325
|
+
|
326
|
+
So we do not recommend having any code executed when the module is loaded, including project code and third-party modules used, and the following are some of the ways we do not recommend writing.
|
327
|
+
|
328
|
+
```tsx
|
329
|
+
// routes/user/page.tsx
|
330
|
+
export default function UserPage() {
|
331
|
+
return <div>profile</div>;
|
332
|
+
}
|
333
|
+
|
334
|
+
UserPage.config = {}
|
335
|
+
```
|
336
|
+
|
337
|
+
```tsx
|
338
|
+
// routes/init.ts
|
339
|
+
document.title = 'Modern.js';
|
340
|
+
|
341
|
+
// routes/layout.tsx
|
342
|
+
import "./init.ts";
|
343
|
+
|
344
|
+
export default function Layout() {
|
345
|
+
return <></>
|
346
|
+
}
|
347
|
+
```
|
348
|
+
|
349
|
+
In SSR scenarios, you usually need to use Server Side packages in the `loader` function, and for non-Node.js core packages, you need to do a re-export using a specially agreed file, such as using `fs-extra`:
|
350
|
+
|
351
|
+
```tsx
|
352
|
+
// routes/user/avatar.tsx
|
353
|
+
import { useLoaderData } from '@modern-js/runtime/router';
|
354
|
+
import { readFile } from './utils.server';
|
355
|
+
|
356
|
+
type ProfileData = { /* some type declarations */ }
|
357
|
+
|
358
|
+
export const loader = async(): ProfileData => {
|
359
|
+
const profile = await readFile('profile.json');
|
360
|
+
return profile;
|
361
|
+
}
|
362
|
+
|
363
|
+
export default function UserPage() {
|
364
|
+
const profileData = useLoaderData() as ProfileData;
|
365
|
+
return <div>{profileData}</div>;
|
366
|
+
}
|
367
|
+
|
368
|
+
// routes/user/utils.server.ts
|
369
|
+
export * from 'fs-extra';
|
370
|
+
```
|
371
|
+
|
372
|
+
### Wrong usage
|
373
|
+
|
374
|
+
1. Only serializable data can be returned in `loader`. In SSR environments, the return value of the `loader` function is serialized to a JSON string, which is then deserialized to an object on the client side. Therefore, no non-serializable data (such as functions) can be returned in the `loader` function.
|
375
|
+
|
376
|
+
:::warning
|
377
|
+
This restriction is not currently in place under CSR, but we strongly recommend that you follow it, and we may add it under CSR in the future.
|
378
|
+
:::
|
379
|
+
|
380
|
+
```ts
|
381
|
+
// This won't work!
|
382
|
+
export const loader = () => {
|
383
|
+
return {
|
384
|
+
user: {},
|
385
|
+
method: () => {
|
386
|
+
|
387
|
+
}
|
388
|
+
}
|
389
|
+
}
|
390
|
+
```
|
391
|
+
|
392
|
+
2. Modern.js will call the `loader` function for you, you shouldn't call it yourself in the component.
|
393
|
+
|
394
|
+
```tsx
|
395
|
+
// This won't work!
|
396
|
+
export const loader = async () => {
|
397
|
+
const res = fetch('https://api/user/profile');
|
398
|
+
return res.json();
|
399
|
+
};
|
400
|
+
|
401
|
+
export default function RouteComp() {
|
402
|
+
const data = loader();
|
403
|
+
}
|
404
|
+
```
|
405
|
+
|
406
|
+
3. When run on the server side, the `loader` functions are packaged into a single bundle, so we do not recommend using `__filename` and `__dirname` for server-side code.
|
407
|
+
|
408
|
+
|
10
409
|
## useLoader(Old)
|
11
410
|
|
12
411
|
**`useLoader`** is an API in Modern.js old version. The API is a React Hook specially provided for SSR applications, allowing developers to fetch data in components.
|
@@ -3,9 +3,9 @@ title: HTML Template
|
|
3
3
|
sidebar_position: 9
|
4
4
|
---
|
5
5
|
|
6
|
-
Modern.js provides **JSX
|
6
|
+
Modern.js provides **JSX syntax** and **HTML(Ejs) syntax** for customizing HTML template.
|
7
7
|
|
8
|
-
## JSX
|
8
|
+
## JSX syntax
|
9
9
|
|
10
10
|
Modern.js convention, in the `src/`, or in the entry directory, you can create `Document.[jt]sx` and export a component by default. The rendering result of this component can be used as an HTML template for the entry.
|
11
11
|
|
@@ -141,11 +141,11 @@ The above JSX component will generate the following HTML template:
|
|
141
141
|
</html>
|
142
142
|
```
|
143
143
|
|
144
|
-
##
|
144
|
+
## Html Synxtax
|
145
145
|
|
146
|
-
Modern.js also supports
|
146
|
+
Modern.js also supports HTML syntax. By default, an HTML template is built into the Modern.js application project to generate HTML code.
|
147
147
|
|
148
|
-
Based on
|
148
|
+
Based on HTML syntax templates, Modern.js provides **Custom HTML Fragments** and **Fully Custom HTML Templates** two ways to customize templates.
|
149
149
|
|
150
150
|
### Custom HTML Fragments
|
151
151
|
|
package/package.json
CHANGED
@@ -11,20 +11,20 @@
|
|
11
11
|
"modern",
|
12
12
|
"modern.js"
|
13
13
|
],
|
14
|
-
"version": "0.0.0-next-
|
14
|
+
"version": "0.0.0-next-20221227140603",
|
15
15
|
"publishConfig": {
|
16
16
|
"registry": "https://registry.npmjs.org/",
|
17
17
|
"access": "public"
|
18
18
|
},
|
19
19
|
"peerDependencies": {
|
20
|
-
"@modern-js/builder-doc": "0.0.0-next-
|
20
|
+
"@modern-js/builder-doc": "0.0.0-next-20221227140603"
|
21
21
|
},
|
22
22
|
"devDependencies": {
|
23
23
|
"ts-node": "^10",
|
24
24
|
"fs-extra": "^10",
|
25
25
|
"@types/node": "^16",
|
26
26
|
"@types/fs-extra": "^9",
|
27
|
-
"@modern-js/builder-doc": "0.0.0-next-
|
27
|
+
"@modern-js/builder-doc": "0.0.0-next-20221227140603"
|
28
28
|
},
|
29
29
|
"scripts": {
|
30
30
|
"build": "npx ts-node ./scripts/sync.ts"
|
@@ -0,0 +1,89 @@
|
|
1
|
+
---
|
2
|
+
title: routes/
|
3
|
+
sidebar_position: 2
|
4
|
+
---
|
5
|
+
|
6
|
+
应用使用基于文件系统路由时的入口标识。
|
7
|
+
|
8
|
+
当项目结构为 `Routes 入口` 类型时, 会分析 `src/routes` 目录下的文件得到客户端路由配置。具体用法请查看[约定式路由](/docs/guides/basic-features/routes)
|
9
|
+
|
10
|
+
任何在 `src/routes` 下的 `layout.[tj]sx` 和 `page.[tj]sx` 都会作为应用的路由:
|
11
|
+
```bash {3}
|
12
|
+
.
|
13
|
+
└── routes
|
14
|
+
├── layout.tsx
|
15
|
+
├── page.tsx
|
16
|
+
└── user
|
17
|
+
├── layout.tsx
|
18
|
+
└── page.tsx
|
19
|
+
```
|
20
|
+
|
21
|
+
## 基本示例
|
22
|
+
|
23
|
+
`routes` 目录下的目录名会作为路由 url 的映射,其中 `layout.tsx` 中作为布局组件,`page.tsx` 作为内容组件,是整条路由的叶子节点,例如以下目录结构:
|
24
|
+
|
25
|
+
```bash
|
26
|
+
.
|
27
|
+
└── routes
|
28
|
+
├── page.tsx
|
29
|
+
└── user
|
30
|
+
└── page.tsx
|
31
|
+
```
|
32
|
+
|
33
|
+
会产出下面两条路由:
|
34
|
+
- `/`
|
35
|
+
- `/user`
|
36
|
+
|
37
|
+
## 动态路由
|
38
|
+
|
39
|
+
如果路由文件的目录名以 `[]` 命名,生成的路由会作为动态路由。例如以下文件目录:
|
40
|
+
```
|
41
|
+
└── routes
|
42
|
+
├── [id]
|
43
|
+
│ └── page.tsx
|
44
|
+
├── blog
|
45
|
+
│ └── page.tsx
|
46
|
+
└── page.tsx
|
47
|
+
```
|
48
|
+
|
49
|
+
`routes/[id]/page.tsx` 文件会转为 `/:id` 路由。除了可以确切匹配的 `/blog` 路由,其他所有 `/xxx` 都会匹配到该路由。
|
50
|
+
|
51
|
+
在组件中,可以通过 [useParams](/docs/apis/app/runtime/router/#useparams) 获取对应命名的参数。
|
52
|
+
|
53
|
+
在 loader 中,params 会作为 [loader](/docs/guides/basic-features/data-fetch#loader-函数) 的入参,通过 `params` 的属性可以获取到对应的参数。
|
54
|
+
|
55
|
+
|
56
|
+
## 布局组件
|
57
|
+
|
58
|
+
如下面的例子,可以通过添加 `layout.tsx`,为所有路由组件添加公共的布局组件:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
.
|
62
|
+
└── routes
|
63
|
+
├── layout.tsx
|
64
|
+
├── page.tsx
|
65
|
+
└── user
|
66
|
+
├── layout.tsx
|
67
|
+
└── page.tsx
|
68
|
+
```
|
69
|
+
|
70
|
+
在布局组件中可以通过使用 `<Outlet>` 表示子组件:
|
71
|
+
```tsx title=routes/layout.tsx
|
72
|
+
import { Link, Outlet, useLoaderData } from '@modern-js/runtime/router';
|
73
|
+
|
74
|
+
export default () => {
|
75
|
+
return (
|
76
|
+
<>
|
77
|
+
<Outlet></Outlet>
|
78
|
+
</>
|
79
|
+
)
|
80
|
+
}
|
81
|
+
```
|
82
|
+
|
83
|
+
:::note
|
84
|
+
`<Outlet>` 是 React Router 6 中新的 API,详情可以查看 [Outlet](https://reactrouter.com/en/main/components/outlet#outlet).
|
85
|
+
:::
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
---
|
2
|
+
sidebar_label: withMasterApp
|
3
|
+
---
|
4
|
+
|
5
|
+
# dev.withMasterApp
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
* 类型: `Object`
|
10
|
+
* 默认值: `null`
|
11
|
+
|
12
|
+
当项目为微前端子应用的时候,可以使用 `withMasterApp` 配置启用子应用调试模式。
|
13
|
+
|
14
|
+
:::caution 注意
|
15
|
+
使用子应用调试的模式时,应该先确保主应用开启了线上 debug 模式。
|
16
|
+
:::
|
17
|
+
|
18
|
+
```js title=modern.config.js
|
19
|
+
export default defineConfig({
|
20
|
+
dev: {
|
21
|
+
withMasterApp: {
|
22
|
+
// 主应用的路径
|
23
|
+
moduleApp: 'https://www.masterApp.com',
|
24
|
+
// 子应用的名称
|
25
|
+
moduleName: 'Contact'
|
26
|
+
}
|
27
|
+
}
|
28
|
+
})
|
29
|
+
```
|
30
|
+
|
31
|
+
- moduleApp: `string` 主应用的线上地址。
|
32
|
+
- moduleName: `Contact` 子应用的名称(需要和在主应用中注册的模块名匹配)。
|
@@ -13,10 +13,24 @@ sidebar_label: masterApp
|
|
13
13
|
## 示例
|
14
14
|
|
15
15
|
import EnableMicroFrontend from '@site-docs/components/enable-micro-frontend.md';
|
16
|
-
import MasterManifestAppConfig from '@site-docs/components/micro-master-manifest-config.md';
|
17
16
|
|
18
17
|
<EnableMicroFrontend />
|
19
|
-
|
18
|
+
|
19
|
+
## `manifest`
|
20
|
+
|
21
|
+
```ts
|
22
|
+
interface Manifest {
|
23
|
+
getAppList?: ()=> Array<AppInfo>
|
24
|
+
}
|
25
|
+
```
|
26
|
+
|
27
|
+
#### `getAppList?`
|
28
|
+
|
29
|
+
通过 `getAppList` 配置,可以自定义如何获取远程列表数据
|
30
|
+
|
31
|
+
```ts
|
32
|
+
type GetAppList = ()=> Promise<Array<AppInfo>>;
|
33
|
+
```
|
20
34
|
|
21
35
|
|
22
36
|
### apps
|
@@ -4,39 +4,32 @@ title: tools.tailwindcss
|
|
4
4
|
sidebar_label: tailwindcss
|
5
5
|
---
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
* 默认值:见下方配置详情。
|
7
|
+
- 类型: `Object | Function`
|
8
|
+
- 默认值:见下方配置详情。
|
10
9
|
|
11
10
|
<details>
|
12
11
|
<summary>TailwindCSS 配置详情</summary>
|
13
12
|
|
14
13
|
```js
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
removeDeprecatedGapUtilities: false,
|
29
|
-
purgeLayersByDefault: true,
|
30
|
-
defaultLineHeights: false,
|
31
|
-
standardFontWeights: false,
|
32
|
-
},
|
33
|
-
theme: source.designSystem // 使用source.designSystem配置作为Tailwind CSS Theme配置
|
34
|
-
}
|
14
|
+
const tailwind = {
|
15
|
+
content: [
|
16
|
+
'./config/html/**/*.html',
|
17
|
+
'./config/html/**/*.ejs',
|
18
|
+
'./config/html/**/*.hbs',
|
19
|
+
'./src/**/*.js',
|
20
|
+
'./src/**/*.jsx',
|
21
|
+
'./src/**/*.ts',
|
22
|
+
'./src/**/*.tsx',
|
23
|
+
'./storybook/**/*',
|
24
|
+
],
|
25
|
+
theme: source.designSystem, // 使用source.designSystem配置作为Tailwind CSS Theme配置
|
26
|
+
};
|
35
27
|
```
|
36
28
|
|
37
29
|
:::tip 提示
|
38
30
|
更多关于:<a href="https://tailwindcss.com/docs/configuration" target="_blank">TailwindCSS 配置</a>。
|
39
31
|
:::
|
32
|
+
|
40
33
|
</details>
|
41
34
|
|
42
35
|
对应 [TailwindCSS](https://tailwindcss.com/docs/configuration) 的配置,值为 `Object` 类型时,与默认配置通过 `Object.assign` 合并。
|