@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
@@ -1,46 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 2
|
3
|
-
title: 函数写法 & 框架写法
|
4
|
-
---
|
5
|
-
# 函数写法 & 框架写法
|
6
|
-
|
7
|
-
运行时框架支持也是 **BFF** 中重要的一环。Modern.js 支持通过插件扩展 BFF 的运行时框架,并提供了一系列内置插件,开发者可以直接使用对应框架的约定和生态。
|
8
|
-
|
9
|
-
插件中兼容了这些框架大部分的规范,每一种框架都需要提供两类扩展写法 BFF 函数的方式,分别是**函数写法**和**框架写法**。
|
10
|
-
|
11
|
-
:::note
|
12
|
-
当前 `api/` 目录结构是否为框架写法由对应的插件决定,Modern.js 并不关心。
|
13
|
-
|
14
|
-
:::
|
15
|
-
|
16
|
-
## 函数写法
|
17
|
-
|
18
|
-
当插件认为当前为函数写法时,必须支持在 `api/_app.ts` 中编写中间件,用来扩展 BFF 函数。
|
19
|
-
|
20
|
-
Modern.js 会收集 `api/_app.ts` 中的中间件,并传递给插件,由插件将中间件注入运行时,例如:
|
21
|
-
|
22
|
-
```ts
|
23
|
-
import { hook } from '@modern-js/runtime/server';
|
24
|
-
|
25
|
-
export default hook(({ addMiddleware }) => {
|
26
|
-
addMiddleware(myMiddleware);
|
27
|
-
});
|
28
|
-
```
|
29
|
-
|
30
|
-
:::note
|
31
|
-
不同插件的中间件的写法不一定相同,详情可见[运行时框架](/guides/advanced-features/bff/frameworks)。
|
32
|
-
|
33
|
-
:::
|
34
|
-
|
35
|
-
## 框架写法
|
36
|
-
|
37
|
-
框架写法是一种使用框架结构来扩展 BFF 函数的方式。和函数写法相比,框架写法虽然能够利用更多框架的结构,在复杂场景下让整个 BFF Server 更加清晰,但也相的更加复杂,需要关心更多框架层面的内容。
|
38
|
-
|
39
|
-
框架写法中,所有的 BFF 函数都需要写在 `api/lambda/` 目录下,并且无法使用钩子文件 `_app.[tj]s`。
|
40
|
-
|
41
|
-
多数情况下,函数写法就能覆盖大多数 BFF 函数的定制需求。只有当你的项目服务端逻辑比较复杂,代码需要分层,或者需要使用更多框架的元素时,才需要使用框架写法。
|
42
|
-
|
43
|
-
:::note
|
44
|
-
不同插件框架写法的目录结构不一定相同,详情可见[运行时框架](/guides/advanced-features/bff/frameworks)。
|
45
|
-
|
46
|
-
:::
|
@@ -1,152 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 8
|
3
|
-
---
|
4
|
-
|
5
|
-
# ESLint 规则集
|
6
|
-
|
7
|
-
{/* 参考 [实战教程 - 确认编程环境](../handbook/c03-ide/3.1-setting-up) 确保本地 IDE 环境正常。 */}
|
8
|
-
|
9
|
-
**Modern.js ESLint 规则集**是全量的 **ESLint** 规则集合,包含 `@modern-js` (对于 Node.js 项目的 Lint 规则)和 `@modern-js-app`(对于前端项目的 Lint 规则)。
|
10
|
-
|
11
|
-
下面以具体问题介绍更多 ESLint 用法。
|
12
|
-
|
13
|
-
## Q: 如何处理 Lint
|
14
|
-
|
15
|
-
### 实时自动修复
|
16
|
-
|
17
|
-
多数问题会被 ESLint 规则的自动修复功能或 [Prettier](https://prettier.io/) 的代码格式化功能(已被集成到 ESLint 里)自动解决,开发者不需要关心问题的细节和解决方式。
|
18
|
-
|
19
|
-
:::info
|
20
|
-
主要在 IDE 保存文件的环节执行这种自动修复,少数漏网之鱼会在提交代码环节被自动修复。
|
21
|
-
|
22
|
-
:::
|
23
|
-
|
24
|
-
### 批量自动修复
|
25
|
-
|
26
|
-
在少数情况下,比如旧项目迁移的时候,可以执行以下命令,批量修复和检查所有文件:
|
27
|
-
|
28
|
-
```bash
|
29
|
-
pnpm run lint:error
|
30
|
-
```
|
31
|
-
|
32
|
-
### 人工修复
|
33
|
-
|
34
|
-
对于无法自动修复的问题,可以在 IDE 里点击问题提示框里的规则链接,打开这条规则的文档,查看问题的解释和解决方案。
|
35
|
-
|
36
|
-
### 声明例外情况
|
37
|
-
|
38
|
-
目前阶段,有些规则并不能做到足够智能,多数情况下会有很大收益,在少数情况下也许不适用。但如果为了这些少数情况就把整个规则关掉或改掉,得不偿失。
|
39
|
-
|
40
|
-
这种情况下可以用 [eslint-disable](https://eslint.org/docs/user-guide/configuring/rules#disabling-rules) 注释,对符合**少数情况**的代码块做标注,声明这里是一个例外,应该忽略。比如:
|
41
|
-
|
42
|
-
```js
|
43
|
-
/* eslint-disable filenames/match-exported */
|
44
|
-
...
|
45
|
-
/* eslint-enable filenames/match-exported */
|
46
|
-
```
|
47
|
-
|
48
|
-
:::info
|
49
|
-
在 VS Code 编辑器里输入 eslint,会自动出现关于 "eslint-disable" 的提示框,选择提示选项生成对应注释对。
|
50
|
-
|
51
|
-
:::
|
52
|
-
|
53
|
-
【Modern.js ESLint 规则集】要求 [eslint-disable](https://eslint.org/docs/user-guide/configuring/rules#disabling-rules) 必须成对使用,必须明确表达要影响的范围,以及在这个范围内明确表达要禁用什么规则,目的是让**例外**有明确的、最小化的范围,避免 [eslint-disable](https://eslint.org/docs/user-guide/configuring/rules#disabling-rules) 被滥用,导致不属于例外的代码也被禁用了规则。
|
54
|
-
|
55
|
-
## Q: 如何自定义 ESLint 规则
|
56
|
-
|
57
|
-
### 仓库根目录下 `package.json` 里的 "eslintConfig" 字段
|
58
|
-
|
59
|
-
这个地方是整个仓库的默认 ESLint 配置,是针对纯 Node.js 代码(只能在 Node.js 里运行)设计的。
|
60
|
-
|
61
|
-
如果项目在某些规则上确实有特殊要求或不可避免的兼容问题(不是例外),可以在这里增加规则配置。该配置会优先于默认的【Modern.js ESLint 规则集】,比如:
|
62
|
-
|
63
|
-
```json
|
64
|
-
"eslintConfig": {
|
65
|
-
"extends": [
|
66
|
-
"@modern-js"
|
67
|
-
],
|
68
|
-
"rules": {
|
69
|
-
"filenames/match-exported": "off"
|
70
|
-
}
|
71
|
-
},
|
72
|
-
|
73
|
-
```
|
74
|
-
|
75
|
-
### `src/.eslintrc.js` 文件
|
76
|
-
|
77
|
-
Modern.js Framework、Modern.js Module 的源代码目录里都会默认有这个配置文件,是针对 Universal JS 代码设计的。
|
78
|
-
|
79
|
-
:::info
|
80
|
-
Universal JS 代码是既能浏览器端也能在服务器端运行的代码。
|
81
|
-
|
82
|
-
:::
|
83
|
-
|
84
|
-
如果项目在某些规则上确实有特殊要求或不可避免的兼容问题(不是例外),可以在这里增加规则配置,该配置会优先于默认的【Modern.js ESLint 规则集】,比如:
|
85
|
-
|
86
|
-
```js
|
87
|
-
// eslint-disable-next-line import/no-commonjs
|
88
|
-
module.exports = {
|
89
|
-
root: true,
|
90
|
-
extends: ['@modern-js-app'],
|
91
|
-
parserOptions: {
|
92
|
-
tsconfigRootDir: __dirname,
|
93
|
-
project: ['../tsconfig.json'],
|
94
|
-
},
|
95
|
-
rules: {
|
96
|
-
'filenames/match-exported': 'off',
|
97
|
-
},
|
98
|
-
};
|
99
|
-
```
|
100
|
-
|
101
|
-
如果有需要,还可以继续在不同的子目录里增加 `.eslintrc.js` 文件,针对这个子目录里的代码做特殊配置:
|
102
|
-
|
103
|
-
```js
|
104
|
-
module.exports = {
|
105
|
-
rules: {
|
106
|
-
'filenames/match-exported': 'off',
|
107
|
-
},
|
108
|
-
};
|
109
|
-
```
|
110
|
-
|
111
|
-
:::tip 提示
|
112
|
-
注意:没有必要使用 `extends` 字段,会自动继承父目录的配置。
|
113
|
-
|
114
|
-
:::
|
115
|
-
|
116
|
-
### package.json 里的 `eslintIgnore` 字段
|
117
|
-
|
118
|
-
把包含 `.js`、`.jsx`、`.ts`、`.tsx` 文件、但不需要做代码检查和自动修复的目录,添加到 `eslintIgnore` 里,可以优化 ESLint 检查的速度,比如:
|
119
|
-
|
120
|
-
```json
|
121
|
-
"eslintIgnore": [
|
122
|
-
"node_modules",
|
123
|
-
"dist",
|
124
|
-
"output"
|
125
|
-
],
|
126
|
-
```
|
127
|
-
|
128
|
-
## Q: 如何升级 ESLint 插件的版本
|
129
|
-
|
130
|
-
只要不是 Major 版本的变化(不符合 [Semver](https://semver.org/) 规则的 `^` 符号),就可以直接在业务项目的 `package.json` 里指定这个依赖,删除 Lock 文件(或尝试手动删除 Lock 文件中这个包名的内容),执行 `pnpm install` 重新安装依赖并且生成新的 Lock 文件。
|
131
|
-
|
132
|
-
做完这些操作之后,在业务项目的 `./node_modules` 目录里,这个插件应该只存在一份,并且升级到了你指定的版本。
|
133
|
-
|
134
|
-
:::tip 提示
|
135
|
-
- Major 版本就是主版本号。更多信息,请阅读 [Semantic Versioning](https://semver.org/#summary)。
|
136
|
-
- 所有被 Modern.js 封装的上游项目(比如 ESLint、[ESLint 插件](https://eslint.org/docs/user-guide/configuring/plugins#plugins)、[React Router](https://reactrouter.com/) 等),也都可以这样升级。
|
137
|
-
- Modern.js 也会在每次发版中尽量及时的升级这些上游依赖。
|
138
|
-
- Major 版本的升级需要由 Modern.js 来发版。
|
139
|
-
|
140
|
-
:::
|
141
|
-
|
142
|
-
## Q: WebStorm 有时候会报 ESLint 错误
|
143
|
-
|
144
|
-
由于 WebStorm 认为 ESLint 执行目录是根据 `.eslintrc` 文件来决定的。因此 `src/.eslintrc` 文件位置的放置会导致 `tsconfig.json` 文件指定的位置(项目根目录下)在 `src/` 目录下找不到。
|
145
|
-
|
146
|
-
此时需要手动配置一下:
|
147
|
-
|
148
|
-
```json
|
149
|
-
--parser-options=project:../tsconfig.json
|
150
|
-
```
|
151
|
-
|
152
|
-

|
@@ -1,116 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 5
|
3
|
-
---
|
4
|
-
|
5
|
-
# 静态站点生成
|
6
|
-
|
7
|
-
SSG(Static Site Generation)是一种基于数据与模板,在构建时渲染完整静态网页的技术解决方案。
|
8
|
-
|
9
|
-
我们首先需要执行 `pnpm run new` 启用 SSG 功能:
|
10
|
-
|
11
|
-
```bash
|
12
|
-
? 请选择你想要的操作 启用可选功能
|
13
|
-
? 请选择功能名称 启用「SSG」功能
|
14
|
-
```
|
15
|
-
|
16
|
-
执行命令后,在 `modern.config.ts` 中注册 SSG 插件:
|
17
|
-
|
18
|
-
```ts title="modern.config.ts"
|
19
|
-
import { ssgPlugin } from '@modern-js/plugin-ssg';
|
20
|
-
|
21
|
-
export default defineConfig({
|
22
|
-
output: {
|
23
|
-
ssg: true,
|
24
|
-
},
|
25
|
-
plugins: [..., ssgPlugin()],
|
26
|
-
});
|
27
|
-
```
|
28
|
-
|
29
|
-
SSG 在**约定式路由**和**自控式路由**下的使用方式不同。
|
30
|
-
|
31
|
-
### 在约定式路由中使用
|
32
|
-
|
33
|
-
**约定式路由**中, Modern.js 根据入口下的文件结构生成路由,因此框架能够收集完整的路由信息。
|
34
|
-
|
35
|
-
例如,以下是一个使用约定式路由的项目目录结构:
|
36
|
-
|
37
|
-
```
|
38
|
-
.
|
39
|
-
├── src
|
40
|
-
│ └── routes
|
41
|
-
│ ├── layout.tsx
|
42
|
-
│ ├── page.tsx
|
43
|
-
│ └── user
|
44
|
-
│ ├── layout.tsx
|
45
|
-
│ ├── page.tsx
|
46
|
-
│ └── profile
|
47
|
-
│ └── page.tsx
|
48
|
-
```
|
49
|
-
|
50
|
-
上述文件目录将会生成以下三条路由:
|
51
|
-
|
52
|
-
- `/`
|
53
|
-
- `/user`
|
54
|
-
- `/user/profile`
|
55
|
-
|
56
|
-
:::note
|
57
|
-
如果还不了解约定式路由的规则,可以先查看[路由方案](/guides/basic-features/routes)。
|
58
|
-
|
59
|
-
:::
|
60
|
-
|
61
|
-
在 `src/routes/page.tsx` 中添加组件代码:
|
62
|
-
|
63
|
-
```jsx title="src/routes/page.tsx"
|
64
|
-
export default () => {
|
65
|
-
return <div>Index Page</div>;
|
66
|
-
};
|
67
|
-
```
|
68
|
-
|
69
|
-
SSG 也是在 Node.js 环境渲染页面,因此我们可以在**开发阶段开启 SSR**,提前在暴露代码问题,验证 SSG 渲染效果:
|
70
|
-
|
71
|
-
```ts title="modern.config.ts"
|
72
|
-
export default defineConfig({
|
73
|
-
server: {
|
74
|
-
ssr: process.env.NODE_ENV === 'development',
|
75
|
-
}
|
76
|
-
}
|
77
|
-
```
|
78
|
-
|
79
|
-
在项目根路径下执行 `pnpm run dev` 命令,查看 `dist/` 目录,此时只生成一个 HTML 文件 `main/index.html`。
|
80
|
-
|
81
|
-
在项目根路径下执行 `pnpm run build` 命令,构建完成后,查看 `dist/` 目录,此时生成 `main/index.html`、`main/user/index.html` 和 `main/user/profile/index.html` 三个 HTML 文件,内容分别对应上述三条路由。
|
82
|
-
|
83
|
-
**约定式路由**中的每一条路由,都会生成一个单独的 HTML 文件。查看 `main/index.html`,可以发现包含 `Index Page` 的文本内容,这正是 SSG 的效果。
|
84
|
-
|
85
|
-
执行 `pnpm run serve` 启动项目后,访问页面,在浏览器我们工具的 Network 窗口,查看请求返回的文档,文档包含组件渲染后的完整页面内容。
|
86
|
-
|
87
|
-
### 在自控式路由中使用
|
88
|
-
|
89
|
-
**自控式路由**是通过组件代码定义路由,需要应用运行起来才能获取准确的路由信息。因此,无法开箱即用的使用 SSG 功能。此时需要用户提前告知 Modern.js 框架,哪些路由需要开启 SSG 功能。
|
90
|
-
|
91
|
-
例如有以下代码,包含多条路由,设置 `output.ssg` 为 `true` 时,默认只会渲染入口路由即 `/`:
|
92
|
-
|
93
|
-
import SelfRouteExample from '@site-docs/components/self-route-example';
|
94
|
-
|
95
|
-
<SelfRouteExample />
|
96
|
-
|
97
|
-
如果我们希望同时开启 `/about` 的 SSG 功能,可以配置 `output.ssg`,告知 Modern.js 开启指定路由的 SSG 功能。
|
98
|
-
|
99
|
-
```ts title="modern.config.ts"
|
100
|
-
export default defineConfig({
|
101
|
-
output: {
|
102
|
-
ssg: {
|
103
|
-
routes: ['/', '/about'],
|
104
|
-
},
|
105
|
-
},
|
106
|
-
});
|
107
|
-
```
|
108
|
-
|
109
|
-
执行 `pnpm run build` 与 `pnpm run serve` 后,访问 `http://localhost:8080/about`,在 Preview 视图中可以看到页面已经完成渲染。
|
110
|
-
|
111
|
-
查看构建产物文件,可以看到 `dist/` 目录中,新增了一个 `main/about/index.html` 文件。
|
112
|
-
|
113
|
-
:::info
|
114
|
-
以上仅介绍了单入口的情况,更多相关内容可以查看 [API 文档](/configure/app/output/ssg)。
|
115
|
-
|
116
|
-
:::
|
@@ -1 +0,0 @@
|
|
1
|
-
["usage", "stream", "cache"]
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# 服务端渲染
|
2
|
-
|
3
|
-
通过在服务器端将网页的 HTML 内容渲染成完整的网页(Server-Side Rendering,简称 SSR),然后将生成的网页发送到客户端,客户端只需要显示网页即可,不需要再进行额外的渲染。
|
4
|
-
|
5
|
-
它主要的优势在于
|
6
|
-
|
7
|
-
- 提高首屏加载速度:SSR 可以在服务器端生成完整的网页,客户端只需要下载网页内容即可,不需要再进行额外的渲染,从而提高了首屏加载速度。
|
8
|
-
- 提高用户体验:SSR 可以提高网页的响应速度,从而提高用户体验。
|
9
|
-
- 有利于 SEO:SSR 可以生成完整的 HTML 内容,搜索引擎可以直接索引 HTML 内容,从而提高网站的排名。
|
10
|
-
|
11
|
-
如果你有以下场景的需求,开发者可以考虑使用 SSR 来渲染你的页面:
|
12
|
-
|
13
|
-
1. 对首屏加载速度要求较高的网站,如电商网站、新闻网站等。
|
14
|
-
2. 对用户体验要求较高的网站,如社交网站、游戏网站等。
|
15
|
-
3. 对 SEO 要求较高的网站,如企业官网、博客等。
|
16
|
-
|
17
|
-
在 Modern.js 中,SSR 也是开箱即用的。开发者无需为 SSR 编写复杂的服务端逻辑,也无需关心 SSR 的运维,或是创建单独的服务。
|
18
|
-
|
19
|
-
除了开箱即用的 SSR 服务,为了保证开发者的开发体验,我们还具备:
|
20
|
-
|
21
|
-
- 完备的 SSR 降级策略,保证页面能够安全运行。
|
22
|
-
- 自动分割子路由,按需加载,减少首屏资源体积。
|
23
|
-
- 内置缓存系统,解决服务端负载高的问题。
|
@@ -1,329 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sidebar_position: 1
|
3
|
-
title: 基础使用
|
4
|
-
---
|
5
|
-
|
6
|
-
# 基础使用
|
7
|
-
|
8
|
-
启用 SSR 非常简单,只需要设置 [`server.ssr`](/configure/app/server/ssr) 为 `true` 即可:
|
9
|
-
|
10
|
-
```ts title="modern.config.ts"
|
11
|
-
import { defineConfig } from '@modern-js/app-tools';
|
12
|
-
|
13
|
-
export default defineConfig({
|
14
|
-
server: {
|
15
|
-
ssr: true,
|
16
|
-
},
|
17
|
-
});
|
18
|
-
```
|
19
|
-
|
20
|
-
## SSR 时的数据获取
|
21
|
-
|
22
|
-
Modern.js 中提供了 Data Loader,方便开发者在 SSR、CSR 下同构地获取数据。每个路由模块,如 `layout.tsx` 和 `page.tsx` 都可以定义自己的 Data Loader:
|
23
|
-
|
24
|
-
```ts title="src/routes/page.data.ts"
|
25
|
-
export const loader = () => {
|
26
|
-
return {
|
27
|
-
message: 'Hello World',
|
28
|
-
};
|
29
|
-
};
|
30
|
-
```
|
31
|
-
|
32
|
-
在组件中可以通过 Hooks API 的方式获取 `loader` 函数返回的数据:
|
33
|
-
|
34
|
-
```tsx
|
35
|
-
import { useLoaderData } from '@modern-js/runtime/router';
|
36
|
-
export default () => {
|
37
|
-
const data = useLoaderData();
|
38
|
-
return <div>{data.message}</div>;
|
39
|
-
};
|
40
|
-
```
|
41
|
-
|
42
|
-
Modern.js 打破传统的 SSR 开发模式,提供了用户无感的 SSR 开发体验。并且提供了优雅的降级处理,一旦 SSR 请求失败,会自动降级在浏览器端重新发起请求。
|
43
|
-
|
44
|
-
不过,开发者仍然需要关注数据的兜底处理,例如 `null` 值或不符合预期的数据返回。避免在 SSR 时产生 React 渲染错误或是返回凌乱的渲染结果。
|
45
|
-
|
46
|
-
:::info 补充信息
|
47
|
-
|
48
|
-
1. 当以客户端路由的方式请求页面时,Modern.js 会发送一个 HTTP 请求,服务端接收到请求后执行页面对应的 Data Loader 函数,然后将执行结果作为请求的响应返回浏览器。
|
49
|
-
|
50
|
-
2. 使用 Data Loader 时,数据获取发生在渲染前,Modern.js 也仍然支持在组件渲染时获取数据。更多相关内容可以查看[数据获取](/guides/basic-features/data/data-fetch)。
|
51
|
-
|
52
|
-
:::
|
53
|
-
|
54
|
-
## 保持渲染一致
|
55
|
-
|
56
|
-
有些业务中,UI 展示会和用户设备有关,例如 [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) 信息。如果处理不够仔细,此时很有可能出现不符合预期的渲染结果。
|
57
|
-
|
58
|
-
这里通过一个例子,演示当 SSR 与 CSR 渲染不一致时出现的问题,在组件中添加以下代码:
|
59
|
-
|
60
|
-
```tsx
|
61
|
-
{
|
62
|
-
typeof window !== 'undefined' ? <div>browser content</div> : null;
|
63
|
-
}
|
64
|
-
```
|
65
|
-
|
66
|
-
启动应用后,访问页面,会发现浏览器控制台抛出警告信息:
|
67
|
-
|
68
|
-
```sh
|
69
|
-
Warning: Expected server HTML to contain a matching <div> in <div>.
|
70
|
-
```
|
71
|
-
|
72
|
-
这是 React hydrate 结果与 SSR 渲染结果不一致造成的。虽然当前页面表现正常,但在复杂应用中,很有可能因此出现 DOM 层级混乱、样式混乱等问题。
|
73
|
-
|
74
|
-
:::info
|
75
|
-
关于 hydrate (注水)逻辑请参考[这里](https://zh-hans.react.dev/reference/react-dom/hydrate)。
|
76
|
-
|
77
|
-
:::
|
78
|
-
|
79
|
-
应用需要保持 SSR 与 CSR 渲染结果的一致性,如果存在不一致的情况,说明这部分内容无需在 SSR 中进行渲染。Modern.js 为这类在 SSR 中不需要渲染的内容提供 [`<NoSSR>` 工具组件](/apis/app/runtime/core/use-runtime-context):
|
80
|
-
|
81
|
-
```ts
|
82
|
-
import { NoSSR } from '@modern-js/runtime/ssr';
|
83
|
-
```
|
84
|
-
|
85
|
-
在不需要进行 SSR 的元素外部,用 `NoSSR` 组件包裹:
|
86
|
-
|
87
|
-
```tsx
|
88
|
-
<NoSSR>
|
89
|
-
<div>client content</div>
|
90
|
-
</NoSSR>
|
91
|
-
```
|
92
|
-
|
93
|
-
修改代码后,刷新页发现之前的 Waring 消失。打开浏览器开发者工具的 Network 窗口,查看返回的 HTML 文档是不包含 `NoSSR` 组件包裹的内容的。
|
94
|
-
|
95
|
-
:::info 补充信息
|
96
|
-
[`useRuntimeContext`](/apis/app/runtime/core/use-runtime-context) 可以获取完整的请求信息,可以利用它保证 SSR 与 CSR 的渲染结果一致。
|
97
|
-
|
98
|
-
:::
|
99
|
-
|
100
|
-
## 关注内存泄漏
|
101
|
-
|
102
|
-
:::warning 警告
|
103
|
-
在 SSR 场景下,开发者需要特别关注内存泄露问题,即使是微小的内存泄露,在大量的访问后也会对服务造成影响。
|
104
|
-
|
105
|
-
:::
|
106
|
-
|
107
|
-
SSR 时,浏览器的每次请求,都会触发服务端重新执行一次组件渲染逻辑。所以,需要避免在全局定义任何可能不断增长的数据结构,或在全局进行事件订阅,或创建不会被销毁的流。
|
108
|
-
|
109
|
-
例如以下代码,使用 [redux-observable](https://redux-observable.js.org/) 时,习惯了 CSR 的开发者通常会在组件中这样编码:
|
110
|
-
|
111
|
-
```tsx
|
112
|
-
/* 代码仅作为示例,不可运行 */
|
113
|
-
import { createEpicMiddleware, combineEpics } from 'redux-observable';
|
114
|
-
|
115
|
-
const epicMiddleware = createEpicMiddleware();
|
116
|
-
const rootEpic = combineEpics();
|
117
|
-
|
118
|
-
export default function Test() {
|
119
|
-
epicMiddleware.run(rootEpic);
|
120
|
-
return <div>Hello Modern.js</div>;
|
121
|
-
}
|
122
|
-
```
|
123
|
-
|
124
|
-
在组件外层创建 Middleware 实例 `epicMiddleware`,并在组件内部调用 `epicMiddleware.run`。
|
125
|
-
|
126
|
-
在浏览器端,这段代码不会造成任何问题,但是在 SSR 时,Middleware 实例会一直无法被销毁。每次渲染组件,调用 `epicMiddleware.run(rootEpic)` 时,都会在内部添加新的事件绑定,导致整个对象不断变大,最终对应用性能造成影响。
|
127
|
-
|
128
|
-
CSR 中这类问题不易被发觉,因此从 CSR 切换到 SSR 时,如果不确定应用是否存在这类隐患,可以对应用进行压测。
|
129
|
-
|
130
|
-
## 收敛服务端数据
|
131
|
-
|
132
|
-
为了使浏览器端能够直接使用 SSR 阶段请求的数据,Modern.js 会将渲染过程中收集的数据与状态注入到 HTML 内。但是,CSR 应用常常存在接口数据量大、组件状态未收敛的情况,这时如果直接使用 SSR,渲染得到的 HTML 体积可能会存在过大的问题。此时,SSR 不仅无法为应用带来用户体验上的提升,反而可能起到相反的作用。
|
133
|
-
|
134
|
-
因此,使用 SSR 时,**开发者需要为应用做合理的瘦身**:
|
135
|
-
|
136
|
-
1. 关注首屏,SSR 中可以只请求首屏需要的数据,并在浏览器端渲染剩余的部分。
|
137
|
-
2. 将与渲染无关的数据,从接口返回数据中剔除。
|
138
|
-
|
139
|
-
## Serverless Pre-render
|
140
|
-
|
141
|
-
:::warning
|
142
|
-
x.43.0+ 已废弃,请使用 [SSR Cache](guides/advanced-features/ssr/cache) 替代
|
143
|
-
:::
|
144
|
-
|
145
|
-
Modern.js 提供 Serverless Pre-rendering (SPR) 这一特性来提升 SSR 性能。
|
146
|
-
|
147
|
-
SPR 利用预渲染与缓存技术,为 SSR 页面提供静态 Web 的响应性能。它让 SSR 应用拥有静态 Web 页面的响应速度与稳定性,同时还能保持数据的动态更新。
|
148
|
-
|
149
|
-
在 Modern.js 中使用 SPR 非常简单,只需要在组件中新增 `PreRender` 组件,该组件所在的页面就会自动开启 SPR。
|
150
|
-
|
151
|
-
这里模拟一个使用 `useLoaderData` API 的组件,Data Loader 中的请求需要消耗 2s 时间。
|
152
|
-
|
153
|
-
```tsx title="page.data.ts"
|
154
|
-
export const loader = async () => {
|
155
|
-
await new Promise((resolve, reject) => {
|
156
|
-
setTimeout(() => {
|
157
|
-
resolve(null);
|
158
|
-
}, 2000);
|
159
|
-
});
|
160
|
-
|
161
|
-
return {
|
162
|
-
message: 'Hello Modern.js',
|
163
|
-
};
|
164
|
-
};
|
165
|
-
```
|
166
|
-
|
167
|
-
```tsx title="page.tsx"
|
168
|
-
import { useLoaderData } from '@modern-js/runtime/router';
|
169
|
-
|
170
|
-
export default () => {
|
171
|
-
const data = useLoaderData();
|
172
|
-
return <div>{data?.message}</div>;
|
173
|
-
};
|
174
|
-
```
|
175
|
-
|
176
|
-
执行 `dev` 命令后,打开页面,可以明显的察觉到页面需要等到 2s 后才返回。
|
177
|
-
|
178
|
-
接下来使用 `PreRender` 组件来进行优化,该组件可以直接从 `@modern-js/runtime/ssr` 中导出:
|
179
|
-
|
180
|
-
```ts
|
181
|
-
import { PreRender } from '@modern-js/runtime/ssr';
|
182
|
-
```
|
183
|
-
|
184
|
-
在路由组件内使用 `PreRender` 组件,并设置参数 `interval`,用于表示该次渲染结果的过期时间为 5s:
|
185
|
-
|
186
|
-
```tsx
|
187
|
-
<PreRender interval={5} />
|
188
|
-
```
|
189
|
-
|
190
|
-
修改后,执行 `pnpm run build && pnpm run serve` 启动应用,并打开页面。
|
191
|
-
|
192
|
-
首次打开时,和之前的渲染并没有什么不同,同样存在 2s 延迟。点击刷新,页面瞬间打开,但此时,页面数据并没有因为刷新发生变化,这是因为缓存还没有过期。
|
193
|
-
|
194
|
-
等待 5s,重新刷新页面,页面的数据仍然没有变化。再一次刷新页面数据发生变化,但是页面仍然几乎是瞬间响应的。
|
195
|
-
这是因为在之前的请求时,SPR 已经在后台异步获取了新的渲染结果,本次请求到的页面是已经缓存在服务器中的版本。
|
196
|
-
|
197
|
-
可以想象,当 `interval` 设置为 1 时,用户可以在感知到实时数据的同时,拥有静态页面的响应体验。
|
198
|
-
|
199
|
-
:::info 补充信息
|
200
|
-
`PreRender` 的详细使用可以参考[这里](/apis/app/runtime/ssr/pre-render)。
|
201
|
-
|
202
|
-
:::
|
203
|
-
|
204
|
-
## Treeshaking
|
205
|
-
|
206
|
-
开启 SSR 时,Modern.js 会用相同的入口,构建出 SSR Bundle 和 CSR Bundle 两份产物。因此,在 SSR Bundle 中存在 Web API,或是在 CSR Bundle 中存在 Node API 时,都可能导致运行出错。
|
207
|
-
|
208
|
-
在组件中引入 Web API,通常情况下是要做一些全局监听,或是获取浏览器相关的数据,例如:
|
209
|
-
|
210
|
-
```tsx
|
211
|
-
document.addEventListener('load', () => {
|
212
|
-
console.log('document load');
|
213
|
-
});
|
214
|
-
const App = () => {
|
215
|
-
return <div>Hello World</div>;
|
216
|
-
};
|
217
|
-
export default App;
|
218
|
-
```
|
219
|
-
|
220
|
-
在组件文件中引入 Node API,通常情况下是因为使用了 `useLoader`,例如:
|
221
|
-
|
222
|
-
```ts
|
223
|
-
import fse from 'fs-extra';
|
224
|
-
import { useLoader } from '@modern-js/runtime'
|
225
|
-
|
226
|
-
const App = () => {
|
227
|
-
const { data } = useLoader(async () => {
|
228
|
-
const file = fse.readFileSync('./myfile');
|
229
|
-
return {
|
230
|
-
...
|
231
|
-
};
|
232
|
-
})
|
233
|
-
|
234
|
-
return <div>Hello World</div>;
|
235
|
-
};
|
236
|
-
export default App;
|
237
|
-
```
|
238
|
-
|
239
|
-
### 环境变量区分
|
240
|
-
|
241
|
-
对于第一种情况,我们可以直接使用 Modern.js 内置的环境变量 `MODERN_TARGET` 进行判断,在构建时删除无用代码:
|
242
|
-
|
243
|
-
```ts
|
244
|
-
if (process.env.MODERN_TARGET === 'browser') {
|
245
|
-
document.addEventListener('load', () => {
|
246
|
-
console.log('document load');
|
247
|
-
});
|
248
|
-
}
|
249
|
-
```
|
250
|
-
|
251
|
-
开发环境打包后,SSR 产物和 CSR 产物会被编译成以下内容。因此 SSR 环境中不会再因为 Web API 报错:
|
252
|
-
|
253
|
-
```ts
|
254
|
-
// SSR 产物
|
255
|
-
if (false) {
|
256
|
-
}
|
257
|
-
|
258
|
-
// CSR 产物
|
259
|
-
if (true) {
|
260
|
-
document.addEventListener('load', () => {
|
261
|
-
console.log('document load');
|
262
|
-
});
|
263
|
-
}
|
264
|
-
```
|
265
|
-
|
266
|
-
:::note
|
267
|
-
更多内容可以查看[环境变量](/guides/basic-features/env-vars)。
|
268
|
-
:::
|
269
|
-
|
270
|
-
### 文件后缀区分
|
271
|
-
|
272
|
-
但例如第二种情况,在代码中引入了 `fs-extra`,它内部有使用了 Node API 的副作用,如果直接引用到组件中,会造成 CSR 加载报错。
|
273
|
-
|
274
|
-
环境变量的方式并不能在这种情况下生效,Modern.js 也支持通过 `.node.` 后缀的文件来区分 SSR Bundle 和 CSR Bundle 产物的打包文件。
|
275
|
-
|
276
|
-
可以创建同名的 `.ts` 和 `.node.ts` 文件做一层代理:
|
277
|
-
|
278
|
-
```ts title="compat.ts"
|
279
|
-
export const readFileSync: any = () => {};
|
280
|
-
```
|
281
|
-
|
282
|
-
```ts title="compat.node.ts"
|
283
|
-
export { readFileSync } from 'fs-extra';
|
284
|
-
```
|
285
|
-
|
286
|
-
在文件中直接引入 `./compat`,此时 SSR 环境下会优先使用 `.node.ts` 后缀的文件,CSR 环境下会使用 `.ts` 后缀的文件。
|
287
|
-
|
288
|
-
```ts title="App.tsx"
|
289
|
-
import { readFileSync } from './compat'
|
290
|
-
|
291
|
-
export const loader = () => {
|
292
|
-
const file = readFileSync('./myfile');
|
293
|
-
return {
|
294
|
-
...
|
295
|
-
};
|
296
|
-
};
|
297
|
-
```
|
298
|
-
|
299
|
-
### 独立文件
|
300
|
-
|
301
|
-
上述两种方式,都会为开发者带来一些心智负担。在真实的业务中,我们发现大多数的 Node / Web 代码混用都出现在数据请求中。
|
302
|
-
|
303
|
-
因此,Modern.js 基于[嵌套路由](/guides/basic-features/routes)开发设计了[更简单的方案](/guides/basic-features/data/data-fetch)来分离 CSR 和 SSR 的代码。
|
304
|
-
|
305
|
-
我们可以通过独立文件来分离**数据请求**与**组件代码**。在 `routes/page.tsx` 中编写组件逻辑,在 `routes/page.data.ts` 中编写数据请求逻辑。
|
306
|
-
|
307
|
-
```ts title="routes/page.tsx"
|
308
|
-
export default Page = () => {
|
309
|
-
return <div>Hello World<div>
|
310
|
-
}
|
311
|
-
```
|
312
|
-
|
313
|
-
```ts title="routes/page.data.tsx"
|
314
|
-
import fse from 'fs-extra';
|
315
|
-
export const loader = () => {
|
316
|
-
const file = fse.readFileSync('./myfile');
|
317
|
-
return {
|
318
|
-
...
|
319
|
-
};
|
320
|
-
}
|
321
|
-
```
|
322
|
-
|
323
|
-
## 接口请求
|
324
|
-
|
325
|
-
在 SSR 中发起接口请求时,开发者有时自己封装了同构的请求工具。部分接口需要传递用户 Cookie,开发者可以通过 [`useRuntimeContext`](/guides/basic-features/data/data-fetch#route-loader) API 获取到请求头来实现。
|
326
|
-
|
327
|
-
需要注意的是,此时获取到的是 HTML 请求的请求头,不一定适用于接口请求,因此**千万不能**透传所有请求头。并且,一些后端接口,或是通用网关,会根据请求头中的信息做校验,全量透传容易出现各种难以排查的问题,推荐**按需透传**。
|
328
|
-
|
329
|
-
如果实在需要透传所有请求头,请务必过滤 `host` 字段。
|
File without changes
|
/package/docs/en/guides/advanced-features/{code-split.mdx → page-performance/code-split.mdx}
RENAMED
File without changes
|
/package/docs/en/guides/advanced-features/{inline-assets.mdx → page-performance/inline-assets.mdx}
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|