@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
@@ -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 */
|