@modern-js/main-doc 2.58.3 → 2.60.0
Sign up to get free protection for your applications and to get access to all the features.
- package/docs/en/_meta.json +10 -5
- package/docs/en/apis/app/hooks/api/lambda.mdx +4 -48
- package/docs/en/apis/app/hooks/api/middleware.mdx +11 -0
- package/docs/en/apis/app/runtime/core/use-loader.mdx +1 -1
- package/docs/en/community/blog/v2-release-note.mdx +1 -1
- package/docs/en/components/enable-bff.mdx +19 -2
- package/docs/en/components/extend-bff-function.mdx +5 -0
- package/docs/en/components/init-app.mdx +0 -1
- package/docs/en/components/init-rspack-app.mdx +0 -1
- package/docs/en/components/other-plugins.mdx +0 -0
- package/docs/en/components/ssr-monitor.mdx +3 -0
- package/docs/en/configure/app/auto-load-plugin.mdx +4 -0
- package/docs/en/configure/app/output/ssg.mdx +52 -141
- package/docs/en/configure/app/plugins.mdx +2 -2
- package/docs/en/configure/app/tools/esbuild.mdx +1 -1
- package/docs/en/configure/app/tools/swc.mdx +1 -1
- package/docs/en/configure/app/tools/tailwindcss.mdx +1 -1
- package/docs/en/guides/_meta.json +0 -5
- package/docs/en/guides/advanced-features/_meta.json +3 -8
- package/docs/en/guides/advanced-features/bff/_meta.json +1 -1
- package/docs/en/guides/advanced-features/bff/extend-server.mdx +154 -0
- package/docs/en/guides/advanced-features/bff/frameworks.mdx +52 -123
- package/docs/en/guides/advanced-features/bff/function.mdx +108 -80
- package/docs/en/guides/advanced-features/bff/sdk.mdx +40 -51
- package/docs/en/guides/advanced-features/build-performance.mdx +6 -21
- package/docs/en/guides/advanced-features/page-performance/_meta.json +1 -0
- package/docs/en/guides/advanced-features/rspack-start.mdx +6 -14
- package/docs/en/guides/basic-features/_meta.json +31 -9
- package/docs/en/guides/basic-features/css/_meta.json +1 -0
- package/docs/en/guides/basic-features/css/css-in-js.mdx +34 -0
- package/docs/en/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -4
- package/docs/en/guides/basic-features/css/css.mdx +25 -0
- package/docs/en/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +5 -66
- package/docs/en/guides/basic-features/data/data-fetch.mdx +134 -235
- package/docs/en/guides/basic-features/data/data-write.mdx +66 -77
- package/docs/en/guides/basic-features/debug/_meta.json +1 -0
- package/docs/en/guides/basic-features/debug/rsdoctor.mdx +57 -0
- package/docs/en/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +2 -0
- package/docs/en/guides/basic-features/render/_meta.json +1 -0
- package/docs/en/guides/basic-features/render/ssg.mdx +208 -0
- package/docs/en/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +38 -50
- package/docs/en/guides/basic-features/render/ssr.mdx +301 -0
- package/docs/en/guides/basic-features/render/streaming-ssr.mdx +230 -0
- package/docs/en/guides/basic-features/routes.mdx +274 -263
- package/docs/en/guides/basic-features/static-assets/_meta.json +1 -0
- package/docs/en/guides/basic-features/static-assets.mdx +2 -2
- package/docs/en/guides/basic-features/testing/_meta.json +1 -0
- package/docs/en/guides/basic-features/testing/cypress.mdx +95 -0
- package/docs/en/guides/basic-features/testing/jest.mdx +148 -0
- package/docs/en/guides/basic-features/testing/playwright.mdx +111 -0
- package/docs/en/guides/basic-features/testing/vitest.mdx +100 -0
- package/docs/en/guides/concept/entries.mdx +9 -2
- package/docs/en/guides/deprecated.md +2 -0
- package/docs/en/guides/get-started/quick-start.mdx +1 -1
- package/docs/en/guides/get-started/tech-stack.mdx +4 -4
- package/docs/en/guides/topic-detail/_meta.json +0 -6
- package/docs/en/guides/topic-detail/generator/create/config.mdx +0 -10
- package/docs/en/guides/topic-detail/generator/create/use.mdx +0 -1
- package/docs/en/plugin/_meta.json +19 -0
- package/docs/en/plugin/cli-plugins/_meta.json +1 -0
- package/docs/en/plugin/cli-plugins/plugin-bff.mdx +5 -0
- package/docs/en/plugin/cli-plugins/plugin-ssg.mdx +5 -0
- package/docs/en/{guides/rsbuild-plugins → plugin/cli-plugins}/plugin-swc.mdx +7 -0
- package/docs/en/plugin/cli-plugins/plugin-tailwind.mdx +5 -0
- package/docs/en/plugin/cli-plugins.mdx +6 -0
- package/docs/en/{guides/advanced-features/rsbuild-plugin.mdx → plugin/introduction.mdx} +36 -11
- package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/extend.mdx +1 -1
- package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/implement.mdx +3 -3
- package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/plugin-api.mdx +2 -2
- package/docs/en/plugin/rsbuild-plugins/_meta.json +1 -0
- package/docs/en/plugin/rsbuild-plugins.mdx +3 -0
- package/docs/en/tutorials/first-app/c03-css.mdx +1 -1
- package/docs/zh/_meta.json +10 -5
- package/docs/zh/apis/app/hooks/api/lambda.mdx +5 -48
- package/docs/zh/apis/app/hooks/api/middleware.mdx +11 -0
- package/docs/zh/apis/app/runtime/core/use-loader.mdx +1 -1
- package/docs/zh/community/blog/v2-release-note.mdx +1 -1
- package/docs/zh/components/enable-bff.mdx +19 -2
- package/docs/zh/components/extend-bff-function.mdx +5 -0
- package/docs/zh/components/init-app.mdx +0 -1
- package/docs/zh/components/init-rspack-app.mdx +0 -1
- package/docs/zh/components/other-plugins.mdx +0 -0
- package/docs/zh/components/ssr-monitor.mdx +3 -0
- package/docs/zh/configure/app/auto-load-plugin.mdx +4 -0
- package/docs/zh/configure/app/output/ssg.mdx +49 -139
- package/docs/zh/configure/app/plugins.mdx +2 -2
- package/docs/zh/configure/app/tools/esbuild.mdx +1 -1
- package/docs/zh/configure/app/tools/swc.mdx +1 -1
- package/docs/zh/configure/app/tools/tailwindcss.mdx +1 -1
- package/docs/zh/guides/_meta.json +0 -5
- package/docs/zh/guides/advanced-features/_meta.json +3 -8
- package/docs/zh/guides/advanced-features/bff/_meta.json +1 -1
- package/docs/zh/guides/advanced-features/bff/extend-server.mdx +156 -0
- package/docs/zh/guides/advanced-features/bff/frameworks.mdx +51 -117
- package/docs/zh/guides/advanced-features/bff/function.mdx +69 -59
- package/docs/zh/guides/advanced-features/bff/sdk.mdx +27 -36
- package/docs/zh/guides/advanced-features/build-performance.mdx +6 -21
- package/docs/zh/guides/advanced-features/page-performance/_meta.json +1 -0
- package/docs/zh/guides/advanced-features/rspack-start.mdx +8 -17
- package/docs/zh/guides/basic-features/_meta.json +31 -9
- package/docs/zh/guides/basic-features/alias.mdx +5 -11
- package/docs/zh/guides/basic-features/css/_meta.json +1 -0
- package/docs/zh/guides/basic-features/css/css-in-js.mdx +34 -0
- package/docs/zh/guides/basic-features/css/css.mdx +25 -0
- package/docs/zh/guides/basic-features/{css.mdx → css/tailwindcss.mdx} +3 -64
- package/docs/zh/guides/basic-features/data/data-fetch.mdx +96 -211
- package/docs/zh/guides/basic-features/data/data-write.mdx +54 -55
- package/docs/zh/guides/basic-features/debug/_meta.json +1 -0
- package/docs/zh/guides/basic-features/debug/rsdoctor.mdx +57 -0
- package/docs/zh/guides/{advanced-features → basic-features/debug}/using-storybook.mdx +1 -1
- package/docs/zh/guides/basic-features/env-vars.mdx +1 -1
- package/docs/zh/guides/basic-features/render/_meta.json +1 -0
- package/docs/zh/guides/basic-features/render/ssg.mdx +210 -0
- package/docs/zh/guides/{advanced-features/ssr/cache.mdx → basic-features/render/ssr-cache.mdx} +16 -26
- package/docs/zh/guides/basic-features/render/ssr.mdx +309 -0
- package/docs/zh/guides/{advanced-features/ssr/stream.mdx → basic-features/render/streaming-ssr.mdx} +22 -37
- package/docs/zh/guides/basic-features/routes.mdx +251 -237
- package/docs/zh/guides/basic-features/static-assets/_meta.json +1 -0
- package/docs/zh/guides/basic-features/static-assets.mdx +3 -7
- package/docs/zh/guides/basic-features/testing/_meta.json +1 -0
- package/docs/zh/guides/basic-features/testing/cypress.mdx +95 -0
- package/docs/zh/guides/basic-features/testing/jest.mdx +148 -0
- package/docs/zh/guides/basic-features/testing/playwright.mdx +112 -0
- package/docs/zh/guides/basic-features/testing/vitest.mdx +100 -0
- package/docs/zh/guides/concept/entries.mdx +6 -3
- package/docs/zh/guides/deprecated.md +4 -0
- package/docs/zh/guides/get-started/quick-start.mdx +1 -1
- package/docs/zh/guides/get-started/tech-stack.mdx +8 -8
- package/docs/zh/guides/topic-detail/_meta.json +0 -6
- package/docs/zh/guides/topic-detail/generator/create/config.mdx +0 -10
- package/docs/zh/guides/topic-detail/generator/create/use.mdx +0 -1
- package/docs/zh/plugin/_meta.json +19 -0
- package/docs/zh/plugin/cli-plugins/_meta.json +1 -0
- package/docs/zh/plugin/cli-plugins/plugin-bff.mdx +5 -0
- package/docs/zh/plugin/cli-plugins/plugin-ssg.mdx +5 -0
- package/docs/zh/{guides/rsbuild-plugins → plugin/cli-plugins}/plugin-swc.mdx +7 -0
- package/docs/zh/plugin/cli-plugins/plugin-tailwind.mdx +5 -0
- package/docs/zh/plugin/cli-plugins.mdx +6 -0
- package/docs/zh/{guides/advanced-features/rsbuild-plugin.mdx → plugin/introduction.mdx} +38 -13
- package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/extend.mdx +1 -1
- package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/implement.mdx +3 -3
- package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/plugin-api.mdx +2 -2
- package/docs/zh/plugin/rsbuild-plugins/_meta.json +1 -0
- package/docs/zh/plugin/rsbuild-plugins.mdx +4 -0
- package/docs/zh/tutorials/first-app/c03-css.mdx +1 -1
- package/i18n.json +42 -6
- package/package.json +7 -6
- package/rspress.config.ts +1 -58
- package/src/components/Footer/index.tsx +1 -1
- package/src/pages/index.tsx +0 -1
- package/docs/en/apis/app/hooks/api/api.mdx +0 -80
- package/docs/en/apis/app/hooks/api/app.mdx +0 -12
- package/docs/en/apis/app/hooks/config/storybook.mdx +0 -37
- package/docs/en/guides/advanced-features/bff/type.mdx +0 -46
- package/docs/en/guides/advanced-features/eslint.mdx +0 -148
- package/docs/en/guides/advanced-features/ssg.mdx +0 -116
- package/docs/en/guides/advanced-features/ssr/_meta.json +0 -1
- package/docs/en/guides/advanced-features/ssr/index.mdx +0 -23
- package/docs/en/guides/advanced-features/ssr/stream.mdx +0 -248
- package/docs/en/guides/advanced-features/ssr/usage.mdx +0 -341
- package/docs/en/guides/advanced-features/ssr.mdx +0 -555
- package/docs/zh/apis/app/hooks/api/api.mdx +0 -81
- package/docs/zh/apis/app/hooks/api/app.mdx +0 -12
- package/docs/zh/apis/app/hooks/config/storybook.mdx +0 -38
- package/docs/zh/guides/advanced-features/bff/type.mdx +0 -46
- package/docs/zh/guides/advanced-features/eslint.mdx +0 -152
- package/docs/zh/guides/advanced-features/ssg.mdx +0 -116
- package/docs/zh/guides/advanced-features/ssr/_meta.json +0 -1
- package/docs/zh/guides/advanced-features/ssr/index.mdx +0 -23
- package/docs/zh/guides/advanced-features/ssr/usage.mdx +0 -329
- /package/docs/en/guides/advanced-features/{bff/index.mdx → bff.mdx} +0 -0
- /package/docs/en/guides/advanced-features/{code-split.mdx → page-performance/code-split.mdx} +0 -0
- /package/docs/en/guides/advanced-features/{inline-assets.mdx → page-performance/inline-assets.mdx} +0 -0
- /package/docs/en/guides/advanced-features/{optimize-bundle.mdx → page-performance/optimize-bundle.mdx} +0 -0
- /package/docs/en/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
- /package/docs/en/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
- /package/docs/en/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
- /package/docs/en/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
- /package/docs/en/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/_meta.json +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook-list.mdx +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook.mdx +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/introduction.mdx +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/lifecycle.mdx +0 -0
- /package/docs/en/{guides/topic-detail/framework-plugin → plugin/plugin-system}/relationship.mdx +0 -0
- /package/docs/en/{guides → plugin}/rsbuild-plugins/plugin-esbuild.mdx +0 -0
- /package/docs/zh/guides/advanced-features/{bff/index.mdx → bff.mdx} +0 -0
- /package/docs/zh/guides/advanced-features/{code-split.mdx → page-performance/code-split.mdx} +0 -0
- /package/docs/zh/guides/advanced-features/{inline-assets.mdx → page-performance/inline-assets.mdx} +0 -0
- /package/docs/zh/guides/advanced-features/{optimize-bundle.mdx → page-performance/optimize-bundle.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{css-modules.mdx → css/css-modules.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{mock.mdx → debug/mock.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{proxy.mdx → debug/proxy.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{json-files.mdx → static-assets/json-files.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{svg-assets.mdx → static-assets/svg-assets.mdx} +0 -0
- /package/docs/zh/guides/basic-features/{wasm-assets.mdx → static-assets/wasm-assets.mdx} +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/_meta.json +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook-list.mdx +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/hook.mdx +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/introduction.mdx +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/lifecycle.mdx +0 -0
- /package/docs/zh/{guides/topic-detail/framework-plugin → plugin/plugin-system}/relationship.mdx +0 -0
- /package/docs/zh/{guides → plugin}/rsbuild-plugins/plugin-esbuild.mdx +0 -0
@@ -4,17 +4,20 @@ sidebar_position: 2
|
|
4
4
|
|
5
5
|
# Routing
|
6
6
|
|
7
|
-
Modern.js
|
7
|
+
Modern.js routing is based on [React Router 6](https://reactrouter.com/en/main), offering file convention-based routing capabilities and supporting the industry-popular **nested routing** pattern. When an entry is recognized as [conventional routing](/guides/concept/entries.html#conventional-routing), Modern.js automatically generates the corresponding routing structure based on the file system.
|
8
8
|
|
9
9
|
:::note
|
10
|
-
The routing mentioned in this section refers to
|
10
|
+
The routing mentioned in this section all refers to conventional routing.
|
11
11
|
:::
|
12
12
|
|
13
|
-
##
|
13
|
+
## What is Nested Routing
|
14
14
|
|
15
|
-
|
15
|
+
Nested routing is a pattern that couples URL segments with the component hierarchy and data. Typically, URL segments determine:
|
16
16
|
|
17
|
-
|
17
|
+
- The layouts to render on the page
|
18
|
+
- The data dependencies of those layouts
|
19
|
+
|
20
|
+
Therefore, when using nested routing, the page's routing and UI structure are in correspondence. We will introduce this routing pattern in detail.
|
18
21
|
|
19
22
|
```bash
|
20
23
|
/user/johnny/profile /user/johnny/posts
|
@@ -27,62 +30,45 @@ Modern.js supports the popular conventional routing mode in the industry: **Nest
|
|
27
30
|
+------------------+ +-----------------+
|
28
31
|
```
|
29
32
|
|
30
|
-
|
33
|
+
## Routing File Conventions
|
31
34
|
|
32
|
-
|
35
|
+
In the `routes/` directory, subdirectory names are mapped to route URLs. Modern.js has two file conventions: `layout.tsx` and `page.tsx`. These files determine the layout hierarchy of the application:
|
33
36
|
|
34
|
-
|
37
|
+
- `page.tsx`: This is the content component. When this file exists in a directory, the corresponding route URL is accessible.
|
38
|
+
- `layout.tsx`: This is the layout component and controls the layout of all sub-routes in its directory by using `<Outlet>` to represent child components.
|
35
39
|
|
36
|
-
|
37
|
-
.
|
38
|
-
|
39
|
-
├── page.tsx
|
40
|
-
└── user
|
41
|
-
└── page.tsx
|
42
|
-
```
|
40
|
+
:::tip
|
41
|
+
`.ts`, `.js`, `.jsx`, or `.tsx` file extensions can be used for the above convention files.
|
42
|
+
:::
|
43
43
|
|
44
|
-
|
44
|
+
### Page
|
45
45
|
|
46
|
-
|
47
|
-
- `/user`
|
46
|
+
The `<Page>` component refers to all `page.tsx` files in the `routes/` directory and is the leaf component for all routes. All routes should end with a `<Page>` component except for wildcard routes.
|
48
47
|
|
49
|
-
|
48
|
+
```tsx title=routes/page.tsx
|
49
|
+
export default () => {
|
50
|
+
return <div>Hello world</div>
|
51
|
+
};
|
52
|
+
```
|
50
53
|
|
51
|
-
|
52
|
-
Here, `routes/layout.tsx` will be used as the layout component for all components under the `/` route, and `routes/user/layout.tsx` will be used as the layout component for all route components under the `/user` route.
|
53
|
-
:::
|
54
|
+
When the application has the following directory structure:
|
54
55
|
|
55
56
|
```bash
|
56
57
|
.
|
57
58
|
└── routes
|
58
|
-
├── layout.tsx
|
59
59
|
├── page.tsx
|
60
60
|
└── user
|
61
|
-
├── layout.tsx
|
62
61
|
└── page.tsx
|
63
62
|
```
|
64
63
|
|
65
|
-
|
66
|
-
|
67
|
-
```tsx
|
68
|
-
<Layout>
|
69
|
-
<Page />
|
70
|
-
</Layout>
|
71
|
-
```
|
72
|
-
|
73
|
-
Similarly, `routes/user/layout.tsx` will be used as the layout component for all components under the `/user` route. When the route is `/user`, the following UI layout will be displayed:
|
64
|
+
The following two routes will be produced:
|
74
65
|
|
75
|
-
|
76
|
-
|
77
|
-
<UserLayout>
|
78
|
-
<UserPage />
|
79
|
-
</UserLayout>
|
80
|
-
</Layout>
|
81
|
-
```
|
66
|
+
- `/`
|
67
|
+
- `/user`
|
82
68
|
|
83
|
-
|
69
|
+
### Layout
|
84
70
|
|
85
|
-
The `<Layout>` component refers to all `layout.tsx` files
|
71
|
+
The `<Layout>` component refers to all `layout.tsx` files in the `routes/` directory. These represent the layout of their respective route segments, using `<Outlet>` for child components.
|
86
72
|
|
87
73
|
```tsx title=routes/layout.tsx
|
88
74
|
import { Link, Outlet, useLoaderData } from '@modern-js/runtime/router';
|
@@ -97,11 +83,10 @@ export default () => {
|
|
97
83
|
```
|
98
84
|
|
99
85
|
:::note
|
100
|
-
`<Outlet>` is
|
101
|
-
|
86
|
+
`<Outlet>` is an API provided by React Router 6. For more details, see [Outlet](https://reactrouter.com/en/main/components/outlet#outlet).
|
102
87
|
:::
|
103
88
|
|
104
|
-
|
89
|
+
Under different directory structures, the components represented by `<Outlet>` are also different. To illustrate the relationship between `<Layout>` and `<Outlet>`, let's consider the following directory structure:
|
105
90
|
|
106
91
|
```bash
|
107
92
|
.
|
@@ -115,7 +100,7 @@ To simplify the introduction of the relationship between `<Layout>` and `<Outlet
|
|
115
100
|
└── page.tsx
|
116
101
|
```
|
117
102
|
|
118
|
-
1. When the route is `/`, the `<Outlet>` in `routes/layout.tsx` represents the component exported
|
103
|
+
1. When the route is `/`, the `<Outlet>` in `routes/layout.tsx` represents the component exported from `routes/page.tsx`. The UI structure of the route is:
|
119
104
|
|
120
105
|
```tsx
|
121
106
|
<Layout>
|
@@ -123,7 +108,7 @@ To simplify the introduction of the relationship between `<Layout>` and `<Outlet
|
|
123
108
|
</Layout>
|
124
109
|
```
|
125
110
|
|
126
|
-
2. When the route is `/blog`, the `<Outlet>` in `routes/layout.tsx` represents the component exported
|
111
|
+
2. When the route is `/blog`, the `<Outlet>` in `routes/layout.tsx` represents the component exported from `routes/blog/page.tsx`. The UI structure of the route is:
|
127
112
|
|
128
113
|
```tsx
|
129
114
|
<Layout>
|
@@ -131,7 +116,7 @@ To simplify the introduction of the relationship between `<Layout>` and `<Outlet
|
|
131
116
|
</Layout>
|
132
117
|
```
|
133
118
|
|
134
|
-
3. When the route is `/user`, the `<Outlet>` in `routes/layout.tsx` represents the component exported
|
119
|
+
3. When the route is `/user`, the `<Outlet>` in `routes/layout.tsx` represents the component exported from `routes/user/layout.tsx`. The `<Outlet>` in `routes/user/layout.tsx` represents the component exported from `routes/user/page.tsx`. The UI structure of the route is:
|
135
120
|
|
136
121
|
```tsx
|
137
122
|
<Layout>
|
@@ -141,92 +126,89 @@ To simplify the introduction of the relationship between `<Layout>` and `<Outlet
|
|
141
126
|
</Layout>
|
142
127
|
```
|
143
128
|
|
144
|
-
In summary, if there is a `layout.tsx`
|
145
|
-
|
146
|
-
#### Page
|
129
|
+
In summary, if there is a `layout.tsx` in the sub-route's directory, the `<Outlet>` in the parent `layout.tsx` corresponds to the `layout.tsx` in the sub-route's directory. Otherwise, it corresponds to the `page.tsx` in the sub-route's directory.
|
147
130
|
|
148
|
-
|
149
|
-
|
150
|
-
#### Config
|
151
|
-
|
152
|
-
Each `Layout`,`$` or `Page` file can define its own `config` file, such as `page.config.ts`. In this file, we have an conventinal on a named export called `handle`, which you can define any properties:
|
153
|
-
|
154
|
-
```ts title="routes/blog/page.config.ts"
|
155
|
-
export const handle = {
|
156
|
-
breadcrumbName: 'profile',
|
157
|
-
};
|
158
|
-
```
|
131
|
+
## Dynamic Routes
|
159
132
|
|
160
|
-
|
161
|
-
|
162
|
-
```ts title="routes/layout.ts"
|
163
|
-
export default () => {
|
164
|
-
const matches = useMatches();
|
165
|
-
const breadcrumbs = matches.map(
|
166
|
-
matchedRoute => matchedRoute?.handle?.breadcrumbName,
|
167
|
-
);
|
168
|
-
return <Breadcrumb names={breadcrumbs}></Breadcrumb>;
|
169
|
-
};
|
170
|
-
```
|
171
|
-
|
172
|
-
### Dynamic Routing
|
173
|
-
|
174
|
-
Routes generated from file directories named with `[]` will be handled as dynamic routes. For example, the following file directory:
|
133
|
+
Files and directories named with `[]` are turned into dynamic routes. For instance, consider the following directory structure:
|
175
134
|
|
176
135
|
```bash
|
136
|
+
.
|
177
137
|
└── routes
|
178
|
-
├── [id]
|
179
|
-
│ └── page.tsx
|
180
138
|
├── blog
|
181
|
-
│ └──
|
139
|
+
│ └── [id]
|
140
|
+
│ └── page.tsx
|
182
141
|
└── page.tsx
|
183
142
|
```
|
184
143
|
|
185
|
-
The `routes/[id]/page.tsx` file will be converted to the `/:id` route.
|
144
|
+
The `routes/[id]/page.tsx` file will be converted to the `/:id` route. Apart from the `/blog` route that can be exactly matched, all `/xxx` paths will match this route.
|
186
145
|
|
187
|
-
In the component, you can use [useParams](/apis/app/runtime/router/router#useparams) to get
|
146
|
+
In the component, you can use [useParams](/apis/app/runtime/router/router#useparams) to get parameters named accordingly.
|
188
147
|
|
189
|
-
|
148
|
+
```tsx
|
149
|
+
import { useParams } from '@modern-js/runtime/router';
|
150
|
+
|
151
|
+
function Blog() {
|
152
|
+
const { id } = useParams();
|
153
|
+
return <div>current blog ID is: {id}</div>;
|
154
|
+
}
|
155
|
+
export default Blog;
|
156
|
+
```
|
190
157
|
|
191
|
-
|
158
|
+
## Optional Dynamic Routes
|
192
159
|
|
193
|
-
|
160
|
+
Files and directories named with `[$]` are turned into optional dynamic routes. For example, the following directory structure:
|
194
161
|
|
195
162
|
```bash
|
163
|
+
.
|
196
164
|
└── routes
|
197
|
-
├──
|
165
|
+
├── blog
|
198
166
|
│ └── [id$]
|
199
167
|
│ └── page.tsx
|
200
|
-
├── blog
|
201
|
-
│ └── page.tsx
|
202
168
|
└── page.tsx
|
203
169
|
```
|
204
170
|
|
205
|
-
The `routes/user/[id$]/page.tsx` file will be converted to the `/user/:id?` route. All routes under `/user` will match this route, and the `id` parameter is optional. This route
|
171
|
+
The `routes/user/[id$]/page.tsx` file will be converted to the `/user/:id?` route. All routes under `/user` will match this route, and the `id` parameter is optional. This route can be used to distinguish between **create** and **edit** actions.
|
206
172
|
|
207
|
-
|
173
|
+
```tsx
|
174
|
+
import { useParams } from '@modern-js/runtime/router';
|
175
|
+
|
176
|
+
function Blog() {
|
177
|
+
const { id } = useParams();
|
178
|
+
if (id) {
|
179
|
+
return <div>current blog ID is: {id}</div>;
|
180
|
+
}
|
208
181
|
|
209
|
-
|
182
|
+
return <div>create new blog</div>;
|
183
|
+
}
|
184
|
+
export default Blog;
|
185
|
+
```
|
210
186
|
|
211
|
-
|
187
|
+
## Wildcard Routes
|
212
188
|
|
213
|
-
If
|
189
|
+
If there is a `$.tsx` file in a subdirectory, it acts as a wildcard route component and will be rendered when no other routes match.
|
214
190
|
|
215
191
|
:::note
|
216
|
-
`$.tsx` can be
|
192
|
+
`$.tsx` can be thought of as a special `<Page>` component. If no routes match, `$.tsx` will be rendered as a child component of the `<Layout>`.
|
193
|
+
:::
|
194
|
+
|
195
|
+
:::warning
|
196
|
+
If there is no `<Layout>` component in the current directory, `$.tsx` will not have any effect.
|
217
197
|
:::
|
218
198
|
|
219
|
-
For example, the following directory structure:
|
199
|
+
For example, consider the following directory structure:
|
220
200
|
|
221
201
|
```bash
|
202
|
+
.
|
222
203
|
└── routes
|
223
|
-
├── $.tsx
|
224
204
|
├── blog
|
225
|
-
│
|
205
|
+
│ ├── $.tsx
|
206
|
+
│ └── layout.tsx
|
207
|
+
├── layout.tsx
|
226
208
|
└── page.tsx
|
227
209
|
```
|
228
210
|
|
229
|
-
When
|
211
|
+
When you visit `/blog/a` and no routes match, the page will render the `routes/blog/$.tsx` component. The UI structure of the route is:
|
230
212
|
|
231
213
|
```tsx
|
232
214
|
<RootLayout>
|
@@ -236,20 +218,76 @@ When accessing any path that does not match(For example `/blog/a`), the `routes/
|
|
236
218
|
</RootLayout>
|
237
219
|
```
|
238
220
|
|
239
|
-
If you want
|
221
|
+
If you want `/blog` to match the `blog/$.tsx` file as well, you need to remove the `blog.tsx` file from the same directory and ensure there are no other sub-routes under `blog`.
|
240
222
|
|
241
|
-
|
223
|
+
Similarly, you can use [useParams](/apis/app/runtime/router/router#useparams) to capture the remaining part of the URL in the `$.tsx` component.
|
242
224
|
|
243
225
|
```ts title="$.tsx"
|
244
226
|
import { useParams } from '@modern-js/runtime/router';
|
245
|
-
|
246
|
-
|
247
|
-
|
227
|
+
|
228
|
+
function Blog() {
|
229
|
+
// When the path is `/blog/aaa/bbb`
|
230
|
+
const params = useParams();
|
231
|
+
console.log(params) // ---> { '*': 'aaa/bbb' }
|
232
|
+
|
233
|
+
return <div>current blog URL is {params["*"]}</div>;
|
234
|
+
}
|
235
|
+
export default Blog;
|
248
236
|
```
|
249
237
|
|
250
|
-
###
|
238
|
+
### Custom 404 Page
|
239
|
+
|
240
|
+
Wildcard routes can be added to any subdirectory in the `routes/` directory. A common use case is to customize a 404 page at any level using a `$.tsx` file.
|
251
241
|
|
252
|
-
|
242
|
+
For instance, if you want to show a 404 page for all unmatched routes, you can add a `routes/$.tsx` file:
|
243
|
+
|
244
|
+
```bash
|
245
|
+
.
|
246
|
+
└── routes
|
247
|
+
├── $.tsx
|
248
|
+
├── blog
|
249
|
+
│ └── [id$]
|
250
|
+
│ └── page.tsx
|
251
|
+
├── layout.tsx
|
252
|
+
└── page.tsx
|
253
|
+
```
|
254
|
+
|
255
|
+
```tsx
|
256
|
+
function Page404() {
|
257
|
+
return <div>404 Not Found</div>;
|
258
|
+
}
|
259
|
+
export default Page404;
|
260
|
+
```
|
261
|
+
|
262
|
+
At this point, when accessing routes other than `/` or `/blog/*`, they will match the `routes/$.tsx` component and display a 404 page.
|
263
|
+
|
264
|
+
## Route Handle Configuration
|
265
|
+
|
266
|
+
In some scenarios, each route might have its own data which the application needs to access in other components. A common example is retrieving breadcrumb information for the matched route.
|
267
|
+
|
268
|
+
Modern.js provides a convention where each `Layout`, `$`, or `Page` file can define its own `config` file such as `page.config.ts`. In this file, we conventionally export a named export `handle`, in which you can define any properties:
|
269
|
+
|
270
|
+
```ts title="routes/page.config.ts"
|
271
|
+
export const handle = {
|
272
|
+
breadcrumbName: 'profile',
|
273
|
+
};
|
274
|
+
```
|
275
|
+
|
276
|
+
These defined properties can be accessed using the [`useMatches`](https://reactrouter.com/en/main/hooks/use-matches) hook.
|
277
|
+
|
278
|
+
```ts title="routes/layout.ts"
|
279
|
+
export default () => {
|
280
|
+
const matches = useMatches();
|
281
|
+
const breadcrumbs = matches.map(
|
282
|
+
matchedRoute => matchedRoute?.handle?.breadcrumbName,
|
283
|
+
);
|
284
|
+
return <Breadcrumb names={breadcrumbs}></Breadcrumb>;
|
285
|
+
};
|
286
|
+
```
|
287
|
+
|
288
|
+
## Pathless Layouts
|
289
|
+
|
290
|
+
When a directory name starts with `__`, the corresponding directory name will not be converted into an actual route path, for example:
|
253
291
|
|
254
292
|
```bash
|
255
293
|
.
|
@@ -258,21 +296,21 @@ When the directory name starts with `__`, the directory name will not be convert
|
|
258
296
|
│ ├── layout.tsx
|
259
297
|
│ ├── login
|
260
298
|
│ │ └── page.tsx
|
261
|
-
│ └──
|
299
|
+
│ └── sign
|
262
300
|
│ └── page.tsx
|
263
301
|
├── layout.tsx
|
264
302
|
└── page.tsx
|
265
303
|
```
|
266
304
|
|
267
|
-
Modern.js will generate
|
305
|
+
Modern.js will generate `/login` and `/sign` routes, and the `__auth/layout.tsx` component will serve as the layout for `login/page.tsx` and `sign/page.tsx`, but `__auth` will not appear as a path segment in the URL.
|
268
306
|
|
269
|
-
This feature is
|
307
|
+
This feature is useful when you need to create independent layouts or categorize routes without adding additional path segments.
|
270
308
|
|
271
|
-
|
309
|
+
## Pathless File Segments
|
272
310
|
|
273
|
-
In some cases,
|
311
|
+
In some cases, a project may need complex routes that do not have independent UI layouts. Creating these routes as regular directories can lead to deeply nested directories.
|
274
312
|
|
275
|
-
|
313
|
+
Modern.js supports replacing directory names with `.` to divide route segments. For example, to create a route like `/user/profile/2022/edit`, you can create the following file:
|
276
314
|
|
277
315
|
```bash
|
278
316
|
└── routes
|
@@ -282,19 +320,97 @@ Therefore, Modern.js supports using `.` to separate route segments instead of fi
|
|
282
320
|
└── page.tsx
|
283
321
|
```
|
284
322
|
|
285
|
-
When
|
323
|
+
When accessed, the resulting route will have the following UI structure:
|
286
324
|
|
287
325
|
```tsx
|
288
326
|
<RootLayout>
|
289
|
-
|
327
|
+
{/* routes/user.profile.[id].edit/page.tsx */}
|
328
|
+
<UserProfileEdit />
|
290
329
|
</RootLayout>
|
291
330
|
```
|
292
331
|
|
293
|
-
|
332
|
+
## Route Redirections
|
294
333
|
|
295
|
-
In
|
334
|
+
In some applications, you may need to redirect to another route based on user identity or other data conditions. In Modern.js, you can use a [`Data Loader`](/guides/basic-features/data/data-fetch) file to fetch data or use traditional React components with `useEffect`.
|
296
335
|
|
297
|
-
|
336
|
+
### Redirecting in Data Loader
|
337
|
+
|
338
|
+
Create a `page.data.ts` file in the same directory as `page.tsx`. This file is the Data Loader for that route. In the Data Loader, you can call the `redirect` API to perform route redirections.
|
339
|
+
|
340
|
+
```ts title="routes/user/page.data.ts"
|
341
|
+
import { redirect } from '@modern-js/runtime/router';
|
342
|
+
|
343
|
+
export const loader = () => {
|
344
|
+
const user = await getUser();
|
345
|
+
if (!user) {
|
346
|
+
return redirect('/login');
|
347
|
+
}
|
348
|
+
return null;
|
349
|
+
};
|
350
|
+
```
|
351
|
+
|
352
|
+
### Redirecting in a Component
|
353
|
+
|
354
|
+
To perform a redirection within a component, use the `useNavigate` hook as shown below:
|
355
|
+
|
356
|
+
```ts title="routes/user/page.ts"
|
357
|
+
import { useNavigate } from '@modern-js/runtime/router';
|
358
|
+
import { useEffect } from 'react';
|
359
|
+
|
360
|
+
export default () => {
|
361
|
+
const navigate = useNavigate();
|
362
|
+
useEffect(() => {
|
363
|
+
getUser().then(user => {
|
364
|
+
if (!user) {
|
365
|
+
navigate('/login');
|
366
|
+
}
|
367
|
+
});
|
368
|
+
});
|
369
|
+
|
370
|
+
return <div>Hello World</div>;
|
371
|
+
};
|
372
|
+
```
|
373
|
+
|
374
|
+
## Error Handling
|
375
|
+
|
376
|
+
In each directory under `routes/`, developers can define an `error.tsx` file that exports an `<ErrorBoundary>` component. When this component is present, rendering errors in the route directory will be caught by the `ErrorBoundary` component.
|
377
|
+
|
378
|
+
`<ErrorBoundary>` can return the UI view when an error occurs. If the current level does not declare an `<ErrorBoundary>` component, errors will bubble up to higher-level components until they are caught or thrown. Additionally, when an error occurs within a component, it only affects the route component and its children, leaving the state and view of other components unaffected and interactive.
|
379
|
+
|
380
|
+
{/* Todo API Routes */}
|
381
|
+
|
382
|
+
In the `<ErrorBoundary>` component, you can use [useRouteError](/apis/app/runtime/router/router#userouteerror) to obtain specific error information:
|
383
|
+
|
384
|
+
```tsx
|
385
|
+
import { useRouteError } from '@modern-js/runtime/router';
|
386
|
+
|
387
|
+
const ErrorBoundary = () => {
|
388
|
+
const error = useRouteError();
|
389
|
+
return (
|
390
|
+
<div>
|
391
|
+
<h1>{error.status}</h1>
|
392
|
+
<h2>{error.message}</h2>
|
393
|
+
</div>
|
394
|
+
);
|
395
|
+
};
|
396
|
+
export default ErrorBoundary;
|
397
|
+
```
|
398
|
+
|
399
|
+
## Loading (Experimental)
|
400
|
+
|
401
|
+
:::info Experimental
|
402
|
+
This feature is currently experimental, and its API may change in the future.
|
403
|
+
:::
|
404
|
+
|
405
|
+
In conventional routing, Modern.js automatically splits routes into chunks (each route loads as a separate JS chunk). When users visit a specific route, the corresponding chunk is automatically loaded, effectively reducing the first-screen load time. However, this can lead to a white screen if the route's chunk is not yet loaded.
|
406
|
+
|
407
|
+
Modern.js supports solving this issue with a `loading.tsx` file. Each directory under `routes/` can create a `loading.tsx` file that exports a `<Loading>` component.
|
408
|
+
|
409
|
+
:::warning
|
410
|
+
If there is no `<Layout>` component in the current directory, `loading.tsx` will not have any effect. To ensure a good user experience, Modern.js recommends adding a root Loading component to each application.
|
411
|
+
:::
|
412
|
+
|
413
|
+
When both this component and a `layout` component exist in the route directory, all child routes under this level will first display the UI from the exported `<Loading>` component until the corresponding JS chunk is fully loaded. For example, with the following file structure:
|
298
414
|
|
299
415
|
```bash
|
300
416
|
.
|
@@ -308,11 +424,9 @@ When this component and the `layout` component exist in the route directory, the
|
|
308
424
|
└── page.tsx
|
309
425
|
```
|
310
426
|
|
311
|
-
When defining `loading.tsx`,
|
312
|
-
|
313
|
-
When the route is `/`:
|
427
|
+
When defining a `loading.tsx`, if the route transitions from `/` to `/blog` or from `/blog` to `/blog/123`, and the JS chunk for the route is not yet loaded, the UI from the `<Loading>` component will be displayed first. This results in the following UI structure:
|
314
428
|
|
315
|
-
```tsx
|
429
|
+
```tsx title=When the route is "/"
|
316
430
|
<Layout>
|
317
431
|
<Suspense fallback={<Loading />}>
|
318
432
|
<Page />
|
@@ -320,9 +434,7 @@ When the route is `/`:
|
|
320
434
|
</Layout>
|
321
435
|
```
|
322
436
|
|
323
|
-
When the route is
|
324
|
-
|
325
|
-
```tsx
|
437
|
+
```tsx title=When the route is "/blog"
|
326
438
|
<Layout>
|
327
439
|
<Suspense fallback={<Loading />}>
|
328
440
|
<BlogPage />
|
@@ -330,9 +442,7 @@ When the route is `/blog`:
|
|
330
442
|
</Layout>
|
331
443
|
```
|
332
444
|
|
333
|
-
When the route is
|
334
|
-
|
335
|
-
```tsx
|
445
|
+
```tsx title=When the route is "/blog/123"
|
336
446
|
<Layout>
|
337
447
|
<Suspense fallback={<Loading />}>
|
338
448
|
<BlogIdPage />
|
@@ -340,71 +450,44 @@ When the route is `/blog/123`:
|
|
340
450
|
</Layout>
|
341
451
|
```
|
342
452
|
|
343
|
-
|
344
|
-
When the Layout component does not exist in the directory, the Loading component in that directory will not take effect. Modern.js recommends having a root Layout and root Loading.
|
345
|
-
|
346
|
-
:::
|
347
|
-
|
348
|
-
When the route jumps from `/` to `/blog`, if the JS Chunk of the `blog/page` component has not been loaded yet, the UI of the component exported in `loading.tsx` will be displayed first.
|
349
|
-
|
350
|
-
Similarly, when the route jumps from `/` or `/blog` to `/blog/123`, if the JS Chunk of the `blog/[id]/page` component has not been loaded yet, the UI of the component exported in `loading.tsx` will be displayed first.
|
453
|
+
## Prefetching
|
351
454
|
|
352
|
-
|
455
|
+
Most white screens during route transitions can be optimized by defining a `<Loading>` component. Modern.js also supports preloading static resources and data with the `prefetch` attribute on `<Link>` components.
|
353
456
|
|
354
|
-
|
457
|
+
For applications with higher performance requirements, prefetching can further enhance the user experience by reducing the time spent displaying the `<Loading>` component:
|
355
458
|
|
356
|
-
```
|
357
|
-
|
358
|
-
|
359
|
-
export const loader = () => {
|
360
|
-
const user = await getUser();
|
361
|
-
if (!user) {
|
362
|
-
return redirect('/login');
|
363
|
-
}
|
364
|
-
return null;
|
365
|
-
};
|
459
|
+
```tsx
|
460
|
+
<Link prefetch="intent" to="page">
|
366
461
|
```
|
367
462
|
|
368
|
-
|
463
|
+
:::tip
|
369
464
|
|
370
|
-
|
371
|
-
import { useNavigate } from '@modern-js/runtime/router';
|
465
|
+
Data preloading currently only preloads data returned by the [Data Loader](/guides/basic-features/data/data-fetch) in SSR projects.
|
372
466
|
|
373
|
-
|
374
|
-
const navigate = useNavigate();
|
375
|
-
navigate('/login');
|
376
|
-
};
|
377
|
-
```
|
467
|
+
:::
|
378
468
|
|
379
|
-
|
469
|
+
The `prefetch` attribute has three optional values:
|
380
470
|
|
381
|
-
|
471
|
+
- `none`: The default value. No prefetching, no additional behavior.
|
472
|
+
- `intent`: This is the recommended value for most scenarios. When you hover over the Link, it will automatically start loading the corresponding chunk and the data defined in the Data Loader. If the mouse moves away, the loading is automatically canceled. In our tests, even quick clicks can reduce load time by approximately 200ms.
|
473
|
+
- `render`: When the `<Link>` component is rendered, it begins loading the corresponding chunk and data defined in the Data Loader.
|
382
474
|
|
383
|
-
|
475
|
+
:::details Difference Between "render" and Not Using Route Splitting
|
476
|
+
- `render` allows you to control the timing of route splitting, triggering only when the `<Link>` component enters the viewport. You can control the loading timing of the split by adjusting the rendering position of the `<Link>` component.
|
477
|
+
- `render` loads static resources only during idle times, thus not occupying the loading time of critical modules.
|
478
|
+
- Besides preloading route splits, `render` will also initiate data prefetching in SSR projects.
|
384
479
|
|
385
|
-
|
480
|
+
:::
|
386
481
|
|
387
|
-
In the `<ErrorBoundary>` component, you can use [useRouteError](/apis/app/runtime/router/router#userouteerror) to get specific information about the error:
|
388
482
|
|
389
|
-
|
390
|
-
import { useRouteError } from '@modern-js/runtime/router';
|
391
|
-
export const ErrorBoundary = () => {
|
392
|
-
const error = useRouteError();
|
393
|
-
return (
|
394
|
-
<div>
|
395
|
-
<h1>{error.status}</h1>
|
396
|
-
<h2>{error.message}</h2>
|
397
|
-
</div>
|
398
|
-
);
|
399
|
-
};
|
400
|
-
```
|
483
|
+
## Runtime Configuration
|
401
484
|
|
402
|
-
|
485
|
+
{/* Todo Move to runtime configuration chapter */}
|
403
486
|
|
404
|
-
In
|
487
|
+
In the root `<Layout>` component (`routes/layout.ts`), you can dynamically define runtime configuration:
|
405
488
|
|
406
489
|
```tsx title="src/routes/layout.tsx"
|
407
|
-
// Define runtime
|
490
|
+
// Define runtime configuration
|
408
491
|
import type { AppConfig } from '@modern-js/runtime';
|
409
492
|
|
410
493
|
export const config = (): AppConfig => {
|
@@ -423,9 +506,11 @@ export const config = (): AppConfig => {
|
|
423
506
|
};
|
424
507
|
```
|
425
508
|
|
426
|
-
|
509
|
+
## Pre-render Hooks
|
510
|
+
|
511
|
+
{/* Todo Move to runtime configuration chapter */}
|
427
512
|
|
428
|
-
In some scenarios, you
|
513
|
+
In some scenarios, you need to perform certain actions before the application renders. You can define the `init` hook in `routes/layout.tsx`, which will be executed both on the client and server. A basic example is shown below:
|
429
514
|
|
430
515
|
```ts title="src/routes/layout.tsx"
|
431
516
|
import type { RuntimeContext } from '@modern-js/runtime';
|
@@ -435,10 +520,10 @@ export const init = (context: RuntimeContext) => {
|
|
435
520
|
};
|
436
521
|
```
|
437
522
|
|
438
|
-
|
523
|
+
With the `init` hook, you can mount some global data that can be accessed elsewhere in the application via the `runtimeContext` variable:
|
439
524
|
|
440
525
|
:::note
|
441
|
-
This feature is very useful when
|
526
|
+
This feature is very useful when applications require pre-rendered data, custom data injection, or framework migration (e.g., Next.js).
|
442
527
|
:::
|
443
528
|
|
444
529
|
```ts title="src/routes/layout.tsx"
|
@@ -452,7 +537,7 @@ export const init = (context: RuntimeContext) => {
|
|
452
537
|
```
|
453
538
|
|
454
539
|
```tsx title="src/routes/page.tsx"
|
455
|
-
import { useRuntimeContext } from '@modern-js/runtime
|
540
|
+
import { useRuntimeContext } from '@modern-js/runtime;
|
456
541
|
|
457
542
|
export default () => {
|
458
543
|
const context = useRuntimeContext();
|
@@ -462,10 +547,10 @@ export default () => {
|
|
462
547
|
};
|
463
548
|
```
|
464
549
|
|
465
|
-
|
550
|
+
With SSR, the browser can obtain the data returned by `init` during SSR. Developers can decide whether to re-fetch the data on the browser side to override the SSR data. For example:
|
466
551
|
|
467
552
|
```tsx title="src/routes/layout.tsx"
|
468
|
-
import { RuntimeContext } from '@modern-js/runtime
|
553
|
+
import { RuntimeContext } from '@modern-js/runtime;
|
469
554
|
|
470
555
|
export const init = (context: RuntimeContext) => {
|
471
556
|
if (process.env.MODERN_TARGET === 'node') {
|
@@ -475,7 +560,7 @@ export const init = (context: RuntimeContext) => {
|
|
475
560
|
} else {
|
476
561
|
const { context } = runtimeContext;
|
477
562
|
const data = context.getInitData();
|
478
|
-
// If
|
563
|
+
// If the expected data is not obtained
|
479
564
|
if (!data.message) {
|
480
565
|
return {
|
481
566
|
message: 'Hello World By Client',
|
@@ -485,94 +570,20 @@ export const init = (context: RuntimeContext) => {
|
|
485
570
|
};
|
486
571
|
```
|
487
572
|
|
488
|
-
### Preloading
|
489
|
-
|
490
|
-
In conventional routing, Modern.js automatically splits routes into chunks based on the route. When a user visits a specific route, the corresponding chunk will be loaded automatically, effectively reducing the loading time of the initial screen.
|
491
|
-
|
492
|
-
However, this also brings a problem: if the chunk corresponding to the route has not finished loading when the user visits the route, a white screen will appear.
|
493
|
-
|
494
|
-
In this case, you can define a `Loading` component to display a custom `Loading` component before the static assets are loaded.
|
495
|
-
|
496
|
-
To further improve the user experience and reduce loading time, Modern.js supports defining the `prefetch` attribute on the Link component to preload static assets and data.
|
497
|
-
|
498
|
-
```tsx
|
499
|
-
<Link prefetch="intent" to="page">
|
500
|
-
```
|
501
|
-
|
502
|
-
:::info
|
503
|
-
|
504
|
-
- This feature is currently only supported in Webpack projects and not yet supported in Rspack projects.
|
505
|
-
- Preloading data currently only preloads the data returned by the [Data Loader](/guides/basic-features/data/data-fetch) in SSR projects.
|
506
|
-
|
507
|
-
:::
|
508
|
-
|
509
|
-
The `prefetch` attribute has three optional values:
|
510
|
-
|
511
|
-
- `none`: default value, no prefetching, no additional behavior.
|
512
|
-
- `intent`: This is the value we recommend for most scenarios. When you hover over the Link, the corresponding chunk and data defined in the data loader will be loaded automatically. When you move the mouse away, the loading will be cancelled automatically. In our tests, even fast clicks can reduce loading time by about 200ms.
|
513
|
-
- `render`: The corresponding chunk and data defined in the Data Loader will be loaded when the Link component is rendered.
|
514
|
-
|
515
|
-
#### FAQ
|
516
|
-
|
517
|
-
1. What is the difference between using `render` and not splitting static assets based on the route?
|
518
|
-
|
519
|
-
- By using `render`, you can specify which routes to load during the initial screen, and you can control the rendering so that only when the `Link` component enters the visible area, the `Link` component will be rendered.
|
520
|
-
- By using `render`, static assets will only be loaded when the system is idle, and will not compete with the static assets of the initial screen for network assets.
|
521
|
-
- In the SSR scenario, data will also be pre-fetched.
|
522
|
-
|
523
|
-
import Motivation from '@site-docs-en/components/convention-routing-motivation';
|
524
|
-
|
525
573
|
<Motivation />
|
526
574
|
|
527
|
-
|
575
|
+
## FAQ
|
528
576
|
|
529
|
-
|
577
|
+
1. Why there is `@modern-js/runtime/router` to re-export React Router API
|
530
578
|
|
531
|
-
|
579
|
+
Notice that all the code examples in the documentation use API exported from the `@modern-js/runtime/router` package instead of directly using the API exported from the React Router package. So, what is the difference?
|
532
580
|
|
533
|
-
|
581
|
+
The API exported from `@modern-js/runtime/router` is entirely consistent with the API from the React Router package. If you encounter issues while using an API, check the React Router documentation and issues first.
|
534
582
|
|
535
|
-
|
536
|
-
import { BrowserRouter, Route, Routes } from '@modern-js/runtime/router';
|
537
|
-
|
538
|
-
export default () => {
|
539
|
-
return (
|
540
|
-
<BrowserRouter>
|
541
|
-
<Routes>
|
542
|
-
<Route index element={<div>index</div>} />
|
543
|
-
<Route path="about" element={<div>about</div>} />
|
544
|
-
</Routes>
|
545
|
-
</BrowserRouter>
|
546
|
-
);
|
547
|
-
};
|
548
|
-
```
|
583
|
+
Additionally, when using conventional routing, make sure to use the API from `@modern-js/runtime/router` instead of directly using the React Router API. Modern.js internally installs React Router, and using the React Router API directly in your application may result in two versions of React Router being present, causing unexpected behavior.
|
549
584
|
|
550
585
|
:::note
|
551
|
-
|
586
|
+
If you must directly use the React Router package's API (e.g., route behavior wrapped in a unified npm package), you can set [`source.alias`](/configure/app/source/alias) to point `react-router` and `react-router-dom` to the project's dependencies, avoiding the issue of two versions of React Router.
|
552
587
|
:::
|
553
588
|
|
554
|
-
|
555
|
-
|
556
|
-
By default, Modern.js will enable the built-in routing scheme, which is React Router.
|
557
|
-
|
558
|
-
```js
|
559
|
-
export default defineConfig({
|
560
|
-
runtime: {
|
561
|
-
router: true,
|
562
|
-
},
|
563
|
-
});
|
564
|
-
```
|
565
|
-
|
566
|
-
As mentioned above, when the [`runtime.router`](/configure/app/runtime/router) configuration is enabled, Modern.js will export the API of React Router from the `@modern-js/runtime/router` namespace for developers to use, ensuring that developers and Modern.js are using the same code, and automatically wrapping the `Provider` component according to the router configuration. In addition, in this case, the code of React Router will be packed into the JS output.
|
567
|
-
|
568
|
-
If the project already has its own routing plan or does not need to use client-side routing, this feature can be disabled.
|
569
|
-
|
570
|
-
```js
|
571
|
-
export default defineConfig({
|
572
|
-
runtime: {
|
573
|
-
router: false,
|
574
|
-
},
|
575
|
-
});
|
576
|
-
```
|
577
|
-
|
578
|
-
As mentioned above, if the [`runtime.router`](/configure/app/runtime/router) configuration is disabled and `react-router-dom` is used directly for project routing management, the `Provider` needs to be wrapped according to the React Router documentation.
|
589
|
+
import Motivation from '@site-docs-en/components/convention-routing-motivation';
|