@modern-js/main-doc 2.35.1 → 2.36.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/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
@@ -54,7 +54,7 @@ The `routes/[id]/page.tsx` file will be converted to the `/:id` route. Except fo
|
|
54
54
|
|
55
55
|
In the component, you can use [useParams](/apis/app/runtime/router/router#useparams) to obtain the corresponding named parameter.
|
56
56
|
|
57
|
-
When using the [loader](/guides/basic-features/data-fetch#the-loader-function) function to obtain data, `params` will be passed as an input parameter to the `loader` function, and the corresponding parameter can be obtained through the attribute of `params`.
|
57
|
+
When using the [loader](/guides/basic-features/data/data-fetch#the-loader-function) function to obtain data, `params` will be passed as an input parameter to the `loader` function, and the corresponding parameter can be obtained through the attribute of `params`.
|
58
58
|
|
59
59
|
## Layout Component
|
60
60
|
|
@@ -39,8 +39,8 @@ import { defineConfig } from '@modern-js/app-tools';
|
|
39
39
|
export default defineConfig({
|
40
40
|
source: {
|
41
41
|
entries: {
|
42
|
-
// Specify a new entry named
|
43
|
-
|
42
|
+
// Specify a new entry named 'my-entry'
|
43
|
+
'my-entry': './src/home/test/index.ts',
|
44
44
|
},
|
45
45
|
disableDefaultEntries: true,
|
46
46
|
},
|
@@ -90,9 +90,10 @@ import { defineConfig } from '@modern-js/app-tools';
|
|
90
90
|
export default defineConfig({
|
91
91
|
source: {
|
92
92
|
entries: {
|
93
|
-
|
93
|
+
'my-entry': {
|
94
94
|
// entry file path
|
95
|
-
entry: './src/
|
95
|
+
entry: './src/my-page/index.tsx',
|
96
|
+
disableMount: true,
|
96
97
|
},
|
97
98
|
},
|
98
99
|
// Disable default entry scanning
|
@@ -111,8 +112,8 @@ If you want to disable the logic of Modern.js automatically generating entry fil
|
|
111
112
|
export default defineConfig({
|
112
113
|
source: {
|
113
114
|
entries: {
|
114
|
-
|
115
|
-
entry: './src/
|
115
|
+
'my-entry': {
|
116
|
+
entry: './src/my-page/index.tsx',
|
116
117
|
disableMount: true,
|
117
118
|
},
|
118
119
|
},
|
@@ -0,0 +1,119 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 4
|
3
|
+
title: Custom request SDK
|
4
|
+
---
|
5
|
+
# Custom request SDK
|
6
|
+
|
7
|
+
Modernjs's BFF is isomorphic in CSR and SSR.In the browser side rely on the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch),On the server relies on the [node-fetch](https://www.npmjs.com/package/node-fetch).However, in many business scenarios we need to do some additional processing of the request or response, for example:
|
8
|
+
|
9
|
+
- Write auth information in the request header
|
10
|
+
- Uniform processing of response data or errors
|
11
|
+
- The browser's native fetch function is not available for a particular platform, and other methods of sending requests are required
|
12
|
+
|
13
|
+
For the above scenario, Modern.js provides the `configure` function,the customization capabilities range from low to high and can be used to configure ssr pass-through request headers, interceptors, and request SDKs..
|
14
|
+
|
15
|
+
:::caution
|
16
|
+
The `configure` function call needs to be called before all BFF requests are sent, to ensure that the default request configuration is overridden.
|
17
|
+
|
18
|
+
:::
|
19
|
+
|
20
|
+
|
21
|
+
```ts title="App.tsx"
|
22
|
+
import { configure } from '@modern-js/runtime/bff';
|
23
|
+
|
24
|
+
configure({
|
25
|
+
request: customRequest
|
26
|
+
})
|
27
|
+
```
|
28
|
+
|
29
|
+
## Configure ssr pass-through request headers
|
30
|
+
|
31
|
+
In scenarios where both Modern.js SSR and BFF are used, it is often necessary to pass some request headers on SSR page requests to the BFF service.
|
32
|
+
|
33
|
+
For example, the project has a page address `https://website.com`, which is an SSR page, and the API interface `https://website.com/api/info` will be called in the component, which requires the user's cookie information for authentication. When the page requests this API interface, it needs to pass the `cookie` requested by the SSR page to BFF.
|
34
|
+
|
35
|
+
Currently the following request headers are automatically passed through in Modern.js:
|
36
|
+
|
37
|
+
- cookie
|
38
|
+
- x-tt-logid
|
39
|
+
- user-agent
|
40
|
+
- x-tt-stress
|
41
|
+
|
42
|
+
The request header can be configured via `configure`. For example, in the following example, Modern.js will automatically pass the cookie information of the SSR page request to the BFF service:
|
43
|
+
|
44
|
+
```tsx title="App.tsx"
|
45
|
+
import { configure } from '@modern-js/runtime/bff';
|
46
|
+
|
47
|
+
configure({
|
48
|
+
allowedHeaders: ['x-uid']
|
49
|
+
})
|
50
|
+
```
|
51
|
+
|
52
|
+
## Configuring Interceptors
|
53
|
+
|
54
|
+
In certain business scenarios, there is a requirement for unified processing of requests and responses, and interceptors can be configured to fulfill these requirements in such scenarios.
|
55
|
+
|
56
|
+
```tsx title="App.tsx"
|
57
|
+
configure({
|
58
|
+
// The request here is the default request sdk for bff, and the interceptor function needs to return a new request.
|
59
|
+
// The return value of the new request must be the result of the parse body
|
60
|
+
interceptor(request){
|
61
|
+
return async(url, params) => {
|
62
|
+
const res = await request(url, params);
|
63
|
+
return res.json();
|
64
|
+
};
|
65
|
+
};
|
66
|
+
});
|
67
|
+
```
|
68
|
+
|
69
|
+
## Configure custom request SDK
|
70
|
+
|
71
|
+
If the requirements cannot be met by configuring interceptors alone and need to further customize the request SDK, you can configure the custom request SDK by using the `configure` function:
|
72
|
+
|
73
|
+
:::caution
|
74
|
+
Send a request to the BFF service when the server side renders, Modern.js will find the BFF service intranet IP via **service discovery** and send requests via IP to improve performance. This optimization is **lost** if a custom request SDK is used.
|
75
|
+
|
76
|
+
:::
|
77
|
+
|
78
|
+
```tsx title="App.tsx"
|
79
|
+
import nodeFetch from 'node-fetch';
|
80
|
+
|
81
|
+
const customFetch = (input: RequestInfo | URL, init: RequestInit) => {
|
82
|
+
const curFetch = process.env.MODERN_TARGET !== 'node' ? fetch : nodeFetch as unknown as typeof fetch;
|
83
|
+
return curFetch(input, init).then(async res => {
|
84
|
+
const data = await res.json();
|
85
|
+
data.hello = 'hello custom sdk';
|
86
|
+
return data;
|
87
|
+
});
|
88
|
+
};
|
89
|
+
|
90
|
+
configure({
|
91
|
+
request: customFetch,
|
92
|
+
});
|
93
|
+
```
|
94
|
+
|
95
|
+
The configuration custom request SDK has the following conventions:
|
96
|
+
|
97
|
+
- The `configure` function allows you to configure a `request` function whose input is the same as the Fetch or node-fetch in the browser, and all BFF functions will send requests through this function
|
98
|
+
- The return value of the `request` function must be the actual data returned by the interface, not a Promise, otherwise the BFF function will not return data properly.
|
99
|
+
- In the case of SSR projects, `request` must support both browser-side and server-side sending of requests.
|
100
|
+
|
101
|
+
Example of custom request SDK using axios:
|
102
|
+
|
103
|
+
```tsx title="App.tsx"
|
104
|
+
import { configure } from '@modern-js/runtime/bff';
|
105
|
+
import type { Method, AxiosRequestHeaders as Headers } from 'axios';
|
106
|
+
|
107
|
+
configure({
|
108
|
+
async request(...config: Parameters<typeof fetch>) {
|
109
|
+
const [url, params] = config;
|
110
|
+
const res = await axios({
|
111
|
+
url: url as string, // Here, because of some incompatibility between fetch and axios types, you need to use `as`
|
112
|
+
method: params?.method as Method,
|
113
|
+
data: params?.body,
|
114
|
+
headers: params?.headers as Headers,
|
115
|
+
});
|
116
|
+
return res.data;
|
117
|
+
},
|
118
|
+
});
|
119
|
+
```
|
@@ -26,7 +26,7 @@ After the project is created, you can experience the project by running `pnpm ru
|
|
26
26
|
When using Rspack as the bundler, the following Features are temporarily unavailable as some of the capabilities are still under development and we will provide support in the future.
|
27
27
|
|
28
28
|
- Storybook Devtool
|
29
|
-
- The usage of [useLoader](/guides/basic-features/data-fetch.html) in Client Side Rendering
|
29
|
+
- The usage of [useLoader](/guides/basic-features/data/data-fetch.html) in Client Side Rendering
|
30
30
|
|
31
31
|
:::
|
32
32
|
|
@@ -22,8 +22,8 @@ export default defineConfig({
|
|
22
22
|
|
23
23
|
Modern.js provides a Data Loader that simplifies data fetching for developers working with SSR and CSR. Each routing module, such as `layout.tsx` and `page.tsx`, can define its own Data Loader:
|
24
24
|
|
25
|
-
```ts title="src/routes/page.
|
26
|
-
export
|
25
|
+
```ts title="src/routes/page.data.ts"
|
26
|
+
export const loader = () => {
|
27
27
|
return {
|
28
28
|
message: 'Hello World',
|
29
29
|
};
|
@@ -49,7 +49,7 @@ Developers should still be mindful of data fallback, including `null` values or
|
|
49
49
|
|
50
50
|
1. When requesting a page through client-side routing, Modern.js sends an HTTP request. The server receives the request and executes the corresponding Data Loader function for the page, then returns the execution result as a response to the browser.
|
51
51
|
|
52
|
-
2. When using Data Loader, data is fetched before rendering. Modern.js also supports obtaining data during component rendering. For more related content, please refer to [Data Fetch](/guides/basic-features/data-fetch).
|
52
|
+
2. When using Data Loader, data is fetched before rendering. Modern.js also supports obtaining data during component rendering. For more related content, please refer to [Data Fetch](/guides/basic-features/data/data-fetch).
|
53
53
|
|
54
54
|
:::
|
55
55
|
|
@@ -158,10 +158,10 @@ Using SPR in Modern.js is very simple. Just add the PreRender component to your
|
|
158
158
|
|
159
159
|
Here is a simulated component that uses the useLoaderData API. The request in the Data Loader takes 2 seconds to consume.
|
160
160
|
|
161
|
-
```tsx title="page.
|
161
|
+
```tsx title="page.data.ts"
|
162
162
|
import { useLoaderData } from '@modern-js/runtime/router';
|
163
163
|
|
164
|
-
export
|
164
|
+
export const loader = async () => {
|
165
165
|
await new Promise((resolve, reject) => {
|
166
166
|
setTimeout(() => {
|
167
167
|
resolve(null);
|
@@ -307,9 +307,9 @@ export const loader = () => {
|
|
307
307
|
|
308
308
|
The two methods mentioned above will both bring some mental burden to developers. In real business scenarios, we found that most of the mixed Node/Web code appears in data requests.
|
309
309
|
|
310
|
-
Therefore, Modern.js has designed a [Data Fetch](/guides/basic-features/data-fetch) to separate CSR and SSR code based on [Nested Routing](/guides/basic-features/routes).
|
310
|
+
Therefore, Modern.js has designed a [Data Fetch](/guides/basic-features/data/data-fetch) to separate CSR and SSR code based on [Nested Routing](/guides/basic-features/routes).
|
311
311
|
|
312
|
-
We can separate **data requests from component code** by using independent files. Write the component logic in `routes/page.tsx` and write the data request logic in `routes/page.
|
312
|
+
We can separate **data requests from component code** by using independent files. Write the component logic in `routes/page.tsx` and write the data request logic in `routes/page.data.ts`.
|
313
313
|
|
314
314
|
```ts title="routes/page.tsx"
|
315
315
|
export default Page = () => {
|
@@ -317,9 +317,9 @@ export default Page = () => {
|
|
317
317
|
}
|
318
318
|
```
|
319
319
|
|
320
|
-
```ts title="routes/page.
|
320
|
+
```ts title="routes/page.data.tsx"
|
321
321
|
import fse from 'fs-extra';
|
322
|
-
export
|
322
|
+
export const loader = () => {
|
323
323
|
const file = fse.readFileSync('./myfile');
|
324
324
|
return {
|
325
325
|
...
|
@@ -329,7 +329,7 @@ export default () => {
|
|
329
329
|
|
330
330
|
## Remote Request
|
331
331
|
|
332
|
-
When initiating interface requests in SSR, developers sometimes encapsulate isomorphic request tools themselves. For some interfaces that require passing user cookies, developers can use the ['useRuntimeContext'](/guides/basic-features/data-fetch#route-loader) API to get the request header for implementation.
|
332
|
+
When initiating interface requests in SSR, developers sometimes encapsulate isomorphic request tools themselves. For some interfaces that require passing user cookies, developers can use the ['useRuntimeContext'](/guides/basic-features/data/data-fetch#route-loader) API to get the request header for implementation.
|
333
333
|
|
334
334
|
It should be noted that the obtained request header is for HTML requests, which may not be suitable for API requests. Therefore, ** don't passed through all request headers **.
|
335
335
|
|
@@ -361,7 +361,7 @@ The streaming SSR of Modern.js is implemented based on React Router, and the mai
|
|
361
361
|
|
362
362
|
### Return async data
|
363
363
|
|
364
|
-
```ts title="page.
|
364
|
+
```ts title="page.data.ts"
|
365
365
|
import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
|
366
366
|
|
367
367
|
interface User {
|
@@ -373,7 +373,7 @@ export interface Data {
|
|
373
373
|
data: User;
|
374
374
|
}
|
375
375
|
|
376
|
-
export
|
376
|
+
export const loader = ({ params }: LoaderFunctionArgs) => {
|
377
377
|
const userId = params.id;
|
378
378
|
|
379
379
|
const user = new Promise<User>(resolve => {
|
@@ -393,7 +393,7 @@ export default ({ params }: LoaderFunctionArgs) => {
|
|
393
393
|
|
394
394
|
`defer` can receive both asynchronous and synchronous data at the same time. For example:
|
395
395
|
|
396
|
-
```ts title="page.
|
396
|
+
```ts title="page.data.ts"
|
397
397
|
// skip some codes
|
398
398
|
|
399
399
|
export default ({ params }: LoaderFunctionArgs) => {
|
@@ -430,7 +430,7 @@ With the `<Await>` component, you can retrieve the data asynchronously returned
|
|
430
430
|
```tsx title="page.tsx"
|
431
431
|
import { Await, useLoaderData } from '@modern-js/runtime/router';
|
432
432
|
import { Suspense } from 'react';
|
433
|
-
import type { Data } from './page.
|
433
|
+
import type { Data } from './page.data';
|
434
434
|
|
435
435
|
const Page = () => {
|
436
436
|
const data = useLoaderData() as Data;
|
@@ -461,7 +461,7 @@ export default Page;
|
|
461
461
|
:::warning Warning
|
462
462
|
When importing types from a Data Loader file, it is necessary to use the `import type` syntax to ensure that only type information is imported. This can avoid packaging Data Loader code into the bundle file of the front-end product.
|
463
463
|
|
464
|
-
Therefore, the import method here is: `import type { Data } from './page.
|
464
|
+
Therefore, the import method here is: `import type { Data } from './page.data'`;
|
465
465
|
:::
|
466
466
|
|
467
467
|
You can also retrieve asynchronous data returned by the Data Loader using `useAsyncValue`. For example:
|
@@ -504,10 +504,10 @@ export default Page;
|
|
504
504
|
The `errorElement` property of the `<Await>` component can be used to handle errors thrown when the Data Loader executes or when a child component renders.
|
505
505
|
For example, we intentionally throw an error in the Data Loader function:
|
506
506
|
|
507
|
-
```ts title="page.
|
507
|
+
```ts title="page.data.ts"
|
508
508
|
import { defer } from '@modern-js/runtime/router';
|
509
509
|
|
510
|
-
export
|
510
|
+
export const loader = () => {
|
511
511
|
const data = new Promise((resolve, reject) => {
|
512
512
|
setTimeout(() => {
|
513
513
|
reject(new Error('error occurs'));
|
@@ -14,13 +14,19 @@ It should be noted that these APIs do not help applications initiate requests, b
|
|
14
14
|
Modern.js recommends using [conventional routing](/guides/basic-features/routes) for routing management. Through Modern.js's [conventional (nested) routing](/guides/basic-features/routes#conventional-routing), each routing component (`layout.ts` or `page.ts`) can have a same-named `loader` file. The `loader` file needs to export a function that will be executed before the component is rendered to provide data for the routing component.
|
15
15
|
|
16
16
|
:::info
|
17
|
-
Modern.js v1 supports fetching data via [useLoader](</guides/basic-features/data-fetch.html#useloader-(old-version)>), which is no longer the recommended usage. We do not recommend mixing the two except during the migration process.
|
17
|
+
Modern.js v1 supports fetching data via [useLoader](</guides/basic-features/data/data-fetch.html#useloader-(old-version)>), which is no longer the recommended usage. We do not recommend mixing the two except during the migration process.
|
18
|
+
|
19
|
+
:::
|
20
|
+
|
21
|
+
:::warning
|
22
|
+
- In the previous version, Modern.js Data Loader was defined in the `loader` file. In later versions, we recommend defining it in the `data` file, while we will maintain compatibility with the `loader` file.
|
23
|
+
- In the `data` file, the corresponding `loader` needs to be exported with a name。
|
18
24
|
|
19
25
|
:::
|
20
26
|
|
21
27
|
### Basic Example
|
22
28
|
|
23
|
-
Routing components such as `layout.ts` or `page.ts` can define a same-named `loader` file. The function exported by the `
|
29
|
+
Routing components such as `layout.ts` or `page.ts` can define a same-named `loader` file. The function exported by the `data` file provides the data required by the component, and then the data is obtained in the routing component through the `useLoaderData` function, as shown in the following example:
|
24
30
|
|
25
31
|
```bash
|
26
32
|
.
|
@@ -28,16 +34,16 @@ Routing components such as `layout.ts` or `page.ts` can define a same-named `loa
|
|
28
34
|
├── layout.tsx
|
29
35
|
└── user
|
30
36
|
├── layout.tsx
|
31
|
-
├── layout.
|
37
|
+
├── layout.data.ts
|
32
38
|
├── page.tsx
|
33
|
-
└── page.
|
39
|
+
└── page.data.ts
|
34
40
|
```
|
35
41
|
|
36
42
|
Define the following code in the file:
|
37
43
|
|
38
44
|
```ts title="routes/user/page.tsx"
|
39
45
|
import { useLoaderData } from '@modern-js/runtime/router';
|
40
|
-
import type { ProfileData } from './page.
|
46
|
+
import type { ProfileData } from './page.data.ts';
|
41
47
|
|
42
48
|
export default function UserPage() {
|
43
49
|
const profileData = useLoaderData() as ProfileData;
|
@@ -45,19 +51,19 @@ export default function UserPage() {
|
|
45
51
|
}
|
46
52
|
```
|
47
53
|
|
48
|
-
```ts title="routes/user/page.
|
54
|
+
```ts title="routes/user/page.data.ts"
|
49
55
|
export type ProfileData = {
|
50
56
|
/* some types */
|
51
57
|
};
|
52
58
|
|
53
|
-
export
|
59
|
+
export const loader = async (): Promise<ProfileData> => {
|
54
60
|
const res = await fetch('https://api/user/profile');
|
55
61
|
return await res.json();
|
56
62
|
};
|
57
63
|
```
|
58
64
|
|
59
65
|
:::caution
|
60
|
-
Here, routing components and `
|
66
|
+
Here, routing components and `data` files share a type, so the `import type` syntax should be used.
|
61
67
|
|
62
68
|
:::
|
63
69
|
|
@@ -81,7 +87,7 @@ The `loader` function has two input parameters:
|
|
81
87
|
When the route file is accessed through `[]`, it is used as [dynamic routing](/guides/basic-features/routes#dynamic-routing), and the dynamic routing fragment is passed as a parameter to the `loader` function:
|
82
88
|
|
83
89
|
```tsx
|
84
|
-
// routes/user/[id]/page.
|
90
|
+
// routes/user/[id]/page.data.tsx
|
85
91
|
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
86
92
|
|
87
93
|
export default async ({ params }: LoaderFunctionArgs) => {
|
@@ -100,10 +106,10 @@ When accessing `/user/123`, the parameter of the `loader` function is `{ params:
|
|
100
106
|
A common usage scenario is to get query parameters through `request`:
|
101
107
|
|
102
108
|
```tsx
|
103
|
-
// routes/user/[id]/page.
|
109
|
+
// routes/user/[id]/page.data.ts
|
104
110
|
import { LoaderFunctionArgs } from '@modern-js/runtime/router';
|
105
111
|
|
106
|
-
export
|
112
|
+
export const loader = async ({ request }: LoaderFunctionArgs) => {
|
107
113
|
const url = new URL(request.url);
|
108
114
|
const userId = url.searchParams.get('id');
|
109
115
|
return queryUser(userId);
|
@@ -152,8 +158,8 @@ function loader() {
|
|
152
158
|
In the `loader` function, errors can be handled by throwing an `error` or a `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`](/guides/basic-features/routes#error-handling) component:
|
153
159
|
|
154
160
|
```tsx
|
155
|
-
// routes/user/profile/page.
|
156
|
-
export
|
161
|
+
// routes/user/profile/page.data.tsx
|
162
|
+
export const loader = async function loader() {
|
157
163
|
const res = await fetch('https://api/user/profile');
|
158
164
|
if (!res.ok) {
|
159
165
|
throw res;
|
@@ -185,7 +191,7 @@ In many cases, child components need to access data in the parent component `loa
|
|
185
191
|
import { useRouteLoaderData } from '@modern-js/runtime/router';
|
186
192
|
|
187
193
|
export default function UserLayout() {
|
188
|
-
// Get the data returned by the loader in routes/user/layout.
|
194
|
+
// Get the data returned by the loader in routes/user/layout.data.ts
|
189
195
|
const data = useRouteLoaderData('user/layout');
|
190
196
|
return (
|
191
197
|
<div>
|
@@ -219,12 +225,12 @@ If you want to get the data returned by the `loader` in `entry1/routes/layout.ts
|
|
219
225
|
This feature is currently experimental and the API may change in the future.
|
220
226
|
:::
|
221
227
|
|
222
|
-
Create `user/layout.
|
228
|
+
Create `user/layout.data.ts` and add the following code:
|
223
229
|
|
224
|
-
```ts title="routes/user/layout.
|
230
|
+
```ts title="routes/user/layout.data.ts"
|
225
231
|
import { defer } from '@modern-js/runtime/router';
|
226
232
|
|
227
|
-
const loader = () =>
|
233
|
+
export const loader = () =>
|
228
234
|
defer({
|
229
235
|
userInfo: new Promise(resolve => {
|
230
236
|
setTimeout(() => {
|
@@ -236,7 +242,6 @@ const loader = () =>
|
|
236
242
|
}),
|
237
243
|
});
|
238
244
|
|
239
|
-
export default loader;
|
240
245
|
```
|
241
246
|
|
242
247
|
Add the following code in `user/layout.tsx`:
|
@@ -286,24 +291,27 @@ Currently, there is no such restriction under CSR, but we strongly recommend tha
|
|
286
291
|
|
287
292
|
```ts
|
288
293
|
// This won't work!
|
289
|
-
export
|
290
|
-
|
291
|
-
|
292
|
-
method: () => {},
|
293
|
-
};
|
294
|
+
export const loader = async () => {
|
295
|
+
const res = fetch('https://api/user/profile');
|
296
|
+
return res.json();
|
294
297
|
};
|
298
|
+
|
299
|
+
import { loader } from './page.data.ts';
|
300
|
+
export default function RouteComp() {
|
301
|
+
const data = loader();
|
302
|
+
}
|
295
303
|
```
|
296
304
|
|
297
305
|
2. Modern.js will call the `loader` function for you, so you should not call the `loader` function yourself:
|
298
306
|
|
299
307
|
```tsx
|
300
308
|
// This won't work!
|
301
|
-
export
|
309
|
+
export const loader = async () => {
|
302
310
|
const res = fetch('https://api/user/profile');
|
303
311
|
return res.json();
|
304
312
|
};
|
305
313
|
|
306
|
-
import loader from './page.
|
314
|
+
import { loader } from './page.data.ts';
|
307
315
|
export default function RouteComp() {
|
308
316
|
const data = loader();
|
309
317
|
}
|
@@ -315,7 +323,7 @@ export default function RouteComp() {
|
|
315
323
|
// Not allowed
|
316
324
|
// routes/layout.tsx
|
317
325
|
import { useLoaderData } from '@modern-js/runtime/router';
|
318
|
-
import { ProfileData } from './page.
|
326
|
+
import { ProfileData } from './page.data.ts'; // should use "import type" instead
|
319
327
|
|
320
328
|
export const fetch = wrapFetch(fetch);
|
321
329
|
|
@@ -324,7 +332,7 @@ export default function UserPage() {
|
|
324
332
|
return <div>{profileData}</div>;
|
325
333
|
}
|
326
334
|
|
327
|
-
// routes/layout.
|
335
|
+
// routes/layout.data.ts
|
328
336
|
import { fetch } from './layout.tsx'; // should not be imported from the routing component
|
329
337
|
export type ProfileData = {
|
330
338
|
/* some types */
|