@modern-js/app-tools 3.7.0 → 3.8.1

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 (306) hide show
  1. package/bin/modern-bundle-docs.js +7 -0
  2. package/dist/cjs/builder/generator/createBuilderProviderConfig.js +5 -1
  3. package/dist/cjs/bundleDocs.js +114 -0
  4. package/dist/cjs/commands/build.js +2 -1
  5. package/dist/cjs/commands/deploy.js +4 -2
  6. package/dist/cjs/commands/index.js +0 -4
  7. package/dist/cjs/config/default.js +2 -0
  8. package/dist/cjs/index.js +52 -14
  9. package/dist/cjs/plugins/analyze/index.js +2 -2
  10. package/dist/cjs/plugins/analyze/utils.js +3 -2
  11. package/dist/cjs/plugins/initialize/index.js +4 -3
  12. package/dist/cjs/plugins/serverBuild.js +3 -2
  13. package/dist/esm/builder/generator/createBuilderProviderConfig.mjs +5 -1
  14. package/dist/esm/bundleDocs.mjs +62 -0
  15. package/dist/esm/commands/build.mjs +2 -1
  16. package/dist/esm/commands/deploy.mjs +4 -2
  17. package/dist/esm/commands/index.mjs +0 -4
  18. package/dist/esm/config/default.mjs +2 -0
  19. package/dist/esm/index.mjs +15 -1
  20. package/dist/esm/plugins/analyze/index.mjs +2 -2
  21. package/dist/esm/plugins/analyze/utils.mjs +3 -2
  22. package/dist/esm/plugins/initialize/index.mjs +4 -3
  23. package/dist/esm/plugins/serverBuild.mjs +3 -2
  24. package/dist/esm-node/builder/generator/createBuilderProviderConfig.mjs +5 -1
  25. package/dist/esm-node/bundleDocs.mjs +63 -0
  26. package/dist/esm-node/commands/build.mjs +2 -1
  27. package/dist/esm-node/commands/deploy.mjs +4 -2
  28. package/dist/esm-node/commands/index.mjs +0 -4
  29. package/dist/esm-node/config/default.mjs +2 -0
  30. package/dist/esm-node/index.mjs +15 -1
  31. package/dist/esm-node/plugins/analyze/index.mjs +2 -2
  32. package/dist/esm-node/plugins/analyze/utils.mjs +3 -2
  33. package/dist/esm-node/plugins/initialize/index.mjs +4 -3
  34. package/dist/esm-node/plugins/serverBuild.mjs +3 -2
  35. package/dist/types/bundleDocs.d.ts +20 -0
  36. package/dist/types/commands/deploy.d.ts +2 -1
  37. package/dist/types/index.d.ts +4 -1
  38. package/dist/types/plugins/analyze/utils.d.ts +1 -1
  39. package/dist/types/types/config/dev.d.ts +6 -0
  40. package/docs/apis/app/commands.md +241 -0
  41. package/docs/apis/app/hooks/api/lambda.md +9 -0
  42. package/docs/apis/app/hooks/config/favicon.md +24 -0
  43. package/docs/apis/app/hooks/config/html.md +5 -0
  44. package/docs/apis/app/hooks/config/icon.md +24 -0
  45. package/docs/apis/app/hooks/config/mock.md +6 -0
  46. package/docs/apis/app/hooks/config/public.md +26 -0
  47. package/docs/apis/app/hooks/config/upload.md +50 -0
  48. package/docs/apis/app/hooks/modern-config.md +5 -0
  49. package/docs/apis/app/hooks/server/server.md +5 -0
  50. package/docs/apis/app/hooks/shared.md +3 -0
  51. package/docs/apis/app/hooks/src/app.md +30 -0
  52. package/docs/apis/app/hooks/src/entry.md +34 -0
  53. package/docs/apis/app/hooks/src/entry.server.md +51 -0
  54. package/docs/apis/app/hooks/src/modern.runtime.md +5 -0
  55. package/docs/apis/app/hooks/src/routes.md +86 -0
  56. package/docs/apis/app/hooks/src/server.md +3 -0
  57. package/docs/apis/app/runtime/bff/use-hono-context.md +27 -0
  58. package/docs/apis/app/runtime/core/create-root.md +19 -0
  59. package/docs/apis/app/runtime/core/render.md +39 -0
  60. package/docs/apis/app/runtime/core/runtime-context.md +156 -0
  61. package/docs/apis/app/runtime/router/router.md +280 -0
  62. package/docs/apis/app/runtime/ssr/no-ssr.md +35 -0
  63. package/docs/apis/app/runtime/ssr/renderStreaming.md +67 -0
  64. package/docs/apis/app/runtime/ssr/renderString.md +60 -0
  65. package/docs/apis/app/runtime/ssr/requestHandler.md +44 -0
  66. package/docs/apis/app/runtime/utility/css-in-js.md +40 -0
  67. package/docs/apis/app/runtime/utility/head.md +35 -0
  68. package/docs/apis/app/runtime/utility/loadable.md +82 -0
  69. package/docs/community/blog/2022-0708-updates.md +91 -0
  70. package/docs/community/blog/2022-0910-updates.md +76 -0
  71. package/docs/community/blog/overview.md +63 -0
  72. package/docs/community/blog/v2-release-note.md +238 -0
  73. package/docs/community/blog/v3-release-note.md +622 -0
  74. package/docs/community/contributing-guide.md +253 -0
  75. package/docs/community/releases.md +27 -0
  76. package/docs/community/showcase.md +34 -0
  77. package/docs/community/team.md +14 -0
  78. package/docs/configure/app/bff/cross-project.md +20 -0
  79. package/docs/configure/app/bff/prefix.md +29 -0
  80. package/docs/configure/app/builder-plugins.md +66 -0
  81. package/docs/configure/app/dev/asset-prefix.md +13 -0
  82. package/docs/configure/app/dev/before-start-url.md +17 -0
  83. package/docs/configure/app/dev/client.md +41 -0
  84. package/docs/configure/app/dev/hmr.md +10 -0
  85. package/docs/configure/app/dev/host.md +18 -0
  86. package/docs/configure/app/dev/https.md +77 -0
  87. package/docs/configure/app/dev/lazy-compilation.md +39 -0
  88. package/docs/configure/app/dev/live-reload.md +10 -0
  89. package/docs/configure/app/dev/mock-dir.md +31 -0
  90. package/docs/configure/app/dev/progress-bar.md +19 -0
  91. package/docs/configure/app/dev/server.md +124 -0
  92. package/docs/configure/app/dev/setup-middlewares.md +32 -0
  93. package/docs/configure/app/dev/start-url.md +48 -0
  94. package/docs/configure/app/dev/watch-files.md +27 -0
  95. package/docs/configure/app/dev/write-to-disk.md +10 -0
  96. package/docs/configure/app/experiments/source-build.md +31 -0
  97. package/docs/configure/app/html/app-icon.md +28 -0
  98. package/docs/configure/app/html/crossorigin.md +10 -0
  99. package/docs/configure/app/html/favicon.md +16 -0
  100. package/docs/configure/app/html/inject.md +10 -0
  101. package/docs/configure/app/html/meta.md +24 -0
  102. package/docs/configure/app/html/mount-id.md +10 -0
  103. package/docs/configure/app/html/output-structure.md +10 -0
  104. package/docs/configure/app/html/script-loading.md +10 -0
  105. package/docs/configure/app/html/tags.md +15 -0
  106. package/docs/configure/app/html/template-parameters.md +33 -0
  107. package/docs/configure/app/html/template.md +10 -0
  108. package/docs/configure/app/html/title.md +18 -0
  109. package/docs/configure/app/output/asset-prefix.md +11 -0
  110. package/docs/configure/app/output/assets-retry.md +77 -0
  111. package/docs/configure/app/output/charset.md +10 -0
  112. package/docs/configure/app/output/clean-dist-path.md +16 -0
  113. package/docs/configure/app/output/convert-to-rem.md +79 -0
  114. package/docs/configure/app/output/copy.md +10 -0
  115. package/docs/configure/app/output/css-modules.md +48 -0
  116. package/docs/configure/app/output/data-uri-limit.md +26 -0
  117. package/docs/configure/app/output/disable-css-module-extension.md +55 -0
  118. package/docs/configure/app/output/disable-inline-runtime-chunk.md +41 -0
  119. package/docs/configure/app/output/disable-svgr.md +16 -0
  120. package/docs/configure/app/output/disable-ts-checker.md +49 -0
  121. package/docs/configure/app/output/dist-path.md +43 -0
  122. package/docs/configure/app/output/enable-asset-manifest.md +36 -0
  123. package/docs/configure/app/output/enable-css-module-tsdeclaration.md +28 -0
  124. package/docs/configure/app/output/enable-inline-route-manifests.md +16 -0
  125. package/docs/configure/app/output/externals.md +20 -0
  126. package/docs/configure/app/output/filename-hash.md +10 -0
  127. package/docs/configure/app/output/filename.md +55 -0
  128. package/docs/configure/app/output/inject-styles.md +10 -0
  129. package/docs/configure/app/output/inline-scripts.md +29 -0
  130. package/docs/configure/app/output/inline-styles.md +29 -0
  131. package/docs/configure/app/output/legal-comments.md +18 -0
  132. package/docs/configure/app/output/minify.md +22 -0
  133. package/docs/configure/app/output/override-browserslist.md +22 -0
  134. package/docs/configure/app/output/polyfill.md +12 -0
  135. package/docs/configure/app/output/source-map.md +30 -0
  136. package/docs/configure/app/output/split-route-chunks.md +16 -0
  137. package/docs/configure/app/output/ssg.md +81 -0
  138. package/docs/configure/app/output/ssgByEntries.md +90 -0
  139. package/docs/configure/app/output/svg-default-export.md +30 -0
  140. package/docs/configure/app/output/temp-dir.md +20 -0
  141. package/docs/configure/app/performance/build-cache.md +39 -0
  142. package/docs/configure/app/performance/chunk-split.md +40 -0
  143. package/docs/configure/app/performance/dns-prefetch.md +15 -0
  144. package/docs/configure/app/performance/preconnect.md +16 -0
  145. package/docs/configure/app/performance/prefetch.md +21 -0
  146. package/docs/configure/app/performance/preload.md +23 -0
  147. package/docs/configure/app/performance/print-file-size.md +40 -0
  148. package/docs/configure/app/performance/profile.md +10 -0
  149. package/docs/configure/app/performance/remove-console.md +10 -0
  150. package/docs/configure/app/performance/remove-moment-locale.md +10 -0
  151. package/docs/configure/app/plugins.md +59 -0
  152. package/docs/configure/app/resolve/alias-strategy.md +10 -0
  153. package/docs/configure/app/resolve/alias.md +9 -0
  154. package/docs/configure/app/resolve/condition-names.md +13 -0
  155. package/docs/configure/app/resolve/dedupe.md +9 -0
  156. package/docs/configure/app/resolve/extensions.md +13 -0
  157. package/docs/configure/app/runtime/0-intro.md +58 -0
  158. package/docs/configure/app/runtime/plugins.md +58 -0
  159. package/docs/configure/app/runtime/router.md +35 -0
  160. package/docs/configure/app/security/check-syntax.md +69 -0
  161. package/docs/configure/app/security/nonce.md +15 -0
  162. package/docs/configure/app/security/sri.md +20 -0
  163. package/docs/configure/app/server/base-url.md +26 -0
  164. package/docs/configure/app/server/port.md +18 -0
  165. package/docs/configure/app/server/public-routes.md +22 -0
  166. package/docs/configure/app/server/routes.md +86 -0
  167. package/docs/configure/app/server/rsc.md +26 -0
  168. package/docs/configure/app/server/ssr-by-entries.md +25 -0
  169. package/docs/configure/app/server/ssr.md +78 -0
  170. package/docs/configure/app/server/tsconfig-path.md +59 -0
  171. package/docs/configure/app/source/alias-strategy.md +14 -0
  172. package/docs/configure/app/source/alias.md +23 -0
  173. package/docs/configure/app/source/config-dir.md +20 -0
  174. package/docs/configure/app/source/decorators.md +25 -0
  175. package/docs/configure/app/source/define.md +16 -0
  176. package/docs/configure/app/source/disable-default-entries.md +28 -0
  177. package/docs/configure/app/source/enable-async-entry.md +54 -0
  178. package/docs/configure/app/source/enable-async-pre-entry.md +26 -0
  179. package/docs/configure/app/source/entries-dir.md +35 -0
  180. package/docs/configure/app/source/entries.md +179 -0
  181. package/docs/configure/app/source/exclude.md +10 -0
  182. package/docs/configure/app/source/global-vars.md +106 -0
  183. package/docs/configure/app/source/include.md +36 -0
  184. package/docs/configure/app/source/main-entry-name.md +24 -0
  185. package/docs/configure/app/source/pre-entry.md +10 -0
  186. package/docs/configure/app/source/react-compiler.md +68 -0
  187. package/docs/configure/app/source/transform-import.md +27 -0
  188. package/docs/configure/app/split-chunks.md +17 -0
  189. package/docs/configure/app/tools/autoprefixer.md +44 -0
  190. package/docs/configure/app/tools/bundler-chain.md +26 -0
  191. package/docs/configure/app/tools/css-extract.md +33 -0
  192. package/docs/configure/app/tools/css-loader.md +17 -0
  193. package/docs/configure/app/tools/dev-server.md +113 -0
  194. package/docs/configure/app/tools/html-plugin.md +41 -0
  195. package/docs/configure/app/tools/less.md +81 -0
  196. package/docs/configure/app/tools/lightningcss-loader.md +35 -0
  197. package/docs/configure/app/tools/minify-css.md +53 -0
  198. package/docs/configure/app/tools/postcss.md +34 -0
  199. package/docs/configure/app/tools/rspack.md +10 -0
  200. package/docs/configure/app/tools/sass.md +78 -0
  201. package/docs/configure/app/tools/style-loader.md +10 -0
  202. package/docs/configure/app/tools/swc.md +65 -0
  203. package/docs/configure/app/tools/ts-checker.md +109 -0
  204. package/docs/configure/app/usage.md +276 -0
  205. package/docs/guides/advanced-features/bff/cross-project.md +109 -0
  206. package/docs/guides/advanced-features/bff/extend-server.md +120 -0
  207. package/docs/guides/advanced-features/bff/frameworks.md +124 -0
  208. package/docs/guides/advanced-features/bff/function.md +314 -0
  209. package/docs/guides/advanced-features/bff/operators.md +554 -0
  210. package/docs/guides/advanced-features/bff/sdk.md +116 -0
  211. package/docs/guides/advanced-features/bff/upload.md +101 -0
  212. package/docs/guides/advanced-features/bff.md +18 -0
  213. package/docs/guides/advanced-features/build-performance.md +130 -0
  214. package/docs/guides/advanced-features/compatibility.md +120 -0
  215. package/docs/guides/advanced-features/international/advanced.md +128 -0
  216. package/docs/guides/advanced-features/international/api.md +231 -0
  217. package/docs/guides/advanced-features/international/best-practices.md +286 -0
  218. package/docs/guides/advanced-features/international/configuration.md +227 -0
  219. package/docs/guides/advanced-features/international/locale-detection.md +126 -0
  220. package/docs/guides/advanced-features/international/quick-start.md +128 -0
  221. package/docs/guides/advanced-features/international/resource-loading.md +154 -0
  222. package/docs/guides/advanced-features/international/routing.md +130 -0
  223. package/docs/guides/advanced-features/international.md +27 -0
  224. package/docs/guides/advanced-features/low-level.md +46 -0
  225. package/docs/guides/advanced-features/page-performance/code-split.md +77 -0
  226. package/docs/guides/advanced-features/page-performance/inline-assets.md +159 -0
  227. package/docs/guides/advanced-features/page-performance/optimize-bundle.md +97 -0
  228. package/docs/guides/advanced-features/page-performance/react-compiler.md +69 -0
  229. package/docs/guides/advanced-features/server-monitor/logger.md +41 -0
  230. package/docs/guides/advanced-features/server-monitor/metrics.md +58 -0
  231. package/docs/guides/advanced-features/server-monitor/monitors.md +242 -0
  232. package/docs/guides/advanced-features/source-build.md +164 -0
  233. package/docs/guides/advanced-features/web-server.md +288 -0
  234. package/docs/guides/basic-features/alias.md +102 -0
  235. package/docs/guides/basic-features/css/css-in-js.md +72 -0
  236. package/docs/guides/basic-features/css/css-modules.md +212 -0
  237. package/docs/guides/basic-features/css/css.md +27 -0
  238. package/docs/guides/basic-features/css/tailwindcss.md +27 -0
  239. package/docs/guides/basic-features/data/data-cache.md +510 -0
  240. package/docs/guides/basic-features/data/data-fetch.md +415 -0
  241. package/docs/guides/basic-features/data/data-write.md +227 -0
  242. package/docs/guides/basic-features/debug/mock.md +109 -0
  243. package/docs/guides/basic-features/debug/proxy.md +21 -0
  244. package/docs/guides/basic-features/debug/rsdoctor.md +62 -0
  245. package/docs/guides/basic-features/debug/using-storybook.md +112 -0
  246. package/docs/guides/basic-features/deploy.md +458 -0
  247. package/docs/guides/basic-features/env-vars.md +177 -0
  248. package/docs/guides/basic-features/html.md +255 -0
  249. package/docs/guides/basic-features/output-files.md +141 -0
  250. package/docs/guides/basic-features/render/before-render.md +108 -0
  251. package/docs/guides/basic-features/render/overview.md +47 -0
  252. package/docs/guides/basic-features/render/rsc.md +525 -0
  253. package/docs/guides/basic-features/render/ssg.md +228 -0
  254. package/docs/guides/basic-features/render/ssr-cache.md +201 -0
  255. package/docs/guides/basic-features/render/ssr.md +321 -0
  256. package/docs/guides/basic-features/render/streaming-ssr.md +264 -0
  257. package/docs/guides/basic-features/routes/config-routes.md +426 -0
  258. package/docs/guides/basic-features/routes/routes.md +498 -0
  259. package/docs/guides/basic-features/static-assets/json-files.md +120 -0
  260. package/docs/guides/basic-features/static-assets/svg-assets.md +168 -0
  261. package/docs/guides/basic-features/static-assets/wasm-assets.md +62 -0
  262. package/docs/guides/basic-features/static-assets.md +160 -0
  263. package/docs/guides/basic-features/testing/playwright.md +120 -0
  264. package/docs/guides/basic-features/testing/rstest.md +251 -0
  265. package/docs/guides/concept/builder.md +37 -0
  266. package/docs/guides/concept/entries.md +319 -0
  267. package/docs/guides/concept/server.md +35 -0
  268. package/docs/guides/get-started/ai-coding-agents.md +58 -0
  269. package/docs/guides/get-started/glossary.md +63 -0
  270. package/docs/guides/get-started/introduction.md +36 -0
  271. package/docs/guides/get-started/quick-start.md +236 -0
  272. package/docs/guides/get-started/tech-stack.md +82 -0
  273. package/docs/guides/get-started/upgrade.md +123 -0
  274. package/docs/guides/topic-detail/module-federation/application.md +116 -0
  275. package/docs/guides/topic-detail/module-federation/deploy.md +104 -0
  276. package/docs/guides/topic-detail/module-federation/i18n.md +670 -0
  277. package/docs/guides/topic-detail/module-federation/introduce.md +35 -0
  278. package/docs/guides/topic-detail/module-federation/ssr.md +118 -0
  279. package/docs/guides/topic-detail/module-federation/usage.md +219 -0
  280. package/docs/guides/troubleshooting/builder.md +110 -0
  281. package/docs/guides/troubleshooting/cli.md +35 -0
  282. package/docs/guides/troubleshooting/dependencies.md +119 -0
  283. package/docs/guides/troubleshooting/hmr.md +144 -0
  284. package/docs/guides/upgrade/config.md +963 -0
  285. package/docs/guides/upgrade/entry.md +463 -0
  286. package/docs/guides/upgrade/other.md +183 -0
  287. package/docs/guides/upgrade/overview.md +33 -0
  288. package/docs/guides/upgrade/tailwindcss.md +91 -0
  289. package/docs/guides/upgrade/web-server.md +109 -0
  290. package/docs/index.md +33 -0
  291. package/docs/llms.txt +285 -0
  292. package/docs/plugin/cli-plugins/api.md +573 -0
  293. package/docs/plugin/cli-plugins/life-cycle.md +2 -0
  294. package/docs/plugin/introduction.md +152 -0
  295. package/docs/plugin/official/cli-plugins/plugin-bff.md +5 -0
  296. package/docs/plugin/official/cli-plugins/plugin-ssg.md +5 -0
  297. package/docs/plugin/official/cli-plugins/plugin-styled-components.md +5 -0
  298. package/docs/plugin/official/cli-plugins.md +4 -0
  299. package/docs/plugin/plugin-system.md +238 -0
  300. package/docs/plugin/runtime-plugins/api.md +194 -0
  301. package/docs/plugin/runtime-plugins/life-cycle.md +2 -0
  302. package/docs/plugin/server-plugins/api.md +209 -0
  303. package/docs/plugin/server-plugins/life-cycle.md +13 -0
  304. package/docs/tutorials/examples/csr-auth.md +9 -0
  305. package/docs/tutorials/foundations/introduction.md +16 -0
  306. package/package.json +46 -13
