@modern-js/main-doc 2.67.4 → 2.67.6

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 (198) hide show
  1. package/docs/en/apis/app/hooks/server/server.mdx +10 -0
  2. package/docs/en/apis/app/hooks/src/routes.mdx +3 -3
  3. package/docs/en/apis/app/runtime/bff/use-hono-context.mdx +30 -0
  4. package/docs/en/components/enable-bff.mdx +1 -27
  5. package/docs/en/components/rsbuild-config-tooltip.mdx +2 -2
  6. package/docs/en/components/tech-stack-node-framework.mdx +1 -1
  7. package/docs/en/configure/app/dev/asset-prefix.mdx +2 -3
  8. package/docs/en/configure/app/dev/client.mdx +2 -3
  9. package/docs/en/configure/app/dev/hmr.mdx +2 -3
  10. package/docs/en/configure/app/dev/live-reload.mdx +2 -3
  11. package/docs/en/configure/app/dev/progress-bar.mdx +2 -3
  12. package/docs/en/configure/app/dev/setup-middlewares.mdx +2 -3
  13. package/docs/en/configure/app/dev/watch-files.mdx +2 -3
  14. package/docs/en/configure/app/dev/write-to-disk.mdx +2 -3
  15. package/docs/en/configure/app/html/app-icon.mdx +2 -3
  16. package/docs/en/configure/app/html/crossorigin.mdx +2 -3
  17. package/docs/en/configure/app/html/favicon.mdx +2 -3
  18. package/docs/en/configure/app/html/inject.mdx +2 -3
  19. package/docs/en/configure/app/html/meta.mdx +2 -3
  20. package/docs/en/configure/app/html/mount-id.mdx +2 -3
  21. package/docs/en/configure/app/html/output-structure.mdx +2 -3
  22. package/docs/en/configure/app/html/script-loading.mdx +2 -3
  23. package/docs/en/configure/app/html/tags.mdx +2 -3
  24. package/docs/en/configure/app/html/template-parameters.mdx +2 -3
  25. package/docs/en/configure/app/html/template.mdx +2 -3
  26. package/docs/en/configure/app/html/title.mdx +2 -3
  27. package/docs/en/configure/app/output/asset-prefix.mdx +2 -3
  28. package/docs/en/configure/app/output/charset.mdx +2 -3
  29. package/docs/en/configure/app/output/copy.mdx +2 -3
  30. package/docs/en/configure/app/output/css-modules.mdx +2 -3
  31. package/docs/en/configure/app/output/data-uri-limit.mdx +2 -3
  32. package/docs/en/configure/app/output/dist-path.mdx +2 -4
  33. package/docs/en/configure/app/output/externals.mdx +2 -3
  34. package/docs/en/configure/app/output/filename-hash.mdx +2 -3
  35. package/docs/en/configure/app/output/filename.mdx +2 -3
  36. package/docs/en/configure/app/output/inject-styles.mdx +2 -3
  37. package/docs/en/configure/app/output/inline-scripts.mdx +2 -3
  38. package/docs/en/configure/app/output/inline-styles.mdx +2 -3
  39. package/docs/en/configure/app/output/legal-comments.mdx +2 -3
  40. package/docs/en/configure/app/output/minify.mdx +2 -3
  41. package/docs/en/configure/app/output/override-browserslist.mdx +2 -3
  42. package/docs/en/configure/app/output/polyfill.mdx +2 -3
  43. package/docs/en/configure/app/output/source-map.mdx +2 -3
  44. package/docs/en/configure/app/performance/build-cache.mdx +2 -3
  45. package/docs/en/configure/app/performance/bundle-analyze.mdx +2 -3
  46. package/docs/en/configure/app/performance/chunk-split.mdx +2 -3
  47. package/docs/en/configure/app/performance/dns-prefetch.mdx +2 -3
  48. package/docs/en/configure/app/performance/preconnect.mdx +2 -3
  49. package/docs/en/configure/app/performance/prefetch.mdx +2 -3
  50. package/docs/en/configure/app/performance/preload.mdx +2 -3
  51. package/docs/en/configure/app/performance/print-file-size.mdx +2 -3
  52. package/docs/en/configure/app/performance/profile.mdx +2 -3
  53. package/docs/en/configure/app/performance/remove-console.mdx +2 -3
  54. package/docs/en/configure/app/performance/remove-moment-locale.mdx +2 -3
  55. package/docs/en/configure/app/plugins.mdx +13 -33
  56. package/docs/en/configure/app/runtime/master-app.mdx +1 -5
  57. package/docs/en/configure/app/runtime/plugins.mdx +58 -0
  58. package/docs/en/configure/app/security/nonce.mdx +2 -3
  59. package/docs/en/configure/app/security/sri.mdx +0 -1
  60. package/docs/en/configure/app/server/port.mdx +2 -3
  61. package/docs/en/configure/app/source/alias-strategy.mdx +2 -3
  62. package/docs/en/configure/app/source/alias.mdx +2 -3
  63. package/docs/en/configure/app/source/decorators.mdx +2 -3
  64. package/docs/en/configure/app/source/define.mdx +2 -3
  65. package/docs/en/configure/app/source/exclude.mdx +2 -3
  66. package/docs/en/configure/app/source/include.mdx +2 -3
  67. package/docs/en/configure/app/source/pre-entry.mdx +2 -3
  68. package/docs/en/configure/app/source/transform-import.mdx +2 -3
  69. package/docs/en/configure/app/tools/css-extract.mdx +2 -3
  70. package/docs/en/configure/app/tools/css-loader.mdx +2 -2
  71. package/docs/en/configure/app/tools/html-plugin.mdx +7 -3
  72. package/docs/en/configure/app/tools/lightningcss-loader.mdx +2 -3
  73. package/docs/en/configure/app/tools/postcss.mdx +2 -3
  74. package/docs/en/configure/app/tools/rspack.mdx +2 -3
  75. package/docs/en/configure/app/tools/style-loader.mdx +2 -3
  76. package/docs/en/configure/app/tools/swc.mdx +1 -1
  77. package/docs/en/configure/app/usage.mdx +1 -1
  78. package/docs/en/guides/advanced-features/bff/extend-server.mdx +33 -82
  79. package/docs/en/guides/advanced-features/bff/frameworks.mdx +12 -68
  80. package/docs/en/guides/advanced-features/bff.mdx +1 -1
  81. package/docs/en/guides/advanced-features/compatibility.mdx +1 -1
  82. package/docs/en/guides/advanced-features/page-performance/_meta.json +1 -1
  83. package/docs/en/guides/advanced-features/page-performance/inline-assets.mdx +2 -0
  84. package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  85. package/docs/en/guides/advanced-features/page-performance/react-compiler.mdx +44 -0
  86. package/docs/en/guides/advanced-features/web-server.mdx +378 -14
  87. package/docs/en/guides/basic-features/data/data-fetch.mdx +2 -1
  88. package/docs/en/guides/basic-features/deploy.mdx +3 -3
  89. package/docs/en/guides/basic-features/html.mdx +3 -3
  90. package/docs/en/guides/basic-features/output-files.mdx +0 -28
  91. package/docs/en/guides/basic-features/render/ssr.mdx +2 -2
  92. package/docs/en/guides/concept/entries.mdx +1 -1
  93. package/docs/en/plugin/cli-plugins/api.mdx +6 -0
  94. package/docs/en/plugin/runtime-plugins/api.mdx +37 -12
  95. package/docs/en/tutorials/first-app/c04-routes.mdx +4 -2
  96. package/docs/en/tutorials/first-app/c05-loader.mdx +5 -2
  97. package/docs/zh/apis/app/hooks/server/server.mdx +10 -0
  98. package/docs/zh/apis/app/hooks/src/routes.mdx +3 -3
  99. package/docs/zh/apis/app/runtime/bff/use-hono-context.mdx +31 -0
  100. package/docs/zh/components/enable-bff.mdx +2 -27
  101. package/docs/zh/components/rsbuild-config-tooltip.mdx +2 -2
  102. package/docs/zh/components/tech-stack-node-framework.mdx +1 -1
  103. package/docs/zh/configure/app/dev/asset-prefix.mdx +2 -3
  104. package/docs/zh/configure/app/dev/client.mdx +2 -3
  105. package/docs/zh/configure/app/dev/hmr.mdx +2 -3
  106. package/docs/zh/configure/app/dev/live-reload.mdx +2 -3
  107. package/docs/zh/configure/app/dev/progress-bar.mdx +2 -3
  108. package/docs/zh/configure/app/dev/setup-middlewares.mdx +2 -3
  109. package/docs/zh/configure/app/dev/watch-files.mdx +2 -3
  110. package/docs/zh/configure/app/dev/write-to-disk.mdx +2 -3
  111. package/docs/zh/configure/app/html/app-icon.mdx +2 -3
  112. package/docs/zh/configure/app/html/crossorigin.mdx +2 -3
  113. package/docs/zh/configure/app/html/favicon.mdx +2 -3
  114. package/docs/zh/configure/app/html/inject.mdx +2 -3
  115. package/docs/zh/configure/app/html/meta.mdx +2 -3
  116. package/docs/zh/configure/app/html/mount-id.mdx +2 -3
  117. package/docs/zh/configure/app/html/output-structure.mdx +2 -3
  118. package/docs/zh/configure/app/html/script-loading.mdx +2 -3
  119. package/docs/zh/configure/app/html/tags.mdx +2 -3
  120. package/docs/zh/configure/app/html/template-parameters.mdx +2 -3
  121. package/docs/zh/configure/app/html/template.mdx +2 -3
  122. package/docs/zh/configure/app/html/title.mdx +2 -3
  123. package/docs/zh/configure/app/output/asset-prefix.mdx +2 -3
  124. package/docs/zh/configure/app/output/charset.mdx +2 -3
  125. package/docs/zh/configure/app/output/copy.mdx +2 -3
  126. package/docs/zh/configure/app/output/css-modules.mdx +2 -3
  127. package/docs/zh/configure/app/output/data-uri-limit.mdx +2 -3
  128. package/docs/zh/configure/app/output/dist-path.mdx +2 -4
  129. package/docs/zh/configure/app/output/externals.mdx +2 -3
  130. package/docs/zh/configure/app/output/filename-hash.mdx +2 -3
  131. package/docs/zh/configure/app/output/filename.mdx +2 -3
  132. package/docs/zh/configure/app/output/inject-styles.mdx +2 -3
  133. package/docs/zh/configure/app/output/inline-scripts.mdx +2 -3
  134. package/docs/zh/configure/app/output/inline-styles.mdx +2 -3
  135. package/docs/zh/configure/app/output/legal-comments.mdx +2 -3
  136. package/docs/zh/configure/app/output/minify.mdx +2 -3
  137. package/docs/zh/configure/app/output/override-browserslist.mdx +2 -3
  138. package/docs/zh/configure/app/output/polyfill.mdx +2 -3
  139. package/docs/zh/configure/app/output/source-map.mdx +2 -3
  140. package/docs/zh/configure/app/performance/build-cache.mdx +2 -3
  141. package/docs/zh/configure/app/performance/bundle-analyze.mdx +2 -3
  142. package/docs/zh/configure/app/performance/chunk-split.mdx +2 -3
  143. package/docs/zh/configure/app/performance/dns-prefetch.mdx +2 -3
  144. package/docs/zh/configure/app/performance/preconnect.mdx +2 -3
  145. package/docs/zh/configure/app/performance/prefetch.mdx +2 -3
  146. package/docs/zh/configure/app/performance/preload.mdx +2 -3
  147. package/docs/zh/configure/app/performance/print-file-size.mdx +2 -3
  148. package/docs/zh/configure/app/performance/profile.mdx +2 -3
  149. package/docs/zh/configure/app/performance/remove-console.mdx +2 -3
  150. package/docs/zh/configure/app/performance/remove-moment-locale.mdx +2 -3
  151. package/docs/zh/configure/app/plugins.mdx +3 -24
  152. package/docs/zh/configure/app/runtime/master-app.mdx +1 -5
  153. package/docs/zh/configure/app/runtime/plugins.mdx +58 -0
  154. package/docs/zh/configure/app/security/nonce.mdx +2 -3
  155. package/docs/zh/configure/app/security/sri.mdx +0 -1
  156. package/docs/zh/configure/app/server/port.mdx +2 -3
  157. package/docs/zh/configure/app/source/alias-strategy.mdx +2 -3
  158. package/docs/zh/configure/app/source/alias.mdx +2 -3
  159. package/docs/zh/configure/app/source/decorators.mdx +2 -3
  160. package/docs/zh/configure/app/source/define.mdx +2 -3
  161. package/docs/zh/configure/app/source/exclude.mdx +2 -3
  162. package/docs/zh/configure/app/source/include.mdx +2 -3
  163. package/docs/zh/configure/app/source/pre-entry.mdx +2 -3
  164. package/docs/zh/configure/app/source/transform-import.mdx +2 -3
  165. package/docs/zh/configure/app/tools/css-extract.mdx +2 -3
  166. package/docs/zh/configure/app/tools/css-loader.mdx +2 -3
  167. package/docs/zh/configure/app/tools/html-plugin.mdx +6 -3
  168. package/docs/zh/configure/app/tools/lightningcss-loader.mdx +2 -3
  169. package/docs/zh/configure/app/tools/postcss.mdx +2 -3
  170. package/docs/zh/configure/app/tools/rspack.mdx +2 -3
  171. package/docs/zh/configure/app/tools/style-loader.mdx +2 -3
  172. package/docs/zh/configure/app/tools/swc.mdx +1 -1
  173. package/docs/zh/configure/app/usage.mdx +1 -1
  174. package/docs/zh/guides/advanced-features/bff/extend-server.mdx +28 -76
  175. package/docs/zh/guides/advanced-features/bff/frameworks.mdx +6 -66
  176. package/docs/zh/guides/advanced-features/page-performance/_meta.json +1 -1
  177. package/docs/zh/guides/advanced-features/page-performance/react-compiler.mdx +44 -0
  178. package/docs/zh/guides/advanced-features/web-server.mdx +375 -18
  179. package/docs/zh/guides/basic-features/deploy.mdx +4 -3
  180. package/docs/zh/guides/basic-features/output-files.mdx +0 -28
  181. package/docs/zh/plugin/cli-plugins/api.mdx +6 -0
  182. package/docs/zh/plugin/runtime-plugins/api.mdx +37 -12
  183. package/docs/zh/tutorials/first-app/c04-routes.mdx +4 -2
  184. package/docs/zh/tutorials/first-app/c05-loader.mdx +4 -1
  185. package/package.json +7 -4
  186. package/rspress.config.ts +16 -1
  187. package/src/components/RsbuildLink/index.tsx +2 -2
  188. package/src/i18n/index.ts +1 -1
  189. package/src/index.ts +1 -5
  190. package/src/pages/index.tsx +3 -3
  191. package/docs/en/apis/app/hooks/api/middleware.mdx +0 -11
  192. package/docs/en/apis/app/runtime/bff/hook.mdx +0 -44
  193. package/docs/en/apis/app/runtime/bff/use-context.mdx +0 -38
  194. package/docs/en/configure/app/bff/enable-handle-web.mdx +0 -24
  195. package/docs/zh/apis/app/hooks/api/middleware.mdx +0 -11
  196. package/docs/zh/apis/app/runtime/bff/hook.mdx +0 -44
  197. package/docs/zh/apis/app/runtime/bff/use-context.mdx +0 -38
  198. package/docs/zh/configure/app/bff/enable-handle-web.mdx +0 -24
