@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.
Files changed (58) hide show
  1. package/docs/en/apis/app/hooks/src/routes.mdx +1 -1
  2. package/docs/en/components/debug-app.mdx +1 -1
  3. package/docs/en/components/turtorials-example-list.mdx +2 -0
  4. package/docs/en/configure/app/source/entries.mdx +7 -6
  5. package/docs/en/guides/advanced-features/bff/sdk.mdx +119 -0
  6. package/docs/en/guides/advanced-features/rspack-start.mdx +1 -1
  7. package/docs/en/guides/advanced-features/ssr.mdx +17 -17
  8. package/docs/en/guides/basic-features/data/_category_.json +4 -0
  9. package/docs/en/guides/basic-features/{data-fetch.mdx → data/data-fetch.mdx} +35 -27
  10. package/docs/en/guides/basic-features/data/data-write.mdx +241 -0
  11. package/docs/en/guides/basic-features/routes.mdx +7 -7
  12. package/docs/en/guides/concept/entries.mdx +31 -30
  13. package/docs/en/guides/get-started/quick-start.mdx +1 -1
  14. package/docs/en/guides/topic-detail/framework-plugin/extend.mdx +0 -1
  15. package/docs/en/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
  16. package/docs/en/guides/topic-detail/framework-plugin/hook.mdx +1 -1
  17. package/docs/en/guides/topic-detail/framework-plugin/implement.mdx +1 -2
  18. package/docs/en/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
  19. package/docs/en/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
  20. package/docs/en/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
  21. package/docs/en/guides/topic-detail/framework-plugin/relationship.mdx +2 -2
  22. package/docs/en/guides/topic-detail/generator/new/config.md +0 -5
  23. package/docs/en/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
  24. package/docs/en/tutorials/first-app/c05-loader.mdx +2 -2
  25. package/docs/en/tutorials/first-app/c06-model.mdx +4 -4
  26. package/docs/en/tutorials/first-app/c07-container.mdx +3 -3
  27. package/docs/en/tutorials/foundations/introduction.mdx +3 -2
  28. package/docs/zh/apis/app/hooks/src/routes.mdx +1 -1
  29. package/docs/zh/components/debug-app.mdx +1 -1
  30. package/docs/zh/components/micro-runtime-config.mdx +2 -2
  31. package/docs/zh/components/turtorials-example-list.mdx +2 -0
  32. package/docs/zh/configure/app/source/entries.mdx +7 -6
  33. package/docs/zh/guides/advanced-features/bff/sdk.mdx +119 -0
  34. package/docs/zh/guides/advanced-features/rspack-start.mdx +1 -1
  35. package/docs/zh/guides/advanced-features/ssr.mdx +16 -16
  36. package/docs/zh/guides/basic-features/data/_category_.json +4 -0
  37. package/docs/zh/guides/basic-features/{data-fetch.mdx → data/data-fetch.md} +31 -27
  38. package/docs/zh/guides/basic-features/data/data-write.mdx +236 -0
  39. package/docs/zh/guides/basic-features/routes.mdx +7 -7
  40. package/docs/zh/guides/concept/entries.mdx +34 -32
  41. package/docs/zh/guides/get-started/quick-start.mdx +1 -1
  42. package/docs/zh/guides/topic-detail/framework-plugin/extend.mdx +0 -1
  43. package/docs/zh/guides/topic-detail/framework-plugin/hook-list.mdx +0 -1
  44. package/docs/zh/guides/topic-detail/framework-plugin/hook.mdx +1 -1
  45. package/docs/zh/guides/topic-detail/framework-plugin/implement.mdx +0 -1
  46. package/docs/zh/guides/topic-detail/framework-plugin/introduction.mdx +1 -1
  47. package/docs/zh/guides/topic-detail/framework-plugin/lifecycle.mdx +1 -1
  48. package/docs/zh/guides/topic-detail/framework-plugin/plugin-api.mdx +31 -11
  49. package/docs/zh/guides/topic-detail/framework-plugin/relationship.mdx +1 -1
  50. package/docs/zh/guides/topic-detail/generator/new/config.md +0 -5
  51. package/docs/zh/guides/topic-detail/micro-frontend/c03-main-app.mdx +2 -2
  52. package/docs/zh/guides/topic-detail/monorepo/create-sub-project.mdx +0 -14
  53. package/docs/zh/guides/topic-detail/monorepo/sub-project-interface.mdx +7 -43
  54. package/docs/zh/tutorials/first-app/c05-loader.mdx +2 -2
  55. package/docs/zh/tutorials/first-app/c06-model.mdx +3 -3
  56. package/docs/zh/tutorials/first-app/c07-container.mdx +3 -3
  57. package/docs/zh/tutorials/foundations/introduction.mdx +3 -2
  58. 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
 
