@modern-js/main-doc 2.12.0 → 2.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/docs/en/apis/app/commands.mdx +1 -1
  3. package/docs/en/apis/app/hooks/api/framework/lambda.mdx +2 -2
  4. package/docs/en/apis/app/hooks/api/functions/api.mdx +3 -3
  5. package/docs/en/apis/app/hooks/api/functions/app.mdx +1 -1
  6. package/docs/en/apis/app/hooks/api/test.mdx +2 -1
  7. package/docs/en/apis/app/hooks/config/mock.mdx +1 -1
  8. package/docs/en/apis/app/hooks/config/upload.mdx +1 -1
  9. package/docs/en/apis/app/hooks/server/test.mdx +1 -1
  10. package/docs/en/apis/app/hooks/src/app.mdx +1 -1
  11. package/docs/en/apis/app/hooks/src/pages.mdx +1 -1
  12. package/docs/en/apis/app/runtime/app/define-config.mdx +1 -1
  13. package/docs/en/apis/app/runtime/core/bootstrap.mdx +2 -2
  14. package/docs/en/apis/app/runtime/core/use-loader.mdx +6 -2
  15. package/docs/en/apis/app/runtime/model/auto-actions.mdx +6 -6
  16. package/docs/en/apis/app/runtime/model/connect.mdx +2 -1
  17. package/docs/en/apis/app/runtime/model/create-app.mdx +1 -1
  18. package/docs/en/apis/app/runtime/model/handle-effect.mdx +3 -3
  19. package/docs/en/apis/app/runtime/model/model_.mdx +2 -2
  20. package/docs/en/apis/app/runtime/model/use-model.mdx +2 -2
  21. package/docs/en/apis/app/runtime/model/use-static-model.mdx +2 -2
  22. package/docs/en/apis/app/runtime/model/use-store.mdx +1 -1
  23. package/docs/en/apis/app/runtime/router/router.mdx +1 -0
  24. package/docs/en/apis/app/runtime/ssr/pre-render.mdx +2 -2
  25. package/docs/en/apis/app/runtime/testing/render.mdx +1 -1
  26. package/docs/en/components/enable-bff.mdx +2 -2
  27. package/docs/en/configure/app/html/script-loading.mdx +13 -0
  28. package/docs/en/configure/app/output/ssg.mdx +1 -1
  29. package/docs/en/configure/app/plugins.mdx +3 -3
  30. package/docs/en/configure/app/source/disable-entry-dirs.mdx +1 -1
  31. package/docs/en/configure/app/tools/swc.mdx +1 -1
  32. package/docs/en/configure/app/usage.mdx +65 -23
  33. package/docs/en/guides/advanced-features/bff/function.mdx +3 -3
  34. package/docs/en/guides/advanced-features/code-split.mdx +2 -2
  35. package/docs/en/guides/advanced-features/eslint.mdx +1 -1
  36. package/docs/en/guides/advanced-features/ssg.mdx +2 -2
  37. package/docs/en/guides/advanced-features/ssr.mdx +45 -8
  38. package/docs/en/guides/basic-features/alias.mdx +1 -1
  39. package/docs/en/guides/basic-features/env-vars.mdx +5 -5
  40. package/docs/en/guides/basic-features/html.mdx +0 -4
  41. package/docs/en/guides/basic-features/routes.mdx +48 -28
  42. package/docs/en/guides/concept/entries.mdx +3 -3
  43. package/docs/en/guides/get-started/introduction.mdx +21 -1
  44. package/docs/en/guides/get-started/quick-start.mdx +6 -23
  45. package/docs/en/guides/get-started/upgrade.mdx +7 -7
  46. package/docs/en/guides/topic-detail/framework-plugin/hook.mdx +1 -1
  47. package/docs/en/guides/topic-detail/generator/codesmith/api/json.mdx +3 -3
  48. package/docs/en/guides/topic-detail/generator/config/app.mdx +1 -1
  49. package/docs/en/guides/topic-detail/generator/config/monorepo.mdx +1 -1
  50. package/docs/en/guides/topic-detail/generator/plugin/api/file/addHelper.mdx +1 -1
  51. package/docs/en/guides/topic-detail/model/manage-effects.mdx +2 -1
  52. package/docs/en/guides/topic-detail/model/model-communicate.mdx +1 -1
  53. package/docs/en/tutorials/foundations/introduction.mdx +0 -2
  54. package/docs/zh/apis/app/hooks/src/pages.mdx +1 -1
  55. package/docs/zh/apis/app/runtime/core/use-loader.mdx +4 -0
  56. package/docs/zh/apis/app/runtime/model/handle-effect.mdx +2 -1
  57. package/docs/zh/apis/app/runtime/model/model_.mdx +4 -2
  58. package/docs/zh/blog/updates/2022-0708-updates.md +1 -2
  59. package/docs/zh/components/enable-bff.mdx +2 -2
  60. package/docs/zh/configure/app/html/script-loading.mdx +13 -0
  61. package/docs/zh/configure/app/source/disable-entry-dirs.mdx +2 -2
  62. package/docs/zh/configure/app/usage.mdx +66 -24
  63. package/docs/zh/guides/advanced-features/ssr.mdx +74 -36
  64. package/docs/zh/guides/basic-features/html.mdx +0 -4
  65. package/docs/zh/guides/basic-features/routes.mdx +64 -24
  66. package/docs/zh/guides/concept/entries.mdx +4 -4
  67. package/docs/zh/guides/get-started/introduction.mdx +21 -1
  68. package/docs/zh/guides/get-started/upgrade.mdx +3 -3
  69. package/docs/zh/guides/topic-detail/changesets/release.mdx +2 -2
  70. package/package.json +5 -5
  71. package/src/components/SolutionCards/index.module.scss +62 -0
  72. package/src/components/SolutionCards/index.tsx +26 -0
