@modern-js/main-doc 2.12.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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';