@@ -6,7 +6,7 @@ $ pnpm run dev
6
6
  > modern dev
7
7
 
8
8
  info Starting dev server...
9
- ready Client compiled in 50ms
9
+ ready Client compiled in 50 ms
10
10
 
11
11
  > Local: http://localhost:8080/
12
12
  > Network: http://192.168.0.1:8080/
@@ -0,0 +1,2 @@
1
+ - [Route Authorization](/tutorials/examples/csr-auth.html)
2
+ - ...
@@ -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 entry_customize
43
- entry_customize: './src/home/test/index.ts',
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
- entry_customize: {
93
+ 'my-entry': {
94
94
  // entry file path
95
- entry: './src/home/test/App.tsx',
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
- entry_customize: {
115
- entry: './src/home/test/index.tsx',
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.loader.ts"
26
- export default () => {
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.loader.ts"
161
+ ```tsx title="page.data.ts"
162
162
  import { useLoaderData } from '@modern-js/runtime/router';
163
163
 
164
- export default async () => {
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.loader.ts`.
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.loader.tsx"
320
+ ```ts title="routes/page.data.tsx"
321
321
  import fse from 'fs-extra';
322
- export default () => {
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.loader.ts"
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 default ({ params }: LoaderFunctionArgs) => {
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.loader.ts"
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.loader';
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.loader'`;
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.loader.ts"
507
+ ```ts title="page.data.ts"
508
508
  import { defer } from '@modern-js/runtime/router';
509
509
 
510
- export default () => {
510
+ export const loader = () => {
511
511
  const data = new Promise((resolve, reject) => {
512
512
  setTimeout(() => {
513
513
  reject(new Error('error occurs'));
@@ -0,0 +1,4 @@
1
+ {
2
+ "label": "Data solution",
3
+ "position": 3
4
+ }
@@ -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 `loader` 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:
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.loader.ts
37
+ ├── layout.data.ts
32
38
  ├── page.tsx
33
- └── page.loader.ts
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.loader.ts';
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.loader.ts"
54
+ ```ts title="routes/user/page.data.ts"
49
55
  export type ProfileData = {
50
56
  /* some types */
51
57
  };
52
58
 
53
- export default async (): Promise<ProfileData> => {
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 `loader` files share a type, so the `import type` syntax should be used.
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.loader.tsx
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.loader.ts
109
+ // routes/user/[id]/page.data.ts
104
110
  import { LoaderFunctionArgs } from '@modern-js/runtime/router';
105
111
 
106
- export default async ({ request }: LoaderFunctionArgs) => {
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.loader.tsx
156
- export default async function loader() {
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.loader.ts
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.loader.ts` and add the following code:
228
+ Create `user/layout.data.ts` and add the following code:
223
229
 
224
- ```ts title="routes/user/layout.loader.ts"
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 default () => {
290
- return {
291
- user: {},
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 default async () => {
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.loader.ts';
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.loader.ts'; // should use "import type" instead
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.loader.ts
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 */