@modern-js/app-tools 3.6.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +48 -15
@@ -0,0 +1,27 @@
1
+ # Using Tailwind CSS
2
+
3
+ [Tailwind CSS](https://tailwindcss.com/) is a CSS framework and design system based on Utility Class, which can quickly add common styles to components, and support flexible extension of theme styles.
4
+
5
+ ## Using Tailwind CSS in Modern.js
6
+
7
+ To use [Tailwind CSS](https://tailwindcss.com/) in Modern.js, you only need to configure it according to the Rsbuild steps. Rsbuild supports Tailwind CSS versions v3 and v4:
8
+
9
+ - [Tailwind CSS v3](https://v2.rsbuild.rs/guide/styling/tailwindcss-v3#tailwind-css-v3)
10
+ - [Tailwind CSS v4](https://v2.rsbuild.rs/guide/styling/tailwindcss)
11
+
12
+ ## Tailwind CSS Autocomplete
13
+
14
+ Tailwind CSS provides an official extension called [Tailwind CSS IntelliSense](https://github.com/tailwindlabs/tailwindcss-intellisense) for autocompletion of Tailwind CSS class names, CSS functions, and directives in VS Code.
15
+
16
+ You can follow the steps below to enable the autocomplete feature:
17
+
18
+ 1. Install the [Tailwind CSS IntelliSense](https://github.com/tailwindlabs/tailwindcss-intellisense) extension in VS Code.
19
+ 2. If the root directory of your project does not have a `tailwind.config.{ts,js}` file, you need to create one and write the Tailwind CSS configuration for your current project. Otherwise, the IDE plugin will not work correctly.
20
+
21
+ ## Browser Compatibility
22
+
23
+ Tailwind CSS v3 does not support the IE 11 browser, please refer to:
24
+
25
+ - [Tailwind CSS v3 - Browser Support](https://tailwindcss.com/docs/browser-support).
26
+
27
+ If you use Tailwind CSS on IE 11 browser, some styles may not be available, please use it with caution.
@@ -0,0 +1,510 @@
1
+ # Data Caching
2
+
3
+ The `cache` function allows you to cache the results of data fetching or computation, Compared to full-page [rendering cache](/guides/basic-features/render/ssr-cache.md), it provides more fine-grained control over data granularity and is applicable to various scenarios such as Client-Side Rendering (CSR), Server-Side Rendering (SSR), and API services (BFF).
4
+
5
+ ## Basic Usage
6
+
7
+ :::note
8
+
9
+ If you use the `cache` function in BFF, you should import the cache funtion from `@modern-js/server-runtime/cache`
10
+
11
+ `import { cache } from '@modern-js/server-runtime/cache'`
12
+
13
+ :::
14
+
15
+ ```ts
16
+ import { cache } from '@modern-js/runtime/cache';
17
+ import { fetchUserData } from './api';
18
+
19
+ const getUser = cache(fetchUserData);
20
+
21
+ const loader = async () => {
22
+ const user = await getUser('123'); // When the parameters of the function changes, the function will be re-executed
23
+ return {
24
+ user,
25
+ };
26
+ };
27
+ ```
28
+
29
+ ### Parameters
30
+
31
+ - `fn`: The data fetching or computation function to be cached
32
+ - `options` (optional): Cache configuration
33
+ - `tag`: Tag to identify the cache, which can be used to invalidate the cache
34
+ - `maxAge`: Cache validity period (milliseconds)
35
+ - `revalidate`: Time window for revalidating the cache (milliseconds), similar to HTTP Cache-Control's stale-while-revalidate functionality
36
+ - `getKey`: Simplified cache key generation function based on function parameters
37
+ - `customKey`: Custom cache key generation function, used to maintain cache when function references change
38
+
39
+ The type of the `options` parameter is as follows:
40
+
41
+ ```ts
42
+ interface CacheOptions {
43
+ tag?: string | string[];
44
+ maxAge?: number;
45
+ revalidate?: number;
46
+ getKey?: <Args extends any[]>(...args: Args) => string;
47
+ customKey?: <Args extends any[]>(options: {
48
+ params: Args;
49
+ fn: (...args: Args) => any;
50
+ generatedKey: string;
51
+ }) => string | symbol;
52
+ }
53
+ ```
54
+
55
+ ### Return Value
56
+
57
+ The `cache` function returns a new function with caching capabilities. Multiple calls to this function will not re-execute the `fn` function.
58
+
59
+ ## Usage Scope
60
+
61
+ Unlike React's [cache](https://react.dev/reference/react/cache) function which can only be used in server components,
62
+ Modern.js's `cache` function can be used in any frontend or server-side code.
63
+
64
+ ## Detailed Usage
65
+
66
+ ### Without options Parameter
67
+
68
+ When no `options` parameter is provided, it's primarily useful in SSR projects, the cache lifecycle is limited to a single SSR rendering request. For example, when the same cachedFn is called in multiple data loaders, the cachedFn function won't be executed repeatedly. This allows data sharing between different data loaders while avoiding duplicate requests. Modern.js will re-execute the `fn` function with each server request.
69
+
70
+ :::info
71
+ Without the `options` parameter, it can be considered a replacement for React's [`cache`](https://react.dev/reference/react/cache) function and can be used in any server-side code (such as in data loaders of SSR projects), not limited to server components.
72
+ :::
73
+
74
+ ```ts
75
+ import { cache } from '@modern-js/runtime/cache';
76
+ import { fetchUserData } from './api';
77
+
78
+ const getUser = cache(fetchUserData);
79
+
80
+ const loader = async () => {
81
+ const user = await getUser();
82
+ return {
83
+ user,
84
+ };
85
+ };
86
+ ```
87
+
88
+ ### With options Parameter
89
+
90
+ #### `maxAge` Parameter
91
+
92
+ After each computation, the framework records the time when the cache is written.
93
+ When the function is called again, it checks if the cache has expired based on the `maxAge` parameter.
94
+ If expired, the `fn` function is re-executed; otherwise, the cached data is returned.
95
+
96
+ ```ts
97
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
98
+
99
+ const getDashboardStats = cache(
100
+ async () => {
101
+ return await fetchComplexStatistics();
102
+ },
103
+ {
104
+ maxAge: CacheTime.MINUTE * 2, // Calling this function within 2 minutes will return cached data
105
+ },
106
+ );
107
+ ```
108
+
109
+ #### `revalidate` Parameter
110
+
111
+ The `revalidate` parameter sets a time window for revalidating the cache after it expires. It can be used together with the `maxAge` parameter, similar to HTTP Cache-Control's stale-while-revalidate mode.
112
+
113
+ In the following example, the cache behavior is divided into three phases based on time:
114
+
115
+ 1. **0 to 2 minutes (within `maxAge`)**: Cache is fresh, returns cached data directly without re-fetching
116
+ 2. **2 to 3 minutes (between `maxAge` and `maxAge + revalidate`)**: Cache has expired but is within the revalidation window, returns stale data immediately while re-fetching and updating the cache in the background
117
+ 3. **Beyond 3 minutes (exceeding `maxAge + revalidate`)**: Cache is completely expired, re-executes the function to fetch new data
118
+
119
+ ```ts
120
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
121
+
122
+ const getDashboardStats = cache(
123
+ async () => {
124
+ return await fetchComplexStatistics();
125
+ },
126
+ {
127
+ maxAge: CacheTime.MINUTE * 2,
128
+ revalidate: CacheTime.MINUTE * 1,
129
+ },
130
+ );
131
+ ```
132
+
133
+ #### `tag` Parameter
134
+
135
+ The `tag` parameter identifies the cache with a tag, which can be a string or an array of strings.
136
+ You can invalidate caches based on this tag, and multiple cache functions can use the same tag.
137
+
138
+ ```ts
139
+ import { cache, revalidateTag } from '@modern-js/runtime/cache';
140
+
141
+ const getDashboardStats = cache(
142
+ async () => {
143
+ return await fetchDashboardStats();
144
+ },
145
+ {
146
+ tag: 'dashboard',
147
+ },
148
+ );
149
+
150
+ const getComplexStatistics = cache(
151
+ async () => {
152
+ return await fetchComplexStatistics();
153
+ },
154
+ {
155
+ tag: 'dashboard',
156
+ },
157
+ );
158
+
159
+ await revalidateTag('dashboard'); // Invalidates the cache for both getDashboardStats and getComplexStatistics functions
160
+ ```
161
+
162
+ #### `getKey` Parameter
163
+
164
+ The `getKey` parameter simplifies cache key generation, especially useful when you only need to rely on part of the function parameters to differentiate caches. It's a function that receives the same parameters as the original function and returns a string.
165
+
166
+ Its return value becomes part of the final cache key, but the key is still combined with a unique function identifier, making the cache **function-scoped**.
167
+
168
+ ```ts
169
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
170
+ import { fetchUserData } from './api';
171
+
172
+ const getUser = cache(
173
+ async (userId, options) => {
174
+ // Here options might contain many configurations, but we only want to cache based on userId
175
+ return await fetchUserData(userId, options);
176
+ },
177
+ {
178
+ maxAge: CacheTime.MINUTE * 5,
179
+ // Only use the first parameter (userId) as the cache key
180
+ getKey: (userId, options) => userId,
181
+ },
182
+ );
183
+
184
+ // The following two calls will share the cache because getKey only uses userId
185
+ await getUser(123, { language: 'zh' });
186
+ await getUser(123, { language: 'en' }); // Cache hit, won't request again
187
+
188
+ // Different userId will use different cache
189
+ await getUser(456, { language: 'zh' }); // Won't hit cache, will request again
190
+ ```
191
+
192
+ You can also use Modern.js's `generateKey` function together with getKey to generate the cache key:
193
+
194
+ :::info
195
+
196
+ The `generateKey` function in Modern.js ensures that a consistent and unique key is generated even if object property orders change, guaranteeing stable caching.
197
+
198
+ :::
199
+
200
+ ```ts
201
+ import { cache, CacheTime, generateKey } from '@modern-js/runtime/cache';
202
+ import { fetchUserData } from './api';
203
+
204
+ const getUser = cache(
205
+ async (userId, options) => {
206
+ return await fetchUserData(userId, options);
207
+ },
208
+ {
209
+ maxAge: CacheTime.MINUTE * 5,
210
+ getKey: (userId, options) => generateKey(userId),
211
+ },
212
+ );
213
+ ```
214
+
215
+ Additionally, `getKey` can also return a numeric type as a cache key:
216
+
217
+ ```ts
218
+ const getUserById = cache(fetchUserDataById, {
219
+ maxAge: CacheTime.MINUTE * 5,
220
+ // Directly use the numeric ID as the cache key
221
+ getKey: id => id,
222
+ });
223
+
224
+ await getUserById(42); // Uses 42 as the cache key
225
+ ```
226
+
227
+ #### `customKey` parameter
228
+
229
+ The `customKey` parameter is used to **fully customize** the cache key. It is a function that receives an object with the following properties and returns a string as the cache key.
230
+
231
+ Its return value **directly becomes** the final cache key, **overriding** the default combination of a function identifier and parameter-based key. This allows you to create **globally unique** keys and share cache across different functions.
232
+
233
+ - `params`: Array of arguments passed to the cached function
234
+ - `fn`: Reference to the original function being cached
235
+ - `generatedKey`: Cache key automatically generated by the framework based on input parameters
236
+
237
+ :::info
238
+
239
+ Generally, the cache will be invalidated in the following scenarios:
240
+
241
+ 1. The function's input parameters change
242
+ 2. The maxAge condition is no longer satisfied
243
+ 3. The `revalidateTag` method has been called
244
+
245
+ By default, the framework generates a stable function ID based on the function's string representation and combines it with the generated parameter key. `customKey` can be used when you need complete control over the cache key generation, especially useful for sharing cache across different function instances. If you just need to customize how parameters are converted to cache keys, it is recommended to use `getKey`.
246
+
247
+ :::
248
+
249
+ This is very useful in some scenarios, such as when you want to share cache across different function instances or when you need predictable cache keys for external cache management.
250
+
251
+ ```ts
252
+ import { cache } from '@modern-js/runtime/cache';
253
+ import { fetchUserData } from './api';
254
+
255
+ // Different function references, but share the same cache via customKey
256
+ const getUserA = cache(fetchUserData, {
257
+ maxAge: CacheTime.MINUTE * 5,
258
+ customKey: ({ params }) => {
259
+ // Return a stable string as the cache key
260
+ return `user-${params[0]}`;
261
+ },
262
+ });
263
+
264
+ // Even if the function reference changes,
265
+ // as long as customKey returns the same value, the cache will be hit
266
+ const getUserB = cache(
267
+ (...args) => fetchUserData(...args), // New function reference
268
+ {
269
+ maxAge: CacheTime.MINUTE * 5,
270
+ customKey: ({ params }) => {
271
+ // Return the same key as getUserA
272
+ return `user-${params[0]}`;
273
+ },
274
+ },
275
+ );
276
+
277
+ // Now you can share cache across different function implementations
278
+ await getUserA(123); // Fetches data and caches with key "user-123"
279
+ await getUserB(123); // Cache hit, returns cached data
280
+
281
+ // You can utilize the generatedKey parameter to modify the default key
282
+ const getUserC = cache(fetchUserData, {
283
+ customKey: ({ generatedKey }) => `prefix-${generatedKey}`,
284
+ });
285
+
286
+ // For predictable cache keys that can be managed externally
287
+ const getUserD = cache(
288
+ async (userId: string) => {
289
+ return await fetchUserData(userId);
290
+ },
291
+ {
292
+ maxAge: CacheTime.MINUTE * 5,
293
+ customKey: ({ params }) => `app:user:${params[0]}`,
294
+ },
295
+ );
296
+ ```
297
+
298
+ #### `onCache` Parameter
299
+
300
+ The `onCache` parameter allows you to track cache statistics such as hit rate. It's a callback function that receives information about each cache operation, including the status, key, parameters, and result.
301
+
302
+ ```ts
303
+ import { cache, CacheTime } from '@modern-js/runtime/cache';
304
+
305
+ // Track cache statistics
306
+ const stats = {
307
+ total: 0,
308
+ hits: 0,
309
+ misses: 0,
310
+ stales: 0,
311
+ hitRate: () => stats.hits / stats.total,
312
+ };
313
+
314
+ const getUser = cache(fetchUserData, {
315
+ maxAge: CacheTime.MINUTE * 5,
316
+ onCache({ status, key, params, result }) {
317
+ // status can be 'hit', 'miss', or 'stale'
318
+ stats.total++;
319
+
320
+ if (status === 'hit') {
321
+ stats.hits++;
322
+ } else if (status === 'miss') {
323
+ stats.misses++;
324
+ } else if (status === 'stale') {
325
+ stats.stales++;
326
+ }
327
+
328
+ console.log(
329
+ `Cache ${
330
+ status === 'hit' ? 'hit' : status === 'miss' ? 'miss' : 'stale'
331
+ } for key: ${String(key)}`,
332
+ );
333
+ console.log(`Current hit rate: ${stats.hitRate() * 100}%`);
334
+ },
335
+ });
336
+
337
+ // Usage example
338
+ await getUser(1); // Cache miss
339
+ await getUser(1); // Cache hit
340
+ await getUser(2); // Cache miss
341
+ ```
342
+
343
+ The `onCache` callback receives an object with the following properties:
344
+
345
+ - `status`: The cache operation status, which can be:
346
+ - `hit`: Cache hit, returning cached content
347
+ - `miss`: Cache miss, executing the function and caching the result
348
+ - `stale`: Cache hit but data is stale, returning cached content while revalidating in the background
349
+ - `key`: The cache key, which is either the result of `customKey` or the default generated key
350
+ - `params`: The parameters passed to the cached function
351
+ - `result`: The result data (either from cache or newly computed)
352
+
353
+ This callback is only invoked when the `options` parameter is provided. When using the cache function without options, the `onCache` callback is not called.
354
+
355
+ The `onCache` callback is useful for:
356
+
357
+ - Monitoring cache performance
358
+ - Calculating hit rates
359
+ - Logging cache operations
360
+ - Implementing custom metrics
361
+
362
+ ### Storage
363
+
364
+ #### Default Storage
365
+
366
+ Currently, both client and server caches are stored in memory.
367
+ The default storage limit for all cached functions is 1GB. When this limit is reached, the oldest cache is removed using an LRU algorithm.
368
+
369
+ :::info
370
+ Considering that the results of `cache` function caching are not large, they are currently stored in memory by default.
371
+ :::
372
+
373
+ You can specify the storage limit using the `configureCache` function:
374
+
375
+ ```ts
376
+ import { configureCache, CacheSize } from '@modern-js/runtime/cache';
377
+
378
+ configureCache({
379
+ maxSize: CacheSize.MB * 10, // 10MB
380
+ });
381
+ ```
382
+
383
+ #### Custom Storage Container
384
+
385
+ In addition to the default memory storage, you can use custom storage containers such as Redis, file systems, databases, etc. This enables cache sharing across processes and servers.
386
+
387
+ ##### Container Interface
388
+
389
+ Custom storage containers need to implement the `Container` interface:
390
+
391
+ ```ts
392
+ interface Container {
393
+ get: (key: string) => Promise<string | undefined | null>;
394
+ set: (key: string, value: string, options?: { ttl?: number }) => Promise<any>;
395
+ has: (key: string) => Promise<boolean>;
396
+ delete: (key: string) => Promise<boolean>;
397
+ clear: () => Promise<void>;
398
+ }
399
+ ```
400
+
401
+ ##### Basic Usage
402
+
403
+ ```ts
404
+ import { configureCache } from '@modern-js/runtime/cache';
405
+
406
+ // Use custom storage container
407
+ configureCache({
408
+ container: customContainer,
409
+ });
410
+ ```
411
+
412
+ ##### Using `customKey` to Ensure Cache Key Stability
413
+
414
+ :::warning Important Recommendation
415
+
416
+ When using custom storage containers (such as Redis), **it's recommended to configure `customKey`** to ensure cache key stability. This ensures:
417
+
418
+ 1. **Cross-process sharing**: Different server instances can share the same cache
419
+ 2. **Cache validity after application restart**: Cache remains valid after restarting the application
420
+ 3. **Cache persistence after code deployment**: Cache for the same logic remains effective after code updates
421
+
422
+ :::
423
+
424
+ The default cache key generation mechanism is based on function references, which may not be stable enough in distributed environments. It's recommended to use `customKey` to provide stable cache keys:
425
+
426
+ ```ts
427
+ import { cache, configureCache } from '@modern-js/runtime/cache';
428
+
429
+ // Configure Redis container
430
+ configureCache({
431
+ container: redisContainer,
432
+ });
433
+
434
+ // Recommended: Use customKey to ensure key stability
435
+ const getUser = cache(
436
+ async (userId: string) => {
437
+ return await fetchUserData(userId);
438
+ },
439
+ {
440
+ maxAge: CacheTime.MINUTE * 5,
441
+ // Use stable identifiers related to the cached function as cache keys
442
+ customKey: () => `fetchUserData`,
443
+ },
444
+ );
445
+ ```
446
+
447
+ ##### Redis Storage Example
448
+
449
+ Here's an example of using Redis as a storage backend:
450
+
451
+ ```ts
452
+ import { Redis } from 'ioredis';
453
+ import { Container, configureCache } from '@modern-js/runtime/cache';
454
+
455
+ class RedisContainer implements Container {
456
+ private client: Redis;
457
+
458
+ constructor(client: Redis) {
459
+ this.client = client;
460
+ }
461
+
462
+ async get(key: string): Promise<string | null> {
463
+ const value = await this.client.get(key);
464
+ return value ? JSON.parse(value) : null;
465
+ }
466
+
467
+ async set(
468
+ key: string,
469
+ value: string,
470
+ options?: { ttl?: number },
471
+ ): Promise<'OK'> {
472
+ if (options?.ttl) {
473
+ return this.client.set(key, JSON.stringify(value), 'EX', options.ttl);
474
+ }
475
+ return this.client.set(key, JSON.stringify(value));
476
+ }
477
+
478
+ async has(key: string): Promise<boolean> {
479
+ const result = await this.client.exists(key);
480
+ return result === 1;
481
+ }
482
+
483
+ async delete(key: string): Promise<boolean> {
484
+ const result = await this.client.del(key);
485
+ return result > 0;
486
+ }
487
+
488
+ async clear(): Promise<void> {
489
+ // Be cautious with this in production. It will clear the entire Redis database.
490
+ // A more robust implementation might use a key prefix and delete keys matching that prefix.
491
+ await this.client.flushdb();
492
+ }
493
+ }
494
+
495
+ // Configure Redis storage
496
+ const redisClient = new Redis({
497
+ host: 'localhost',
498
+ port: 6379,
499
+ });
500
+
501
+ configureCache({
502
+ container: new RedisContainer(redisClient),
503
+ });
504
+ ```
505
+
506
+ ##### Notes
507
+
508
+ 1. **Serialization**: All cached data will be serialized to strings for storage. The container only needs to handle string get/set operations.
509
+
510
+ 2. **TTL Support**: If your storage backend supports TTL (Time To Live), you can use the `options.ttl` parameter in the `set` method (in seconds).