@@ -0,0 +1,321 @@
1
+ # Server-Side Rendering
2
+
3
+ Server-Side Rendering (SSR) generates complete HTML pages on the server and sends them to the browser for direct display, without requiring additional client-side rendering.
4
+
5
+ ## Core Advantages
6
+
7
+ - **Faster First Screen**: Server-side pre-rendering allows the browser to display content directly without waiting for JavaScript execution
8
+ - **Better SEO**: Search engines can directly index complete HTML content
9
+ - **Out of the Box**: No need to write complex server-side logic or maintain separate services
10
+
11
+ :::info Default Rendering Mode
12
+ Modern.js SSR **uses streaming rendering (Streaming SSR) by default**, allowing pages to be returned progressively as they render, so users can see initial content faster.
13
+
14
+ For detailed usage, refer to the [Streaming SSR](/guides/basic-features/render/streaming-ssr.md) documentation.
15
+
16
+ To switch to traditional SSR mode (waiting for all data to load before returning at once), you can configure:
17
+
18
+ ```ts title="modern.config.ts"
19
+ import { defineConfig } from '@modern-js/app-tools';
20
+
21
+ export default defineConfig({
22
+ server: {
23
+ ssr: {
24
+ mode: 'string', // Traditional SSR mode
25
+ },
26
+ },
27
+ });
28
+ ```
29
+
30
+ :::
31
+
32
+ ## Enabling SSR
33
+
34
+ Enabling SSR in Modern.js is straightforward. Simply set [`server.ssr`](/configure/app/server/ssr.md) to `true`:
35
+
36
+ ```ts title="modern.config.ts"
37
+ import { defineConfig } from '@modern-js/app-tools';
38
+
39
+ export default defineConfig({
40
+ server: {
41
+ ssr: true, // Streaming rendering enabled by default
42
+ },
43
+ });
44
+ ```
45
+
46
+ ## Data Fetching
47
+
48
+ Modern.js provides Data Loader, enabling developers to fetch data isomorphically under both SSR and CSR. Each route module (such as `layout.tsx` and `page.tsx`) can define its own Data Loader:
49
+
50
+ :::tip Learn More
51
+ The following approach will not have streaming rendering effects. To achieve streaming rendering effects, refer to [Streaming SSR](/guides/basic-features/render/streaming-ssr.md).
52
+
53
+ :::
54
+
55
+ ```ts title="src/routes/page.data.ts"
56
+ export const loader = () => {
57
+ return {
58
+ message: 'Hello World',
59
+ };
60
+ };
61
+ ```
62
+
63
+ Access data in components through Hooks API:
64
+
65
+ ```tsx
66
+ import { useLoaderData } from '@modern-js/runtime/router';
67
+ export default () => {
68
+ const data = useLoaderData();
69
+ return <div>{data.message}</div>;
70
+ };
71
+ ```
72
+
73
+ ### Using Client Loader
74
+
75
+ By default, in SSR applications, the `loader` function only executes on the server. However, in some scenarios, developers might want requests made on the client-side to bypass the SSR service and directly fetch data from the source. For example:
76
+
77
+ 1. Reducing network consumption on the client-side by directly fetching from the data source.
78
+ 2. The application has data cached on the client side and doesn't want to fetch data from the SSR service.
79
+
80
+ Modern.js supports adding a `.data.client` file, also named exported as `loader`, in SSR applications. If the Data Loader fails to execute on the server side, or when navigating on the client side, it will execute the `loader` function on the client side instead of sending a data request to the SSR service.
81
+
82
+ ```ts title="page.data.client.ts"
83
+ import cache from 'my-cache';
84
+
85
+ export async function loader({ params }) {
86
+ if (cache.has(params.id)) {
87
+ return cache.get(params.id);
88
+ }
89
+ const res = await fetch(`URL_ADDRESS?id=${params.id}`);
90
+ const data = await res.json();
91
+ return {
92
+ message: data.message,
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## SSR Fallback
98
+
99
+ In Modern.js, if an application encounters an error during SSR, it automatically falls back to CSR mode and re-fetches data, ensuring the page can display correctly. SSR fallback can occur for two main reasons:
100
+
101
+ 1. Data Loader execution error.
102
+ 2. React component rendering error on the server side.
103
+
104
+ ### Data Loader Execution Error
105
+
106
+ By default, if the `loader` function for a route throws an error, the framework renders the `<ErrorBoundary>` component directly on the server, displaying the error message. This is the default behavior of most frameworks.
107
+
108
+ Modern.js also supports customizing the fallback strategy through the `loaderFailureMode` field in the [`server.ssr`](/configure/app/server/ssr.md) configuration. Setting this field to `clientRender` immediately falls back to CSR mode and re-fetches the data.
109
+
110
+ If a Client Loader is defined for the route, it will be used to re-fetch the data. If re-rendering fails again, the `<ErrorBoundary>` component will be displayed.
111
+
112
+
113
+ ### Component Rendering Error
114
+
115
+ If the Data Loader executes correctly but the component rendering fails, SSR rendering will partially or completely fail, as shown in the following code:
116
+
117
+ ```tsx
118
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
119
+ import { Suspense } from 'react';
120
+
121
+ const Page = () => {
122
+ const data = useLoaderData();
123
+ const isNode = typeof window === 'undefined';
124
+ const undefinedVars = data.unDefined;
125
+ const definedVars = data.defined;
126
+
127
+ return (
128
+ <div>
129
+ {isNode ? undefinedVars.msg : definedVars.msg}
130
+ </div>
131
+ );
132
+ };
133
+
134
+ export default Page;
135
+ ```
136
+
137
+ In this case, Modern.js will fallback the page to CSR and use the existing data from the Data Loader to render. If the rendering still fails, the `<ErrorBoundary>` component will be rendered.
138
+
139
+ :::tip
140
+ The behavior of component rendering errors is unaffected by `loaderFailureMode` and will not execute the Client Loader on the browser side.
141
+ :::
142
+
143
+
144
+ ## Logging and Monitoring
145
+
146
+ :::tip
147
+ SSR monitoring has been integrated into the Monitors module, see [Monitors](/guides/advanced-features/server-monitor/monitors.md) for details.
148
+ :::
149
+
150
+ ## Page Caching
151
+
152
+ Modern.js has built-in caching capabilities. Refer to [Rendering Cache](/guides/basic-features/render/ssr-cache.md) for details.
153
+
154
+ ## Differences in Runtime Environment
155
+
156
+ SSR applications run on both the server and the client, with differing Web and Node APIs.
157
+
158
+ When enabling SSR, Modern.js uses the same entry to build both SSR and CSR bundles. Therefore, having Web APIs in the SSR bundle or Node APIs in the CSR bundle can lead to runtime errors. This usually happens in two scenarios:
159
+
160
+ - There are issues in the application's own code.
161
+ - The dependency package contains side effects.
162
+
163
+ ### Issues with Own Code
164
+
165
+ This scenario often arises when migrating from CSR to SSR. CSR applications typically import Web APIs in the code. For example, an application might set up global event listeners:
166
+
167
+ ```tsx
168
+ document.addEventListener('load', () => {
169
+ console.log('document load');
170
+ });
171
+ const App = () => {
172
+ return <div>Hello World</div>;
173
+ };
174
+ export default App;
175
+ ```
176
+
177
+ In such cases, you can use Modern.js built-in environment variables `MODERN_TARGET` to remove unused code during the build:
178
+
179
+ ```ts
180
+ if (process.env.MODERN_TARGET === 'browser') {
181
+ document.addEventListener('load', () => {
182
+ console.log('document load');
183
+ });
184
+ }
185
+ ```
186
+
187
+ After packing in the development environment, the SSR and CSR bundles will compile as follows. Therefore, Web API errors will not occur in the SSR environment:
188
+
189
+ ```ts
190
+ // SSR Bundle
191
+ if (false) {
192
+ }
193
+
194
+ // CSR Bundle
195
+ if (true) {
196
+ document.addEventListener('load', () => {
197
+ console.log('document load');
198
+ });
199
+ }
200
+ ```
201
+
202
+ :::note
203
+ For more information, see [Environment Variables](/guides/basic-features/env-vars.md).
204
+ :::
205
+
206
+ ### Side Effects in Dependencies
207
+
208
+ This scenario can occur at any time in SSR applications because not all community packages support running in both environments. Some packages only need to run in one. For instance, importing package A that has a side effect using Web APIs:
209
+
210
+ ```ts title="packageA"
211
+ document.addEventListener('load', () => {
212
+ console.log('document load');
213
+ });
214
+
215
+ export const doSomething = () => {}
216
+ ```
217
+
218
+ Directly referencing this in a component will cause SSR to throw errors, even if you use environment variables to conditionally load the code. The side effects in the dependency will still execute.
219
+
220
+ ```tsx title="routes/page.tsx"
221
+ import { doSomething } from 'packageA';
222
+
223
+ export const Page = () => {
224
+ if (process.env.MODERN_TARGET === 'browser') {
225
+ doSomething();
226
+ }
227
+ return <div>Hello World</div>
228
+ }
229
+ ```
230
+
231
+ Modern.js supports distinguishing between SSR and CSR bundles by using `.server.` suffix files. You can create `.ts` and `.server.ts` files with the same name to create a proxy:
232
+
233
+ ```ts title="a.ts"
234
+ export { doSomething } from 'packageA';
235
+ ```
236
+
237
+ ```ts title="a.server.ts"
238
+ export const doSomething: any = () => {};
239
+ ```
240
+
241
+ Import `./a` in the file, and the SSR bundle will prioritize the `.server.ts` files, while the CSR bundle will prioritize the `.ts` files.
242
+
243
+ ```tsx title="routes/page.tsx"
244
+ import { doSomething } from './a'
245
+
246
+ export const Page = () => {
247
+ doSomething();
248
+ return <div>Hello World</div>
249
+ }
250
+ ```
251
+
252
+ ## Common Issues
253
+
254
+ ### Ensuring Consistent Rendering
255
+
256
+ In SSR applications, it is crucial to ensure that the rendering results on the server are consistent with the hydration results in the browser. Inconsistent rendering may lead to unexpected outcomes. Here’s an example demonstrating issues when SSR and CSR render differently. Add the following code to your component:
257
+
258
+ ```tsx
259
+ {
260
+ typeof window !== 'undefined' ? <div>browser content</div> : null;
261
+ }
262
+ ```
263
+
264
+ After starting the application and visiting the page, you will notice a warning in the browser console:
265
+
266
+ ```sh
267
+ Warning: Expected server HTML to contain a matching <div> in <div>.
268
+ ```
269
+
270
+ This warning is caused by a mismatch between the React hydrate results and the SSR rendering results. Although the current page appears normal, complex applications may experience DOM hierarchy disruptions or style issues.
271
+
272
+ :::info
273
+ For more information on React hydrate logic, refer to [here](https://zh-hans.react.dev/reference/react-dom/hydrate).
274
+ :::
275
+
276
+ The application needs to maintain consistency between SSR and CSR rendering results. If inconsistencies occur, it indicates that some content should not be rendered by SSR. Modern.js provides the `<NoSSR>` utility component for such scenarios:
277
+
278
+ ```ts
279
+ import { NoSSR } from '@modern-js/runtime/ssr';
280
+ ```
281
+
282
+ Wrap elements that should not be server-side rendered with the `NoSSR` component:
283
+
284
+ ```tsx
285
+ <NoSSR>
286
+ <div>browser content</div>
287
+ </NoSSR>
288
+ ```
289
+
290
+ After modifying the code, refresh the page and notice that the previous warning has disappeared. Open the browser's developer tools and check the Network tab. The returned HTML document will not contain the content wrapped by the `NoSSR` component.
291
+
292
+ In practical scenarios, some UI displays might be affected by the user's device, such as [UA](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent) information. Modern.js also provides APIs like `use(RuntimeContext)`, allowing components to access complete request information and maintaining SSR and CSR rendering consistency. For detailed usage, please refer to [Runtime Context](/guides/basic-features/render/before-render.md#runtime-context).
293
+
294
+ ### Attention to Memory Leaks
295
+
296
+ :::warning Alert
297
+ In SSR scenarios, developers need to pay special attention to memory leaks. Even minor memory leaks can significantly impact services after many requests.
298
+ :::
299
+
300
+ With SSR, each browser request triggers server-side component rendering. Therefore, you should avoid defining any data structures that continually grow globally, subscribing to global events, or creating non-disposable streams.
301
+
302
+ For example, when using [redux-observable](https://redux-observable.js.org/), developers accustomed to CSR might code as follows:
303
+
304
+ ```tsx
305
+ /* Code is just an example and not executable */
306
+ import { createEpicMiddleware, combineEpics } from 'redux-observable';
307
+
308
+ const epicMiddleware = createEpicMiddleware();
309
+ const rootEpic = combineEpics();
310
+
311
+ export default function Test() {
312
+ epicMiddleware.run(rootEpic);
313
+ return <div>Hello Modern.js</div>;
314
+ }
315
+ ```
316
+
317
+ In this case, the `epicMiddleware` instance is created outside the component, and `epicMiddleware.run` is called within the component.
318
+
319
+ This code does not cause issues on the client-side. However, in SSR, the Middleware instance remains non-disposable. Each time the component renders, calling `epicMiddleware.run(rootEpic)` adds new event bindings internally, causing the entire object to grow continuously, ultimately affecting application performance.
320
+
321
+ Such issues are not easily noticed in CSR. When transitioning from CSR to SSR, if you're unsure whether your application has such hidden pitfalls, consider stress testing the application.
@@ -0,0 +1,264 @@
1
+ # Streaming Server-Side Rendering
2
+
3
+ Streaming rendering is an advanced rendering method that progressively returns content during the page rendering process, significantly improving user experience.
4
+
5
+ In traditional SSR rendering, the page is rendered all at once, requiring all data to be loaded before returning the complete HTML. In streaming rendering, the page is rendered progressively, allowing content to be returned as it renders, so users can see initial content faster.
6
+
7
+ :::info Default Mode
8
+ **Streaming SSR is the default rendering mode for Modern.js SSR**. When you enable SSR, streaming rendering is available without additional configuration.
9
+
10
+ If you need to switch to traditional SSR mode (waiting for all data to load before returning at once), you can configure `server.ssr.mode` to `'string'`. For detailed information, refer to the [Server-Side Rendering (SSR)](/guides/basic-features/render/ssr.md) documentation.
11
+ :::
12
+
13
+ Compared to traditional SSR rendering:
14
+
15
+ - **Faster Perceived Speed**: Streaming rendering can progressively display content, quickly rendering the home page.
16
+ - **Enhanced User Experience**: Users can see page content faster and interact without waiting for the entire page to render.
17
+ - **Better Performance Control**: Developers can better control the loading priority and order, optimizing performance and user experience.
18
+ - **Better Adaptability**: Streaming rendering adapts better to various network speeds and device performance, ensuring good performance across different environments.
19
+
20
+ ## Enabling Streaming Rendering
21
+
22
+ Modern.js supports React 18+ streaming rendering. When you enable SSR, streaming rendering is enabled by default:
23
+
24
+ ```ts title="modern.config.ts"
25
+ import { defineConfig } from '@modern-js/app-tools';
26
+
27
+ export default defineConfig({
28
+ server: {
29
+ ssr: true, // Streaming rendering enabled by default
30
+ },
31
+ });
32
+ ```
33
+
34
+ If you need to explicitly specify streaming rendering mode, you can configure:
35
+
36
+ ```ts title="modern.config.ts"
37
+ import { defineConfig } from '@modern-js/app-tools';
38
+
39
+ export default defineConfig({
40
+ server: {
41
+ ssr: {
42
+ mode: 'stream', // Explicitly specify streaming rendering mode
43
+ },
44
+ },
45
+ });
46
+ ```
47
+
48
+ Modern.js streaming rendering is based on React Router and involves several key APIs:
49
+
50
+ - [`Await`](https://reactrouter.com/en/main/components/await): Used to render the asynchronous data returned by the Data Loader.
51
+ - [`useAsyncValue`](https://reactrouter.com/en/main/hooks/use-async-value): Used to fetch data from the nearest parent `Await` component.
52
+
53
+ ## Fetching Data
54
+
55
+ ```ts title="user/[id]/page.data.ts"
56
+ import { defer, type LoaderFunctionArgs } from '@modern-js/runtime/router';
57
+
58
+ interface User {
59
+ name: string;
60
+ age: number;
61
+ }
62
+
63
+ export interface Data {
64
+ data: User;
65
+ }
66
+
67
+ export const loader = ({ params }: LoaderFunctionArgs) => {
68
+ const userId = params.id;
69
+
70
+ const user = new Promise<User>(resolve => {
71
+ setTimeout(() => {
72
+ resolve({
73
+ name: `user-${userId}`,
74
+ age: 18,
75
+ });
76
+ }, 200);
77
+ });
78
+
79
+ return defer({ data: user });
80
+ };
81
+ ```
82
+
83
+ Here, `user` is a Promise object representing asynchronously fetched data, processed using `defer`. Notice that `defer` must receive an object parameter; a direct Promise cannot be passed.
84
+
85
+ Additionally, `defer` can receive both asynchronous and synchronous data. In the example below, short-duration requests are returned using object data, while longer-duration requests are returned using a Promise:
86
+
87
+ ```ts title="user/[id]/page.data.ts"
88
+ export const loader = async ({ params }: LoaderFunctionArgs) => {
89
+ const userId = params.id;
90
+
91
+ const user = new Promise<User>(resolve => {
92
+ setTimeout(() => {
93
+ resolve({
94
+ name: `user-${userId}`,
95
+ age: 18,
96
+ });
97
+ }, 2000);
98
+ });
99
+
100
+ const otherData = new Promise<string>(resolve => {
101
+ setTimeout(() => {
102
+ resolve('some sync data');
103
+ }, 200);
104
+ });
105
+
106
+ return defer({
107
+ data: user,
108
+ other: await otherData,
109
+ });
110
+ };
111
+ ```
112
+
113
+ This way, the application can prioritize displaying partially available content without waiting for the most time-consuming data requests.
114
+
115
+ ## Rendering Data
116
+
117
+ To render the asynchronous data returned by the Data Loader, use the `Await` component. For example:
118
+
119
+ ```tsx title="user/[id]/page.tsx"
120
+ import { Await, useLoaderData } from '@modern-js/runtime/router';
121
+ import { Suspense } from 'react';
122
+ import type { Data } from './page.data';
123
+
124
+ const Page = () => {
125
+ const data = useLoaderData() as Data;
126
+
127
+ return (
128
+ <div>
129
+ User info:
130
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
131
+ <Await resolve={data.data}>
132
+ {user => {
133
+ return (
134
+ <div id="data">
135
+ name: {user.name}, age: {user.age}
136
+ </div>
137
+ );
138
+ }}
139
+ </Await>
140
+ </Suspense>
141
+ </div>
142
+ );
143
+ };
144
+
145
+ export default Page;
146
+ ```
147
+
148
+ The `Await` component needs to be wrapped inside a `Suspense` component. The `resolve` prop of `Await` should be the asynchronously fetched data from the Data Loader. When the data is fetched, it will be rendered using the [Render Props](https://zh-hans.react.dev/reference/react/cloneElement#passing-data-with-a-render-prop) pattern. During data fetching, the content set by the `fallback` prop of `Suspense` is displayed.
149
+
150
+ :::warning Warning
151
+ When importing types from the `page.data.ts` file, use `import type` to ensure only type information is imported, preventing Data Loader code from being bundled into the frontend.
152
+ :::
153
+
154
+ In the component, you can also fetch asynchronous data returned by the Data Loader using `useAsyncValue`. For example:
155
+
156
+ ```tsx title='page.tsx'
157
+ import { useAsyncValue } from '@modern-js/runtime/router';
158
+
159
+ const UserInfo = () => {
160
+ const user = useAsyncValue();
161
+ return (
162
+ <div>
163
+ name: {user.name}, age: {user.age}
164
+ </div>
165
+ );
166
+ };
167
+
168
+ const Page = () => {
169
+ const data = useLoaderData() as Data;
170
+ return (
171
+ <div>
172
+ User info:
173
+ <Suspense fallback={<div id="loading">loading user data ...</div>}>
174
+ <Await resolve={data.data}>
175
+ <UserInfo />
176
+ </Await>
177
+ </Suspense>
178
+ </div>
179
+ );
180
+ };
181
+
182
+ export default Page;
183
+ ```
184
+
185
+ ## Error Handling
186
+
187
+ The `errorElement` prop of the `Await` component handles errors in Data Loader or sub-component rendering. For example, intentionally throwing an error in the Data Loader function:
188
+
189
+ ```ts title="page.loader.ts"
190
+ import { defer } from '@modern-js/runtime/router';
191
+
192
+ export default () => {
193
+ const data = new Promise((resolve, reject) => {
194
+ setTimeout(() => {
195
+ reject(new Error('error occurs'));
196
+ }, 200);
197
+ });
198
+
199
+ return defer({ data });
200
+ };
201
+ ```
202
+
203
+ Then, fetch the error using `useAsyncError` and set a component to render the error message for the `errorElement` prop of the `Await` component:
204
+
205
+ ```tsx title="page.ts"
206
+ import { Await, useAsyncError, useLoaderData } from '@modern-js/runtime/router';
207
+ import { Suspense } from 'react';
208
+
209
+ export default function Page() {
210
+ const data = useLoaderData();
211
+
212
+ return (
213
+ <div>
214
+ Error page
215
+ <Suspense fallback={<div>loading ...</div>}>
216
+ <Await resolve={data.data} errorElement={<ErrorElement />}>
217
+ {(data: any) => {
218
+ return <div>never displayed</div>;
219
+ }}
220
+ </Await>
221
+ </Suspense>
222
+ </div>
223
+ );
224
+ }
225
+
226
+ function ErrorElement() {
227
+ const error = useAsyncError() as Error;
228
+ return <p>Something went wrong! {error.message}</p>;
229
+ }
230
+ ```
231
+
232
+ ## Controlling When to Wait for Full HTML
233
+
234
+ Streaming improves perceived speed, but in some cases (SEO crawlers, A/B buckets, compliance pages) you may want to wait for all content before sending the response.
235
+
236
+ Modern.js decides the streaming mode with this priority:
237
+
238
+ 1. Request header `x-should-stream-all` (set per-request in middleware).
239
+ 2. Env `MODERN_JS_STREAM_TO_STRING` (forces full HTML).
240
+ 3. [isbot](https://www.npmjs.com/package/isbot) check on `user-agent` (bots get full HTML).
241
+ 4. Default: stream shell first.
242
+
243
+ Set the header in your middleware to choose the behavior dynamically:
244
+
245
+ ```ts title="middleware example"
246
+ export const middleware = async (ctx, next) => {
247
+ const ua = ctx.req.header('user-agent') || '';
248
+ const shouldWaitAll = /Lighthouse|Googlebot/i.test(ua) || ctx.req.path === '/marketing';
249
+
250
+ // Write a boolean string: true -> onAllReady, false -> onShellReady
251
+ ctx.req.headers.set('x-should-stream-all', String(shouldWaitAll));
252
+
253
+ await next();
254
+ };
255
+ ```
256
+
257
+
258
+ ## Related Documentation
259
+
260
+ - [Rendering Mode Overview](/guides/basic-features/render/overview.md)
261
+ - [Server-Side Rendering (SSR)](/guides/basic-features/render/ssr.md)
262
+ - [Rendering Cache](/guides/basic-features/render/ssr-cache.md)
263
+ - [React Server Components (RSC)](/guides/basic-features/render/rsc.md) - Use with Streaming SSR
264
+ - [New Suspense SSR Architecture in React 18](https://github.com/reactwg/react-18/discussions/37) - React 18 Architecture Overview