@@ -6,34 +6,226 @@ sidebar_position: 16
6
6
 
7
7
  Modern.js 将大部分项目需要的服务端能力都进行了封装,通常项目无需进行服务端开发。但在有些开发场景下,例如用户鉴权、请求预处理、添加页面渲染骨架等,项目仍需要对服务端进行定制。
8
8
 
9
- Modern.js 提供了 **渲染中间件(Middleware)** 与**生命周期钩子(Hook)** 两类 API 来扩展 Web Server
9
+ ## 开启自定义 Web Server
10
+
11
+ :::info
12
+ 必须确保 Modern.js 版本是 x.67.5 及以上。
13
+ :::
14
+
15
+ 开启自定义 Web Server 功能,需要执行以下步骤:
16
+ 1. devDependencies 增加 `@modern-js/server-runtime` 及 `ts-node`依赖并安装。
17
+ 2. `tsconfig` 的 `include` 中添加 `server`。
18
+ 3. 项目目录下创建 `server/modern.server.ts` 文件,可以在这个文件中编写自定义逻辑。
19
+
20
+ ## 自定义 Web Server 能力
21
+
22
+ `server/modern.server.ts` 文件中添加如下配置来扩展 Server:
23
+ - **中间件(Middleware)**
24
+ - **渲染中间件(RenderMiddleware)**
25
+ - **服务端插件(Plugin)**
26
+
27
+ 其中 **Plugin** 中可以定义 **Middleware** 与 **RenderMiddleware**。 中间件加载流程如下图所示:
28
+
29
+ <img
30
+ src="https://lf3-static.bytednsdoc.com/obj/eden-cn/10eh7nuhpenuhog/server-md-wf.png"
31
+ style={{ width: '100%', maxWidth: '540px' }}
32
+ />
33
+
34
+ ### 基本配置
35
+
36
+ ```ts title="server/modern.server.ts"
37
+ import { defineServerConfig } from '@modern-js/server-runtime';
38
+
39
+ export default defineServerConfig({
40
+ middlewares: [], // 中间件
41
+ renderMiddlewares: [], // 渲染中间件
42
+ plugins: [], // 插件
43
+ });
44
+ ```
45
+
46
+
47
+ ### 类型定义
48
+
49
+ `defineServerConfig` 类型定义如下:
50
+
51
+ ```ts
52
+ import type { MiddlewareHandler } from 'hono';
53
+
54
+ type MiddlewareObj = {
55
+ name: string;
56
+ path?: string;
57
+ method?: 'options' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';
58
+ handler: MiddlewareHandler | MiddlewareHandler[];
59
+ };
60
+ type ServerConfig = {
61
+ middlewares?: MiddlewareObj[];
62
+ renderMiddlewares?: MiddlewareObj[];
63
+ plugins?: (ServerPlugin | ServerPluginLegacy)[];
64
+ }
65
+ ```
66
+
67
+
68
+ ### Middleware
69
+
70
+ Middleware 支持在 Modern.js 服务的**请求处理**与**页面路由**的流程前后,执行自定义逻辑。
71
+ 即自定义逻辑既要处理接口路由,也要作用于页面路由,那么 Middleware 是不二选择。
10
72
 