@@ -2,9 +2,10 @@
2
2
  sidebar_position: 1
3
3
  title: model
4
4
  ---
5
+
5
6
  # model
6
7
 
7
- import ReduckTip from "@site-docs/components/reduck-tip"
8
+ import ReduckTip from '@site-docs/components/reduck-tip';
8
9
 
9
10
  <ReduckTip />
10
11
 
@@ -61,7 +62,8 @@ const fooModel = model('foo').define({
61
62
  - context: Context,Reduck 上下文对象,可以获取底层的 `store` 对象。`store` 除支持 Redux Store 的所有 [API](https://redux.js.org/api/store) 以外,还挂载了用于消费 Model 的 `use` 的方法,和用于卸载 Model 的 `unmount` 方法。
62
63
  - utils: Utils,定义 Model 时,常用的工具函数:`use`、`onMount`。`use` 作用同 `store` 对象上的 `use`,`onMount` 是 Model 挂载后的钩子函数。
63
64
 
64
- {/* TODO: @anchao 调整类型 */}
65
+ {/* TODO: @anchao 调整类型 */}
66
+
65
67
  ```ts
66
68
  interface Utils {
67
69
  use: UseModel;
@@ -39,8 +39,7 @@ npx @modern-js/upgrade
39
39
 
40
40
  新的模块工程项目,不仅支持对产物做 bundless 构建,也支持 bundle 构建。通过配置 `buildConfig` 下的 [`buildType`](https://modernjs.dev/v1/docs/apis/module/config/output/build-config/build-type) ,即可进行 bundle 构建:
41
41
 
42
- ```ts
43
- // modern.config.ts
42
+ ```ts title="modern.config.ts"
44
43
  import { defineConfig } from '@modern-js/module-tools';
45
44
 
46
45
  export default defineConfig({
@@ -6,7 +6,7 @@ import { Tabs, Tab as TabItem } from "@theme";
6
6
  <Tabs>
7
7
  <TabItem value="express" label="Express.js" default>
8
8
 
9
- ```ts title="edenx.config.ts"
9
+ ```ts title="modern.config.ts"
10
10
  import expressPlugin from '@modern-js/plugin-express';
11
11
  import bffPlugin from '@modern-js/plugin-bff';
12
12
 
@@ -18,7 +18,7 @@ export default defineConfig({
18
18
  </TabItem>
19
19
  <TabItem value="koa" label="Koa.js">
20
20
 
21
- ```ts title="edenx.config.ts"
21
+ ```ts title="modern.config.ts"
22
22
  import koaPlugin from '@modern-js/plugin-koa';
23
23
  import bffPlugin from '@modern-js/plugin-bff';
24
24
 
@@ -0,0 +1,13 @@
1
+ ---
2
+ sidebar_label: scriptLoading
3
+ ---
4
+
5
+ # html.scriptLoading
6
+
7
+ :::tip
8
+ 该配置由 Modern.js Builder 提供,更多信息可参考 [html.scriptLoading](https://modernjs.dev/builder/api/config-html.html#htmlscriptloading)。
9
+ :::
10
+
11
+ import Main from '@modern-js/builder-doc/docs/zh/config/html/scriptLoading.md';
12
+
13
+ <Main />
@@ -7,14 +7,14 @@ sidebar_label: disableEntryDirs
7
7
  - **类型:** `string[]`
8
8
  - **默认值:** `[]`
9
9
 
10
- 默认会根据 `src` 目录识别应用入口,可通过该选项禁止某些目录被识别为应用入口。
10
+ Modern.js 默认会根据 `src` 目录识别应用入口,你可以通过该选项禁止某些目录被识别为应用入口。
11
11
 
12
12
  例如,当配置与目录结构如下时:
13
13
 
14
14
  ```ts title="modern.config.ts"
15
15
  export default defineConfig({
16
16
  source: {
17
- disableEntryDirs: './src/one',
17
+ disableEntryDirs: ['./src/one'],
18
18
  },
19
19
  });
20
20
  ```
@@ -19,17 +19,33 @@ Modern.js 不支持同时在 package.json 中和 modern.config.ts 中配置同
19
19
 
20
20
  ## 在配置文件中配置
21
21
 
22
- Modern.js 的配置文件定义在项目的根目录下,支持 `.js`, `.ts` 和 `.mjs` 格式:
22
+ Modern.js 的配置文件定义在项目的根目录下,支持 `.ts`, `.js` 和 `.mjs` 格式:
23
23
 
24
- - `modern.config.js`
25
24
  - `modern.config.ts`
25
+ - `modern.config.js`
26
26
  - `modern.config.mjs`
27
27
 
28
- ### modern.config.js
28
+ ### modern.config.ts(推荐)
29
+
30
+ 我们推荐使用 .ts 格式的配置文件,它提供了友好的 TypeScript 类型提示,从而帮助你避免配置中的错误。
31
+
32
+ 从 `@modern-js/app-tools` 中导入 `defineConfig` 工具函数, 它会帮助你进行配置的类型推导和类型补全:
33
+
34
+ ```ts title="modern.config.ts"
35
+ import { defineConfig } from '@modern-js/app-tools';
36
+
37
+ export default defineConfig({
38
+ source: {
39
+ alias: {
40
+ '@common': './src/common',
41
+ },
42
+ },
43
+ });
44
+ ```
29
45
 
30
- `modern.config.js` 中可以使用 JavaScript 语法,因此比 `package.json` 更加灵活。
46
+ ### modern.config.js
31
47
 
32
- 比如,你可以在 `modern.config.js` 中定义函数类型的配置选项:
48
+ 如果你在开发一个非 TypeScript 项目,可以使用 .js 格式的配置文件:
33
49
 
34
50
  ```js title="modern.config.js"
35
51
  export default {
@@ -51,24 +67,6 @@ export default {
51
67
  };
52
68
  ```
53
69
 
54
- ### modern.config.ts(推荐)
55
-
56
- 我们推荐使用 .ts 格式的配置文件,它提供了友好的 TypeScript 类型提示,从而帮助你避免配置中的错误。
57
-
58
- 从 `@modern-js/app-tools` 中导入 `defineConfig` 工具函数, 它会帮助你进行配置的类型推导和类型补全:
59
-
60
- ```ts title="modern.config.ts"
61
- import { defineConfig } from '@modern-js/app-tools';
62
-
63
- export default defineConfig({
64
- source: {
65
- alias: {
66
- '@common': './src/common',
67
- },
68
- },
69
- });
70
- ```
71
-
72
70
  ### 导出配置函数
73
71
 
74
72
  Modern.js 支持在配置文件中导出一个函数,你可以在函数中动态计算配置,并返回给 Modern.js。
@@ -134,7 +132,7 @@ $ modern build -c modern.prod.config.js
134
132
 
135
133
  ## 在 package.json 中配置(不推荐)
136
134
 
137
- 除了配置文件外,也可以在 `package.json` 中的 `modernConfig` 字段下设置配置选项,如:
135
+ 除了配置文件外,你也可以在 `package.json` 中的 `modernConfig` 字段下设置配置项,如:
138
136
 
139
137
  ```json title="package.json"
140
138
  {
@@ -200,3 +198,47 @@ modern.config.local.ts
200
198
  modern.config.local.js
201
199
  modern.config.local.mjs
202
200
  ```
201
+
202
+ ## 合并多份配置
203
+
204
+ 在某些情况下,你可能需要将多份配置合并为一份配置,此时你可以使用 `mergeConfig` 工具函数来合并多个配置。
205
+
206
+ `mergeConfig` 函数接受一个数组作为参数,数组中的每一项都是一个配置对象,`mergeConfig` 会将数组中的每一项配置对象进行深层合并,自动将多个函数项合并为数组,最终返回一个合并后的配置对象。
207
+
208
+ ### 示例
209
+
210
+ ```ts title="modern.config.ts"
211
+ import { mergeConfig } from '@modern-js/app-tools';
212
+
213
+ const config1 = {
214
+ dev: {
215
+ port: 3000,
216
+ },
217
+ tools: {
218
+ postcss: () => console.log('config1');
219
+ },
220
+ };
221
+ const config2 = {
222
+ dev: {
223
+ port: 3001,
224
+ },
225
+ tools: {
226
+ postcss: () => console.log('config2');
227
+ },
228
+ };
229
+
230
+ const mergedConfig = mergeConfig([config1, config2]);
231
+ ```
232
+
233
+ 在以上示例中,合并后的配置对象为:
234
+
235
+ ```ts
236
+ const mergedConfig = {
237
+ dev: {
238
+ port: 3001,
239
+ },
240
+ tools: {
241
+ postcss: [() => console.log('config1'), () => console.log('config2')],
242
+ },
243
+ };
244
+ ```
@@ -2,6 +2,7 @@
2
2
  title: 服务端渲染(SSR)
3
3
  sidebar_position: 3
4
4
  ---
5
+
5
6
  # 服务端渲染(SSR)
6
7
 
7
8
  在 Modern.js 中,SSR 也是开箱即用的。开发者无需为 SSR 编写复杂的服务端逻辑,也无需关心 SSR 的运维,或是创建单独的服务。Modern.js 拥有完备的 SSR 降级策略,保证页面能够安全运行。
@@ -12,10 +13,10 @@ sidebar_position: 3
12
13
  import { defineConfig } from '@modern-js/app-tools';
13
14
 
14
15
  export default defineConfig({
15
- "server": {
16
- "ssr": true,
16
+ server: {
17
+ ssr: true,
17
18
  },
18
- })
19
+ });
19
20
  ```
20
21
 
21
22
  ## SSR 时的数据获取
@@ -33,7 +34,7 @@ export default () => {
33
34
  在组件中可以通过 Hooks API 的方式获取 `loader` 函数返回的数据:
34
35
 
35
36
  ```tsx
36
- import { useLoaderData } from '@modern-js/runtime/router'
37
+ import { useLoaderData } from '@modern-js/runtime/router';
37
38
  export default () => {
38
39
  const data = useLoaderData();
39
40
  return <div>{data.message}</div>;
@@ -45,14 +46,13 @@ Modern.js 打破传统的 SSR 开发模式,提供了用户无感的 SSR 开发
45
46
  不过,开发者仍然需要关注数据的兜底处理,例如 `null` 值或不符合预期的数据返回。避免在 SSR 时产生 React 渲染错误或是返回凌乱的渲染结果。
46
47
 
47
48
  :::info 补充信息
49
+
48
50
  1. 当以客户端路由的方式请求页面时,Modern.js 会发送一个 HTTP 请求,服务端接收到请求后执行页面对应的 Data Loader 函数,然后将执行结果作为请求的响应返回浏览器。
49
51
 
50
52
  2. 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data-fetch)。
51
53
 
52
54
  :::
53
55
 
54
-
55
-
56
56
  ## 保持渲染一致
57
57
 
58
58
  有些业务中,通常需要根据当前的运行容器环境特征做不同的 UI 展示,例如 [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) 信息。如果处理不够仔细,此时很有可能出现不符合预期的渲染结果。
@@ -215,16 +215,23 @@ const App = () => {
215
215
  export default App;
216
216
  ```
217
217
 
218
- 在组件文件中引入 Node API,通常情况下是因为使用了 Data Loader,例如:
218
+ 在组件文件中引入 Node API,通常情况下是因为使用了 `useLoader`,例如:
219
219
 
220
220
  ```ts
221
221
  import fse from 'fs-extra';
222
- export const loader = () => {
223
- const file = fse.readFileSync('./myfile');
224
- return {
225
- ...
226
- };
222
+ import { useLoader } from '@modern-js/runtime'
223
+
224
+ const App = () => {
225
+ const { data } = useLoader(async () => {
226
+ const file = fse.readFileSync('./myfile');
227
+ return {
228
+ ...
229
+ };
230
+ })
231
+
232
+ return <div>Hello World</div>;
227
233
  };
234
+ export default App;
228
235
  ```
229
236
 
230
237
  ### 环境变量区分
@@ -239,16 +246,32 @@ if (process.env.MODERN_TARGET === 'browser') {
239
246
  }
240
247
  ```
241
248
 
249
+ 开发环境打包后,SSR 产物和 CSR 产物会被编译成以下内容。因此 SSR 环境中不会再因为 Web API 报错:
250
+
251
+ ```ts
252
+ // SSR 产物
253
+ if (false) {
254
+ }
255
+
256
+ // CSR 产物
257
+ if (true) {
258
+ document.addEventListener('load', () => {
259
+ console.log('document load');
260
+ });
261
+ }
262
+ ```
263
+
242
264
  :::note
243
265
  更多内容可以查看[环境变量](/guides/basic-features/env-vars)。
244
-
245
266
  :::
246
267
 
247
268
  ### 文件后缀区分
248
269
 
249
- 但例如第二种情况,Treeshaking 的方式并不能保证代码被完全分离。Modern.js 也支持通过 `.node.` 后缀的文件来区分 SSR Bundle 和 CSR Bundle 产物的打包文件。
270
+ 但例如第二种情况,在代码中引入了 `fs-extra`,它内部有使用了 Node API 的副作用,如果直接引用到组件中,会造成 CSR 加载报错。
250
271
 
251
- 例如在代码中引入了 `fs-extra`,这时候直接引用到组件中,会造成 CSR 加载报错。可以创建同名的 `.ts``.node.ts` 文件做一层代理:
272
+ 环境变量的方式并不能在这种情况下生效,Modern.js 也支持通过 `.node.` 后缀的文件来区分 SSR Bundle CSR Bundle 产物的打包文件。
273
+
274
+ 可以创建同名的 `.ts` 和 `.node.ts` 文件做一层代理:
252
275
 
253
276
  ```ts title="compat.ts"
254
277
  export const readFileSync: any = () => {};
@@ -273,7 +296,27 @@ export const loader = () => {
273
296
 
274
297
  ### 独立文件
275
298
 
276
- 上述两种方式,都会为开发者带来一些心智负担。Modern.js 基于[嵌套路由](/guides/basic-features/routes)开发设计了[更简单的方案](/guides/basic-features/data-fetch)来分离 CSR 和 SSR 的代码。
299
+ 上述两种方式,都会为开发者带来一些心智负担。在真实的业务中,我们发现大多数的 Node / Web 代码混用都出现在数据请求中。
300
+
301
+ 因此,Modern.js 基于[嵌套路由](/guides/basic-features/routes)开发设计了[更简单的方案](/guides/basic-features/data-fetch)来分离 CSR 和 SSR 的代码。
302
+
303
+ 我们可以通过独立文件来分离**数据请求**与**组件代码**。在 `routes/page.tsx` 中编写组件逻辑,在 `routes/page.loader.ts` 中编写数据请求逻辑。
304
+
305
+ ```ts title="routes/page.tsx"
306
+ export default Page = () => {
307
+ return <div>Hello World<div>
308
+ }
309
+ ```
310
+
311
+ ```ts title="routes/page.loader.tsx"
312
+ import fse from 'fs-extra';
313
+ export default () => {
314
+ const file = fse.readFileSync('./myfile');
315
+ return {
316
+ ...
317
+ };
318
+ }
319
+ ```
277
320
 
278
321
  ## 接口请求
279
322
 
@@ -291,12 +334,12 @@ Modern.js 支持了 React 18 的流式渲染,可以通过如下配置启用:
291
334
  import { defineConfig } from '@modern-js/app-tools';
292
335
 
293
336
  export default defineConfig({
294
- "server": {
295
- "ssr": {
296
- "mode": "stream",
337
+ server: {
338
+ ssr: {
339
+ mode: 'stream',
297
340
  },
298
341
  },
299
- })
342
+ });
300
343
  ```
301
344
 
302
345
  Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
@@ -305,10 +348,9 @@ Modern.js 的流式渲染基于 React Router 实现,主要涉及 API 有:
305
348
  - [`Await`](https://reactrouter.com/en/main/components/await):用于渲染 Data Loader 返回的异步数据。
306
349
  - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value):用于从最近的父级 `Await` 组件中获取数据。
307
350
 
308
-
309
351
  ### 异步获取数据
310
352
 
311
- ```ts title='page.loader.ts'
353
+ ```ts title="page.loader.ts"
312
354
  import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
313
355
 
314
356
  interface User {
@@ -334,16 +376,14 @@ export default ({ params }: LoaderFunctionArgs) => {
334
376
 
335
377
  return defer({ data: user });
336
378
  };
337
-
338
379
  ```
339
380
 
340
381
  `user` 是一个 Promise 类型的对象,表示需要异步获取的数据,通过 `defer` 处理需要异步获取的 `user`。注意,`defer` 必须接收一个对象类型的参数,
341
- 因此, 传入 `defer` 的参数为 `{data: user}`。
382
+ 因此, 传入 `defer` 的参数为:`{ data: user }`
342
383
 
343
384
  `defer` 还可以同时接收异步数据和同步数据。例如:
344
385
 
345
- ```ts title='page.loader.ts'
346
-
386
+ ```ts title="page.loader.ts"
347
387
  // 省略部分代码
348
388
 
349
389
  export default ({ params }: LoaderFunctionArgs) => {
@@ -366,20 +406,18 @@ export default ({ params }: LoaderFunctionArgs) => {
366
406
 
367
407
  return defer({
368
408
  data: user,
369
- other: await otherData
409
+ other: await otherData,
370
410
  });
371
411
  };
372
-
373
412
  ```
374
413
 
375
414
  `otherData` 前加了 `await`,所以是同步获取的数据,它可以和异步获取的数据 `user` 同时传入 `defer`。
376
415
 
377
-
378
416
  ### 渲染异步数据
379
417
 
380
418
  通过 `Await` 组件,可以获取到 Data Loader 中异步返回的数据,然后进行渲染。例如:
381
419
 
382
- ```tsx title='page.tsx'
420
+ ```tsx title="page.tsx"
383
421
  import { Await, useLoaderData } from '@modern-js/runtime/router';
384
422
  import { Suspense } from 'react';
385
423
  import type { Data } from './page.loader';
@@ -392,7 +430,7 @@ const Page = () => {
392
430
  User info:
393
431
  <Suspense fallback={<div id="loading">loading user data ...</div>}>
394
432
  <Await resolve={data.data}>
395
- {(user) => {
433
+ {user => {
396
434
  return (
397
435
  <div id="data">
398
436
  name: {user.name}, age: {user.age}
@@ -430,11 +468,11 @@ const UserInfo = () => {
430
468
  const user = useAsyncValue();
431
469
 
432
470
  return (
433
- <div>
471
+ <div>
434
472
  name: {user.name}, age: {user.age}
435
473
  </div>
436
- )
437
- }
474
+ );
475
+ };
438
476
 
439
477
  const Page = () => {
440
478
  const data = useLoaderData() as Data;
@@ -459,7 +497,7 @@ export default Page;
459
497
  `Await` 组件的 `errorElement` 属性,可以用来处理当 Data Loader 执行时,或者子组件渲染时抛出的错误。
460
498
  例如,我们故意在 Data Loader 函数中抛出错误:
461
499
 
462
- ```ts title='page.loader.ts'
500
+ ```ts title="page.loader.ts"
463
501
  import { defer } from '@modern-js/runtime/router';
464
502
 
465
503
  export default () => {
@@ -475,7 +513,7 @@ export default () => {
475
513
 
476
514
  然后通过 `useAsyncError` 获取错误,并将用于渲染错误信息的组件赋值给 `Await` 组件的 `errorElement` 属性:
477
515
 
478
- ```tsx title='page.ts'
516
+ ```tsx title="page.ts"
479
517
  import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
480
518
  import { Suspense } from 'react';
481
519
 
@@ -174,10 +174,6 @@ Modern.js 也支持 HTML 语法。默认情况下,Modern.js 的应用工程中
174
174
  <%= meta %>
175
175
  <title><%= title %></title>
176
176
  <%= topTemplate %>
177
-
178
- <script>
179
- window.__assetPrefix__ = '<%= assetPrefix %>';
180
- </script>
181
177
  <%= headTemplate %>
182
178
  {/* webpack inject css */}
183
179
  </head>
@@ -2,6 +2,7 @@
2
2
  title: 路由
3
3
  sidebar_position: 1
4
4
  ---
5
+
5
6
  # 路由
6
7
 
7
8
  Modern.js 的路由基于 [React Router 6](https://reactrouter.com/en/main),并提供了多种类型的路由模式。根据不同 [入口](/guides/concept/entries) 类型,将路由分为三种模式,分别是**约定式路由**,**自控式路由**和**其他路由方案**。
@@ -77,8 +78,8 @@ Modern.js 支持了业界流行的约定式路由模式:**嵌套路由**,使
77
78
  ```tsx
78
79
  <Layout>
79
80
  <UserLayout>
80
- <UserPage>
81
- <UserLayout>
81
+ <UserPage />
82
+ </UserLayout>
82
83
  </Layout>
83
84
  ```
84
85
 
@@ -138,8 +139,8 @@ export default () => {
138
139
  ```tsx
139
140
  <Layout>
140
141
  <UserLayout>
141
- <UserPage>
142
- <UserLayout>
142
+ <UserPage />
143
+ </UserLayout>
143
144
  </Layout>
144
145
  ```
145
146
 
@@ -177,6 +178,7 @@ export default () => {
177
178
  :::
178
179
 
179
180
  例如以下目录结构:
181
+
180
182
  ```
181
183
  └── routes
182
184
  ├── $.tsx
@@ -186,11 +188,12 @@ export default () => {
186
188
  ```
187
189
 
188
190
  当访问任何匹配不到的路径时,都会渲染 `routes/$.tsx` 组件,同样,`$.tsx` 中可以使用 [useParams](/apis/app/runtime/router/router#useparams) 捕获 url 的剩余部分。
191
+
189
192
  ```ts title="$.tsx"
190
193
  import { useParams } from '@modern-js/runtime/router';
191
194
  // 当 path 是 `/aaa/bbb` 时
192
195
  const params = useParams();
193
- params['*'] // => 'aaa/bbb'
196
+ params['*']; // => 'aaa/bbb'
194
197
  ```
195
198
 
196
199
  `$.tsx` 可以加入到 `routes` 目录下的任意目录中,一个常见的使用示例是添加 `routes/$.tsx` 文件去定制任意层级的 404 页面。
@@ -260,8 +263,8 @@ Modern.js 会生成 `/login` 和 `/sign` 两条路由,`__auth/layout.tsx` 组
260
263
 
261
264
  ```tsx title="当路由为 / 时"
262
265
  <Layout>
263
- <Suspense fallback={<Loading/>}>
264
- <Page><Page>
266
+ <Suspense fallback={<Loading />}>
267
+ <Page />
265
268
  </Suspense>
266
269
  </Layout>
267
270
  ```
@@ -297,15 +300,15 @@ Modern.js 建议必须有根 layout 和根 loading。
297
300
  可以通过创建 [`data loader`](/guides/basic-features/data-fetch) 文件做路由的重定向,如有文件 `routes/user/page.tsx`,想对这个文件对应的路由做重定向,可以创建 `routes/user/page.loader.ts` 文件:
298
301
 
299
302
  ```ts title="routes/user/page.loader.ts"
300
- import { redirect } from '@modern-js/runtime/router'
303
+ import { redirect } from '@modern-js/runtime/router';
301
304
 
302
305
  export default () => {
303
306
  const user = await getUser();
304
- if(!user){
307
+ if (!user) {
305
308
  return redirect('/login');
306
309
  }
307
310
  return null;
308
- }
311
+ };
309
312
  ```
310
313
 
311
314
  ### 错误处理
@@ -338,7 +341,7 @@ export default ErrorBoundary;
338
341
 
339
342
  在每个根 `Layout` 组件中(`routes/layout.ts`),可以动态地定义应用运行时配置:
340
343
 
341
- ```ts title="src/routes/layout.tsx"
344
+ ```tsx title="src/routes/layout.tsx"
342
345
  // 定义运行时配置
343
346
  import type { AppConfig } from '@modern-js/runtime';
344
347
 
@@ -348,13 +351,13 @@ export const config = (): AppConfig => {
348
351
  createRoutes() {
349
352
  return [
350
353
  {
351
- path: 'edenx',
352
- element: <div>edenx</div>,
354
+ path: 'modern',
355
+ element: <div>modern</div>,
353
356
  },
354
357
  ];
355
358
  },
356
359
  },
357
- }
360
+ };
358
361
  };
359
362
  ```
360
363
 
@@ -378,15 +381,13 @@ export const init = (context: RuntimeContext) => {
378
381
  :::
379
382
 
380
383
  ```ts title="src/routes/layout.tsx"
381
- import {
382
- RuntimeContext,
383
- } from '@modern-js/runtime';
384
+ import { RuntimeContext } from '@modern-js/runtime';
384
385
 
385
386
  export const init = (context: RuntimeContext) => {
386
387
  return {
387
388
  message: 'Hello World',
388
- }
389
- }
389
+ };
390
+ };
390
391
  ```
391
392
 
392
393
  ```tsx title="src/routes/page.tsx"
@@ -397,7 +398,7 @@ export default () => {
397
398
  const { message } = context.getInitData();
398
399
 
399
400
  return <div>{message}</div>;
400
- }
401
+ };
401
402
  ```
402
403
 
403
404
  配合 SSR 功能时,浏览器端可以获取到 SSR 时 `init` 返回的数据,开发者可以自行判断是否要在浏览器端重新获取数据来覆盖 SSR 数据,例如:
@@ -409,20 +410,42 @@ export const init = (context: RuntimeContext) => {
409
410
  if (process.env.MODERN_TARGET === 'node') {
410
411
  return {
411
412
  message: 'Hello World By Server',
412
- }
413
+ };
413
414
  } else {
414
415
  const { context } = runtimeContext;
415
416
  const data = context.getInitData();
416
417
  // 如果没有获取到期望的数据
417
418
  if (!data.message) {
418
419
  return {
419
- message: 'Hello World By Client'
420
- }
420
+ message: 'Hello World By Client',
421
+ };
421
422
  }
422
423
  }
423
- }
424
+ };
424
425
  ```
425
426
 
427
+ ### Prefetch
428
+
429
+ 在约定式路由下, Modern.js 会根据路由,自动地对路由进行分片,当用户访问具体的路由时,会自动加载对应的分片,这样可以有效地减少首屏加载的时间。但这也带来了一个问题,当用户访问一个路由时,如果该路由对应的分片还未加载完成,就会出现白屏的情况。
430
+ 这种情况下你可以通过定义 `loading` 组件,在静态资源加载完成前,展示一个自定义的 `loading` 组件。
431
+
432
+ 为了进一步提升用户体验,减少 loading 的时间,Modern.js 支持在 Link 组件上定义 `prefetch` 属性,可以提前对静态资源和数据进行加载, `prefetch` 属性有三个可选值:
433
+
434
+ ```
435
+ <Link prefetch="intent" to="page">
436
+ ```
437
+
438
+ :::info
439
+ - 该功能目前仅在 Webpack 项目中支持,Rspack 项目暂不支持。
440
+ - 对数据的预加载目前只会预加载 SSR 项目中 [data loader](/guides/basic-features/data-fetch) 中返回的数据。
441
+
442
+ :::
443
+
444
+ - `none`, 默认值,不会做 prefetch,没有任何额外的行为。
445
+ - `intent`,这是我们推荐大多数场景下使用的值,当你把鼠标放在 Link 上时,会自动开始加载对应的分片和 data loader 中定义的数据,当鼠标移开时,会自动取消加载。在我们的测试中,即使是直接点击,也能减少大约 200ms 的加载时间。
446
+ - `render`,当 Link 组件渲染时,就会加载对应的分片和 data loader 中定义的数据。
447
+
448
+
426
449
 
427
450
  ## 自控式路由
428
451
 
@@ -469,3 +492,20 @@ export default defineConfig({
469
492
  },
470
493
  });
471
494
  ```
495
+
496
+ ### 常见问题
497
+
498
+ 1. 产物中的代码是 es2015+ 的,期望产物中是 es5 的代码
499
+
500
+ react-router^6 的目前默认产物是 es2020 的,如果需要产物中是 es5 的代码,可以配置 `source.include`,让 react-router 相关包经过 bundler 编译 :
501
+
502
+ ```
503
+ source: {
504
+ source: {
505
+ include: [/@remix-run\/router/, /react-router-dom/, /react-router/],
506
+ }
507
+ }
508
+ ```
509
+
510
+
511
+
@@ -2,7 +2,7 @@
2
2
  sidebar_position: 1
3
3
  ---
4
4
 
5
- # 入口(Entry)
5
+ # 入口
6
6
 
7
7
  通过本章节,你可以了解到 Modern.js 中的入口约定,以及如何自定义入口。
8
8
 
@@ -132,9 +132,9 @@ Modern.js 生成的文件内容如下:
132
132
  ```js
133
133
  import React from 'react';
134
134
  import ReactDOM from 'react-dom/client';
135
- import customBootstrap from '@_edenx_src/index.tsx';
136
- import App from '@_edenx_src/App';
137
- import { router, state } from '@edenx/runtime/plugins';
135
+ import customBootstrap from '@_modern_js_src/index.tsx';
136
+ import App from '@_modern_js_src/App';
137
+ import { router, state } from '@modern-js/runtime/plugins';
138
138
 
139
139
  const IS_BROWSER = typeof window !== 'undefined' && window.name !== 'nodejs';
140
140
  const MOUNT_ID = 'root';