11
73
  :::note
12
- Middleware Hook 只会在用户请求页面路由时生效,BFF 路由不会经过这些 API。
74
+ 如果仅需要处理 BFF 接口路由,可以通过检查 `req.path` 是否以 BFF `prefix` 开头,来判断是否为 BFF 接口请求。
13
75
  :::
14
76
 
15
- ## 开启自定义 Web Server
77
+ 使用姿势如下:
78
+
79
+ ```ts title="server/modern.server.ts"
80
+ import { defineServerConfig, type MiddlewareHandler } from '@modern-js/server-runtime';
16
81
 
17
- 开发者可以在项目根目录执行 `pnpm run new` 命令,开启「自定义 Web Server」功能:
82
+ export const handler: MiddlewareHandler = async (c, next) => {
83
+ const monitors = c.get('monitors');
84
+ const start = Date.now();
85
+
86
+ await next();
18
87
 
19
- ```bash
20
- ? 请选择你想要的操作 创建工程元素
21
- ? 请选择创建元素类型 新建「自定义 Web Server」源码目录
88
+ const end = Date.now();
89
+ // 上报耗时
90
+ monitors.timing('request_timing', end - start);
91
+ };
92
+
93
+ export default defineServerConfig({
94
+ middlewares: [
95
+ {
96
+ name: 'request-timing',
97
+ handler,
98
+ },
99
+ ],
100
+ });
22
101
  ```
23
102
 
24
- 执行命令后,在 `modern.config.ts` 中注册 `@modern-js/plugin-server` 插件:
103
+ :::warning
104
+ 必须执行 `next` 函数才会执行后续的 Middleware。
105
+ :::
106
+
107
+
108
+ ### RenderMiddleware
109
+
110
+ 如果只需要处理页面渲染的前后执行逻辑,modern.js 也提供了渲染中间件,使用姿势如下:
111
+
112
+ ```ts title="server/modern.server.ts"
113
+ import { defineServerConfig, type MiddlewareHandler } from '@modern-js/server-runtime';
114
+
115
+ // 注入 render 性能指标
116
+ const renderTiming: MiddlewareHandler = async (c, next) => {
117
+ const start = Date.now();
118
+
119
+ await next();
120
+
121
+ const end = Date.now();
122
+ c.res.headers.set('server-timing', `render; dur=${end - start}`);
123
+ };
124
+
125
+ // 修改响应体
126
+ const modifyResBody: MiddlewareHandler = async (c, next) => {
127
+ await next();
25
128
 
26
- ```ts title="modern.config.ts"
27
- import { serverPlugin } from '@modern-js/plugin-server';
129
+ const { res } = c;
130
+ const text = await res.text();
131
+ const newText = text.replace('<body>', '<body> <h3>bytedance</h3>');
28
132
 
29
- export default defineConfig({
30
- plugins: [..., serverPlugin()],
133
+ c.res = c.body(newText, {
134
+ status: res.status,
135
+ headers: res.headers,
136
+ });
137
+ };
138
+
139
+ export default defineServerConfig({
140
+ renderMiddlewares: [
141
+ {
142
+ name: 'render-timing',
143
+ handler: renderTiming,
144
+ },
145
+ {
146
+ name: 'modify-res-body',
147
+ handler: modifyResBody,
148
+ },
149
+ ],
31
150
  });
32
151
  ```
33
152
 
34
- 开启功能后,项目目录下会自动创建 `server/index.ts` 文件,可以在这个文件中编写自定义逻辑。
35
153
 
36
- ## 自定义 Web Server 能力
154
+ ### Plugin
155
+
156
+ Modern.js 支持在自定义插件中为 Server 添加上述 Middleware 及 RenderMiddleware,使用姿势如下:
157
+
158
+
159
+ ```ts title="server/plugins/server.ts"
160
+ import type { ServerPluginLegacy } from '@modern-js/server-runtime';
161
+
162
+ export default (): ServerPluginLegacy => ({
163
+ name: 'serverPlugin',
164
+ setup(api) {
165
+ return {
166
+ prepare(serverConfig) {
167
+ const { middlewares, renderMiddlewares } = api.useAppContext();
168
+
169
+ // 注入服务端数据,供页面 dataLoader 消费
170
+ middlewares?.push({
171
+ name: 'server-plugin-middleware',
172
+ handler: async (c, next) => {
173
+ c.set('message', 'hi modern.js');
174
+ await next();
175
+ // ...
176
+ },
177
+ });
178
+
179
+ // 重定向
180
+ renderMiddlewares?.push({
181
+ name: 'server-plugin-render-middleware',
182
+ handler: async (c, next) => {
183
+ const user = getUser(c.req);
184
+ if (!user) {
185
+ return c.redirect('/login');
186
+ }
187
+
188
+ await next();
189
+ },
190
+ });
191
+ return serverConfig;
192
+ },
193
+ };
194
+ },
195
+ });
196
+ ```
197
+
198
+
199
+ ```ts title="server/modern.server.ts"
200
+ import { defineServerConfig } from '@modern-js/server-runtime';
201
+ import serverPlugin from './plugins/serverPlugin';
202
+
203
+ export default defineServerConfig({
204
+ plugins: [serverPlugin()],
205
+ });
206
+ ```
207
+
208
+
209
+ ```ts title="src/routes/page.data.ts"
210
+ import { useHonoContext } from '@modern-js/server-runtime';
211
+ import { defer } from '@modern-js/runtime/router';
212
+
213
+ export default () => {
214
+ const ctx = useHonoContext();
215
+ // SSR 场景消费服务端注入的数据
216
+ const message = ctx.get('message');
217
+
218
+ // ...
219
+ };
220
+
221
+ ```
222
+
223
+
224
+ ## 旧版 API(废弃)
225
+
226
+ :::warning
227
+ 旧版 API 兼容但不再推荐使用,扩展 Server 能力请移步 [自定义 Web Server](/guides/advanced-features/web-server.html),迁移指南参考 [迁移至新版自定义 Web Server](/guides/advanced-features/web-server.html#迁移至新版自定义-web-server)。
228
+ :::
37
229
 
38
230
  ### Unstable Middleware
39
231
 
@@ -64,10 +256,6 @@ export const unstableMiddleware: UnstableMiddleware[] = [time];
64
256
 
65
257
  ### Hook
66
258
 
67
- :::warning
68
- 我们推荐使用 UnstableMiddleware 代替 Hook。
69
- :::
70
-
71
259
  Modern.js 提供的 Hook 用于控制 Web Server 中的特定逻辑,所有的页面请求都会经过 Hook。
72
260
 
73
261
  目前提供了两种 Hook,分别是 `AfterMatch` 和 `AfterRender`,开发者可以在 `server/index.ts` 中这样写:
@@ -96,3 +284,172 @@ export const afterRender: AfterRenderHook = (ctx, next) => {
96
284
  :::info
97
285
  详细 API 和更多用法可以查看 [Hook](/apis/app/runtime/web-server/hook)。
98
286
  :::
287
+
288
+
289
+ ## 迁移至新版自定义 Web Server
290
+
291
+ ### 迁移背景
292
+
293
+ Modern.js Server 在不断演进,为了提供更强大的功能,我们对中间件和 Server 插件的定义和使用方式进行了优化。
294
+ 虽然旧版 API 仍被兼容,但我们强烈建议您按照本指南进行迁移,以充分利用新版的优势。
295
+
296
+ ### 迁移步骤
297
+
298
+ 1. 升级 Modern.js 版本至 x.67.5 及以上。
299
+ 2. 按照新版定义方式,在 `server/modern.server.ts` 中配置中间件或插件。
300
+ 3. 将 `server/index.ts` 自定义逻辑迁移到中间件或插件中,并参考 `Context` 和 `Next` 差异,更新您的代码。
301
+
302
+ ### Context 差异
303
+
304
+ 新版中间件 handler 类型为 Hono 的 `MiddlewareHandler`,即 `Context` 类型为 `Hono Context`。对比旧版自定义 Web Server 中 `Context` 差异如下:
305
+
306
+ #### UnstableMiddleware
307
+
308
+
309
+ ```ts
310
+ type Body = ReadableStream | ArrayBuffer | string | null;
311
+
312
+ type UnstableMiddlewareContext<
313
+ V extends Record<string, unknown> = Record<string, unknown>,
314
+ > = {
315
+ request: Request;
316
+ response: Response;
317
+ get: Get<V>;
318
+ set: Set<V>;
319
+ // 当前匹配到的路由信息
320
+ route: string;
321
+ header: (name: string, value: string, options?: { append?: boolean }) => void;
322
+ status: (code: number) => void;
323
+ redirect: (location: string, status?: number) => Response;
324
+ body: (data: Body, init?: ResponseInit) => Response;
325
+ html: (
326
+ data: string | Promise<string>,
327
+ init?: ResponseInit,
328
+ ) => Response | Promise<Response>;
329
+ };
330
+ ```
331
+
332
+ UnstableMiddleware `Context` 和 Hono `Context` 的具体差异:
333
+
334
+ | UnstableMiddleware | Hono | 说明 |
335
+ | :----------------------- | :---------------------------- | :------------------------------------------------------------------------ |
336
+ | `c.request` | `c.req.raw` | 参考 [HonoRequest raw](https://hono.dev/docs/api/request#raw) 文档 |
337
+ | `c.response` | `c.res` | 参考 [Hono Context res](https://hono.dev/docs/api/context#res) 文档 |
338
+ | `c.route` | `c.get('route')` | 获取应用上下文信息 |
339
+ | `loaderContext.get` | `honoContext.get` | 通过 `c.set` 注入数据后 dataLoader 中消费:旧版通过 `loaderContext.get` 获取,新版参考 [Plugin](/guides/advanced-features/web-server.html#使用姿势-2) 示例 |
340
+
341
+ #### Middleware
342
+
343
+ ```ts
344
+ type MiddlewareContext = {
345
+ response: {
346
+ set: (key: string, value: string) => void;
347
+ status: (code: number) => void;
348
+ getStatus: () => number;
349
+ cookies: {
350
+ set: (key: string, value: string, options?: any) => void;
351
+ clear: () => void;
352
+ };
353
+ raw: (
354
+ body: string,
355
+ { status, headers }: { status: number; headers: Record<string, any> },
356
+ ) => void;
357
+ locals: Record<string, any>;
358
+ };
359
+ request: {
360
+ url: string;
361
+ host: string;
362
+ pathname: string;
363
+ query: Record<string, any>;
364
+ cookie: string;
365
+ cookies: {
366
+ get: (key: string) => string;
367
+ };
368
+ headers: IncomingHttpHeaders;
369
+ };
370
+ source: {
371
+ req: IncomingMessage;
372
+ res: ServerResponse;
373
+ };
374
+ };
375
+
376
+ ```
377
+
378
+ Middleware `Context` 和 Hono `Context` 的具体差异:
379
+
380
+ | UnstableMiddleware | Hono | 说明 |
381
+ | :----------------------- | :---------------------------- | :--------------------------------------------------------------------------- |
382
+ | `c.request.cookie` | `c.req.cookie()` | 参考 [Hono Cookie Helper](https://hono.dev/docs/helpers/cookie) 文档 |
383
+ | `c.request.pathname` | `c.req.path` | 参考 [HonoRequest path](https://hono.dev/docs/api/request#path) 文档 |
384
+ | `c.request.url` | - | Hono `c.req.url` 为完整请求路径,自行通过 url 计算 |
385
+ | `c.request.host` | `c.req.header('Host')` | 通过 header 获取 host |
386
+ | `c.request.query` | `c.req.query()` | 参考 [HonoRequest query](https://hono.dev/docs/api/request#query) 文档 |
387
+ | `c.request.headers` | `c.req.header()` | 参考 [HonoRequest header](https://hono.dev/docs/api/request#header) 文档 |
388
+ | `c.response.set` | `c.res.headers.set` | 例:`c.res.headers.set('custom-header', '1')` |
389
+ | `c.response.status` | `c.status` | 例:`c.status(201)` |
390
+ | `c.response.cookies` | `c.header` | 例:`c.header('Set-Cookie', 'user_id=123')` |
391
+ | `c.response.raw` | `c.res` | 参考 [Hono Context res](https://hono.dev/docs/api/context#res) 文档 |
392
+
393
+
394
+ #### Hook
395
+
396
+ ```ts
397
+ type HookContext = {
398
+ response: {
399
+ set: (key: string, value: string) => void;
400
+ status: (code: number) => void;
401
+ getStatus: () => number;
402
+ cookies: {
403
+ set: (key: string, value: string, options?: any) => void;
404
+ clear: () => void;
405
+ };
406
+ raw: (
407
+ body: string,
408
+ { status, headers }: { status: number; headers: Record<string, any> },
409
+ ) => void;
410
+ };
411
+ request: {
412
+ url: string;
413
+ host: string;
414
+ pathname: string;
415
+ query: Record<string, any>;
416
+ cookie: string;
417
+ cookies: {
418
+ get: (key: string) => string;
419
+ };
420
+ headers: IncomingHttpHeaders;
421
+ };
422
+ };
423
+
424
+ type AfterMatchContext = HookContext & {
425
+ router: {
426
+ redirect: (url: string, status: number) => void;
427
+ rewrite: (entry: string) => void;
428
+ };
429
+ };
430
+
431
+ type AfterRenderContext = {
432
+ template: {
433
+ get: () => string;
434
+ set: (html: string) => void;
435
+ prependHead: (fragment: string) => void;
436
+ appendHead: (fragment: string) => void;
437
+ prependBody: (fragment: string) => void;
438
+ appendBody: (fragment: string) => void;
439
+ };
440
+ };
441
+ ```
442
+
443
+ Hook Context 大部分和 Middleware Context 一致,因此我们要额外关注不同 Hook 多余的部分。
444
+
445
+ | UnstableMiddleware | Hono | 说明 |
446
+ | :----------------------- | :---------------------------- | :----------------------------- |
447
+ | `router.redirect` | `c.redirect` | 参考 [Hono Context redirect](https://hono.dev/docs/api/context#redirect) 文档 |
448
+ | `router.rewrite` | - | 暂时没有提供对应的能力 |
449
+ | template API | `c.res` | 参考 [Hono Context res](https://hono.dev/docs/api/context#res) 文档 |
450
+
451
+
452
+ ### Next API 差异
453
+
454
+ 在 Middleware 和 Hook 中,即使不执行 `next`,渲染函数也会执行。
455
+ 在新的设计中,必须执行 `next` 函数才会执行后续的 Middleware。
@@ -110,7 +110,6 @@ Netlify 是一个流行的 Web 开发平台,专为构建、发布和维护现
110
110
 
111
111
  :::info
112
112
  你可参考部署[项目示例](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-csr)。
113
-
114
113
  :::
115
114
 
116
115
  在 Netlify 平台上添加项目,部署即可。
@@ -197,6 +196,7 @@ Vercel 是一个面向现代 Web 应用的部署平台,它提供了丰富的
197
196
  ### 纯前端项目
198
197
 
199
198
  在当前项目的根目录添加 `vercel.json` 文件:
199
+
200
200
  ```bash
201
201
  ./
202
202
  ├── src
@@ -206,6 +206,7 @@ Vercel 是一个面向现代 Web 应用的部署平台,它提供了丰富的
206
206
  ```
207
207
 
208
208
  在 `vercel.json` 中添加以下内容:
209
+
209
210
  ```json title="vercel.json"
210
211
  {
211
212
  "buildCommand": "modern deploy",
@@ -219,7 +220,6 @@ Vercel 是一个面向现代 Web 应用的部署平台,它提供了丰富的
219
220
 
220
221
  :::info
221
222
  你可参考部署[项目示例](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-csr)。
222
-
223
223
  :::
224
224
 
225
225
  ### 全栈项目
@@ -314,6 +314,7 @@ Github Pages 支持两种部署方式,通过分支部署或通过 Github Actio
314
314
  4. 执行 `npm run deploy:gh-pages`。
315
315
 
316
316
  :::info
317
+
317
318
  1. 执行 `MODERNJS_DEPLOY=ghPages modern deploy`,Modern.js 会把可用于 github 部署的产物构建到 `.output` 目录。
318
319
  2. 可以参考项目[示例](https://github.com/web-infra-dev/modern-js-examples/tree/main/examples/modern-js-deploy-csr)。
319
320
 
@@ -393,7 +394,7 @@ Nginx 是一个高性能的 HTTP 和反向代理服务器,它可以处理静
393
394
 
394
395
  如果你的项目是纯前端项目,也可以通过 Nginx 来部署应用,以下提供一个 Nginx 配置的示例来演示如何托管一个纯前端项目的产物。
395
396
 
396
- ```conf title="nginx.conf"
397
+ ```nginx title="nginx.conf"
397
398
  # user [user] [group];
398
399
  worker_processes 1;
399
400
 
@@ -96,34 +96,6 @@ dist
96
96
  └── qux.[hash].mp4
97
97
  ```
98
98
 
99
- ## Node.js 产物目录
100
-
101
- 当你在 Modern.js 中开启了 SSR 或 SSG 等服务端功能时,Modern.js 会在构建后生成一份 Node.js 产物,并输出到 `bundles` 目录下:
102
-
103
- ```bash
104
- dist
105
- ├── bundles
106
- │ └── [name].js
107
- ├── static
108
- └── html
109
- ```
110
-
111
- Node.js 产物通常只包含 JS 文件,不包含 HTML、CSS 等文件。此外,Node 产物的 JS 文件名称也不会自动生成哈希值。
112
-
113
- 你可以通过 [output.distPath.server](/configure/app/output/dist-path) 配置项来修改 Node 产物的输出路径。
114
-
115
- 比如,将 Node.js 产物输出到 `server` 目录:
116
-
117
- ```ts
118
- export default {
119
- output: {
120
- distPath: {
121
- server: 'server',
122
- },
123
- },
124
- };
125
- ```
126
-
127
99
  ## 扁平化产物目录
128
100
 
129
101
  有时候你不想产物目录有太多层级,可以将目录设置为空字符串,使生成的产物目录扁平化。
@@ -2,6 +2,12 @@
2
2
 
3
3
  本文档详细介绍了 Modern.js CLI 插件的 API。CLI 插件允许您在 Modern.js 项目的构建和开发过程中扩展和定制功能。
4
4
 
5
+ :::info
6
+
7
+ CLI 插件需要通过 `modern.config.ts` 中的 [`plugins`](/configure/app/plugins) 字段配置。
8
+
9
+ :::
10
+
5
11
  ## 插件基础结构
6
12
 
7
13
  一个典型的 CLI 插件结构如下:
@@ -2,6 +2,12 @@
2
2
 
3
3
  Modern.js 的 Runtime 插件允许您在应用程序的 React 代码运行时扩展和修改其行为。通过 Runtime 插件,您可以轻松地执行初始化任务、实现 React 高阶组件(HOC)封装等功能。
4
4
 
5
+ :::info
6
+
7
+ Runtime 插件需要通过 `src/modern.runtime.ts` 中的 [`plugins`](/configure/app/runtime/plugins) 字段配置。
8
+
9
+ :::
10
+
5
11
  ## 插件结构
6
12
 
7
13
  一个典型的 Runtime 插件如下所示:
@@ -151,16 +157,35 @@ await hooks.onBeforeRender.call(myContext);
151
157
  您可以组合使用多个钩子来实现更复杂的功能。例如,您可以使用 `onBeforeRender` 获取数据,然后使用 `wrapRoot` 将数据通过 Context 传递给整个应用:
152
158
 
153
159
  ```ts
154
- api.onBeforeRender(async (context) => {
155
- const data = await fetchData(context.req);
156
- context.data = data;
157
- });
158
-
159
- api.wrapRoot((App) => {
160
- return (props) => (
161
- <DataContext.Provider value={props.data}>
162
- <App {...props} />
163
- </DataContext.Provider>
164
- );
165
- });
160
+ import { RuntimePluginFuture, RuntimeReactContext } from '@modern-js/runtime';
161
+ import { useContext, createContext } from 'react';
162
+
163
+ export const ThemeContext = createContext<{ theme: string } | null>(null);
164
+
165
+ export const themePlugin = (): RuntimePluginFuture => {
166
+ return {
167
+ name: 'theme-plugin',
168
+ setup: api => {
169
+ api.onBeforeRender(async context => {
170
+ const userPreference = await fetch('/api/user/theme-settings').then(
171
+ res => res.json(),
172
+ );
173
+ context.data = {
174
+ theme: userPreference.theme,
175
+ };
176
+ });
177
+
178
+ api.wrapRoot(App => {
179
+ return props => {
180
+ const context = useContext(RuntimeReactContext);
181
+ return (
182
+ <ThemeContext.Provider value={context.data}>
183
+ <App {...props} />
184
+ </ThemeContext.Provider>
185
+ );
186
+ };
187
+ });
188
+ },
189
+ };
190
+ };
166
191
  ```
@@ -118,8 +118,9 @@ import { Radio } from 'antd';
118
118
 
119
119
  然后将 UI 最顶部进行修改,增加一组单选框
120
120
 
121
- ```tsx {4-9}
121
+ ```tsx
122
122
  export default function Layout() {
123
+ // [!code highlight:8]
123
124
  return (
124
125
  <div>
125
126
  <div className="h-16 p-2 flex items-center justify-center">
@@ -146,8 +147,9 @@ import { Outlet, useLocation, useNavigate } from '@modern-js/runtime/router';
146
147
 
147
148
  最后在 Layout 组件里增加局部状态和相关逻辑:
148
149
 
149
- ```tsx {2-9}
150
+ ```tsx
150
151
  export default function Layout() {
152
+ // [!code highlight:8]
151
153
  const navigate = useNavigate();
152
154
  const location = useLocation();
153
155
  const [currentList, setList] = useState(location.pathname || '/');
@@ -56,11 +56,13 @@ Data Loader 并非只为 SSR 工作。在 CSR 项目中,Data Loader 也可以
56
56
 
57
57
  Modern.js 也提供了一个叫 `useLoaderData` 的 hooks API,我们修改 `src/routes/page.tsx` 导出的组件:
58
58
 
59
- ```tsx {1,2,5,13}
59
+ ```tsx
60
+ // [!code highlight:2]
60
61
  import { useLoaderData } from '@modern-js/runtime/router';
61
62
  import type { LoaderData } from './page.data';
62
63
 
63
64
  function Index() {
65
+ // [!code highlight:1]
64
66
  const { data } = useLoaderData() as LoaderData;
65
67
 
66
68
  return (
@@ -68,6 +70,7 @@ function Index() {
68
70
  <Helmet>
69
71
  <title>All</title>
70
72
  </Helmet>
73
+ // [!code highlight:1]
71
74
  <List
72
75
  dataSource={data}
73
76
  renderItem={info => <Item key={info.name} info={info} />}
package/package.json CHANGED
@@ -15,17 +15,20 @@
15
15
  "modern",
16
16
  "modern.js"
17
17
  ],
18
- "version": "2.67.4",
18
+ "version": "2.67.6",
19
19
  "publishConfig": {
20
20
  "registry": "https://registry.npmjs.org/",
21
21
  "access": "public"
22
22
  },
23
23
  "dependencies": {
24
24
  "mermaid": "^11.4.1",
25
- "@modern-js/sandpack-react": "2.67.4"
25
+ "@modern-js/sandpack-react": "2.67.6"
26
26
  },
27
27
  "devDependencies": {
28
- "@rspress/shared": "1.43.11",
28
+ "@rsbuild/plugin-sass": "1.3.1",
29
+ "@shikijs/transformers": "^3.4.2",
30
+ "@rspress/shared": "2.0.0-beta.6",
31
+ "@rspress/plugin-llms": "2.0.0-beta.6",
29
32
  "@types/fs-extra": "9.0.13",
30
33
  "@types/node": "^16",
31
34
  "classnames": "^2.5.1",
@@ -33,7 +36,7 @@
33
36
  "fs-extra": "^10",
34
37
  "react": "^18.3.1",
35
38
  "react-dom": "^18.3.1",
36
- "rspress": "1.43.11",
39
+ "rspress": "2.0.0-beta.6",
37
40
  "ts-node": "^10.9.1",
38
41
  "typescript": "^5"
39
42
  },