@modern-js/main-doc 3.0.0-alpha.0 → 3.0.0-alpha.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 (142) hide show
  1. package/docs/en/apis/app/commands.mdx +6 -30
  2. package/docs/en/components/bff-upload.mdx +3 -5
  3. package/docs/en/components/bundler.mdx +1 -1
  4. package/docs/en/components/enable-bff.mdx +6 -2
  5. package/docs/en/components/enable-ssg.mdx +1 -0
  6. package/docs/en/components/esbuild.mdx +2 -2
  7. package/docs/en/components/extend-bff-function.mdx +2 -4
  8. package/docs/en/components/hono.mdx +119 -0
  9. package/docs/en/components/international/custom-instance-code.mdx +16 -0
  10. package/docs/en/components/international/init-options-desc.mdx +1 -0
  11. package/docs/en/components/international/install-command.mdx +15 -1
  12. package/docs/en/components/international/instance-code.mdx +26 -0
  13. package/docs/en/configure/app/builder-plugins.mdx +1 -2
  14. package/docs/en/configure/app/dev/server.mdx +108 -0
  15. package/docs/en/configure/app/experiments/source-build.mdx +0 -1
  16. package/docs/en/configure/app/output/assets-retry.mdx +1 -1
  17. package/docs/en/configure/app/output/disable-inline-runtime-chunk.mdx +2 -2
  18. package/docs/en/configure/app/output/filename.mdx +2 -4
  19. package/docs/en/configure/app/output/temp-dir.mdx +3 -3
  20. package/docs/en/configure/app/performance/build-cache.mdx +1 -1
  21. package/docs/en/configure/app/performance/profile.mdx +1 -1
  22. package/docs/en/configure/app/plugins.mdx +1 -3
  23. package/docs/en/configure/app/runtime/router.mdx +0 -4
  24. package/docs/en/configure/app/security/sri.mdx +0 -1
  25. package/docs/en/configure/app/source/alias.mdx +1 -1
  26. package/docs/en/configure/app/source/enable-async-entry.mdx +1 -1
  27. package/docs/en/configure/app/source/include.mdx +2 -14
  28. package/docs/en/configure/app/tools/dev-server.mdx +8 -8
  29. package/docs/en/configure/app/usage.mdx +0 -12
  30. package/docs/en/guides/_meta.json +5 -0
  31. package/docs/en/guides/advanced-features/bff/_meta.json +9 -1
  32. package/docs/en/guides/advanced-features/bff/cross-project.mdx +1 -1
  33. package/docs/en/guides/advanced-features/bff/frameworks.mdx +2 -15
  34. package/docs/en/guides/advanced-features/bff/function.mdx +4 -4
  35. package/docs/en/guides/advanced-features/bff/operators.mdx +628 -0
  36. package/docs/en/guides/advanced-features/bff/sdk.mdx +17 -9
  37. package/docs/en/guides/advanced-features/bff/upload.mdx +3 -1
  38. package/docs/en/guides/advanced-features/international/configuration.mdx +7 -16
  39. package/docs/en/guides/advanced-features/international/quick-start.mdx +4 -32
  40. package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  41. package/docs/en/guides/advanced-features/page-performance/react-compiler.mdx +18 -4
  42. package/docs/en/guides/advanced-features/rspack-start.mdx +1 -1
  43. package/docs/en/guides/advanced-features/server-monitor/monitors.mdx +62 -5
  44. package/docs/en/guides/basic-features/data/data-cache.mdx +60 -76
  45. package/docs/en/guides/basic-features/data/data-fetch.mdx +15 -14
  46. package/docs/en/guides/basic-features/debug/proxy.mdx +6 -9
  47. package/docs/en/guides/basic-features/render/rsc.mdx +24 -19
  48. package/docs/en/guides/basic-features/render/ssg.mdx +4 -9
  49. package/docs/en/guides/basic-features/render/ssr-cache.mdx +0 -4
  50. package/docs/en/guides/basic-features/static-assets/svg-assets.mdx +0 -4
  51. package/docs/en/guides/get-started/tech-stack.mdx +1 -1
  52. package/docs/en/guides/upgrade/_meta.json +1 -0
  53. package/docs/en/guides/upgrade/config.mdx +936 -0
  54. package/docs/en/guides/upgrade/entry.mdx +463 -0
  55. package/docs/en/guides/upgrade/other.mdx +83 -0
  56. package/docs/en/guides/upgrade/overview.mdx +33 -0
  57. package/docs/en/guides/upgrade/tailwindcss.mdx +130 -0
  58. package/docs/en/guides/upgrade/web-server.mdx +91 -0
  59. package/docs/en/plugin/_meta.json +5 -0
  60. package/docs/en/plugin/cli-plugins/_meta.json +1 -1
  61. package/docs/en/plugin/cli-plugins/api.mdx +13 -63
  62. package/docs/en/plugin/cli-plugins/life-cycle.mdx +0 -4
  63. package/docs/en/plugin/introduction.mdx +8 -20
  64. package/docs/en/plugin/plugin-system.mdx +3 -3
  65. package/docs/en/plugin/runtime-plugins/_meta.json +1 -1
  66. package/docs/en/plugin/runtime-plugins/api.mdx +1 -1
  67. package/docs/en/plugin/server-plugins/_meta.json +1 -0
  68. package/docs/en/plugin/server-plugins/api.mdx +210 -1
  69. package/docs/en/plugin/server-plugins/life-cycle.mdx +41 -1
  70. package/docs/zh/apis/app/commands.mdx +6 -30
  71. package/docs/zh/components/bff-operator-code.mdx +5 -0
  72. package/docs/zh/components/bff-upload.mdx +0 -2
  73. package/docs/zh/components/bundler.mdx +1 -1
  74. package/docs/zh/components/enable-bff.mdx +6 -2
  75. package/docs/zh/components/enable-ssg.mdx +3 -1
  76. package/docs/zh/components/esbuild.mdx +2 -2
  77. package/docs/zh/components/extend-bff-function.mdx +2 -4
  78. package/docs/zh/components/hono.mdx +119 -0
  79. package/docs/zh/components/international/custom-instance-code.mdx +16 -0
  80. package/docs/zh/components/international/init-options-desc.mdx +1 -0
  81. package/docs/zh/components/international/install-command.mdx +15 -0
  82. package/docs/zh/components/international/instance-code.mdx +26 -0
  83. package/docs/zh/configure/app/builder-plugins.mdx +1 -2
  84. package/docs/zh/configure/app/dev/server.mdx +109 -2
  85. package/docs/zh/configure/app/experiments/source-build.mdx +0 -1
  86. package/docs/zh/configure/app/output/assets-retry.mdx +1 -1
  87. package/docs/zh/configure/app/output/disable-inline-runtime-chunk.mdx +2 -2
  88. package/docs/zh/configure/app/output/filename.mdx +2 -4
  89. package/docs/zh/configure/app/output/temp-dir.mdx +3 -3
  90. package/docs/zh/configure/app/performance/build-cache.mdx +1 -1
  91. package/docs/zh/configure/app/performance/profile.mdx +1 -1
  92. package/docs/zh/configure/app/plugins.mdx +1 -2
  93. package/docs/zh/configure/app/runtime/router.mdx +0 -4
  94. package/docs/zh/configure/app/security/sri.mdx +0 -1
  95. package/docs/zh/configure/app/source/alias.mdx +1 -1
  96. package/docs/zh/configure/app/source/enable-async-entry.mdx +1 -1
  97. package/docs/zh/configure/app/source/include.mdx +2 -16
  98. package/docs/zh/configure/app/tools/dev-server.mdx +5 -5
  99. package/docs/zh/configure/app/usage.mdx +0 -12
  100. package/docs/zh/guides/advanced-features/bff/_meta.json +9 -1
  101. package/docs/zh/guides/advanced-features/bff/frameworks.mdx +2 -16
  102. package/docs/zh/guides/advanced-features/bff/operators.mdx +628 -0
  103. package/docs/zh/guides/advanced-features/bff/sdk.mdx +19 -12
  104. package/docs/zh/guides/advanced-features/bff/upload.mdx +3 -1
  105. package/docs/zh/guides/advanced-features/international/configuration.mdx +7 -16
  106. package/docs/zh/guides/advanced-features/international/quick-start.mdx +2 -25
  107. package/docs/zh/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
  108. package/docs/zh/guides/advanced-features/page-performance/react-compiler.mdx +18 -4
  109. package/docs/zh/guides/advanced-features/server-monitor/monitors.mdx +60 -5
  110. package/docs/zh/guides/basic-features/data/data-cache.mdx +47 -54
  111. package/docs/zh/guides/basic-features/data/data-fetch.mdx +9 -12
  112. package/docs/zh/guides/basic-features/debug/proxy.mdx +4 -7
  113. package/docs/zh/guides/basic-features/render/rsc.mdx +23 -37
  114. package/docs/zh/guides/basic-features/render/ssr-cache.mdx +0 -4
  115. package/docs/zh/guides/basic-features/static-assets/svg-assets.mdx +0 -4
  116. package/docs/zh/guides/get-started/tech-stack.mdx +1 -1
  117. package/docs/zh/guides/troubleshooting/builder.mdx +1 -1
  118. package/docs/zh/guides/upgrade/config.mdx +132 -1
  119. package/docs/zh/plugin/_meta.json +5 -0
  120. package/docs/zh/plugin/cli-plugins/_meta.json +1 -1
  121. package/docs/zh/plugin/cli-plugins/api.mdx +15 -65
  122. package/docs/zh/plugin/cli-plugins/life-cycle.mdx +0 -4
  123. package/docs/zh/plugin/introduction.mdx +4 -16
  124. package/docs/zh/plugin/plugin-system.mdx +3 -14
  125. package/docs/zh/plugin/runtime-plugins/_meta.json +1 -1
  126. package/docs/zh/plugin/runtime-plugins/api.mdx +1 -1
  127. package/docs/zh/plugin/server-plugins/_meta.json +1 -0
  128. package/docs/zh/plugin/server-plugins/api.mdx +210 -1
  129. package/docs/zh/plugin/server-plugins/life-cycle.mdx +41 -1
  130. package/package.json +2 -2
  131. package/src/components/FrameworkCode/index.tsx +605 -0
  132. package/docs/en/configure/app/performance/bundle-analyze.mdx +0 -24
  133. package/docs/en/configure/app/tools/babel.mdx +0 -225
  134. package/docs/en/plugin/cli-plugins/migration.mdx +0 -83
  135. package/docs/en/plugin/runtime-plugins/migration.mdx +0 -110
  136. package/docs/zh/components/default-mwa-generate.mdx +0 -4
  137. package/docs/zh/configure/app/performance/bundle-analyze.mdx +0 -24
  138. package/docs/zh/configure/app/tools/babel.mdx +0 -224
  139. package/docs/zh/plugin/cli-plugins/migration.mdx +0 -83
  140. package/docs/zh/plugin/runtime-plugins/migration.mdx +0 -110
  141. /package/docs/en/components/{router-legacy-tip.mdx → upgrade-config-deploy.mdx} +0 -0
  142. /package/docs/zh/components/{router-legacy-tip.mdx → upgrade-config-deploy.mdx} +0 -0
@@ -105,6 +105,7 @@ i18nPlugin({
105
105
  1. **If you configure `loadPath` or `addPath`**: The backend will be automatically enabled (`enabled: true`) without checking for locales directory, since you've already specified the resource path.
106
106
 
107
107
  2. **If you don't configure backend**: The plugin will automatically detect if a `locales` directory exists in:
108
+
108
109
  - Project root: `{projectRoot}/locales`
109
110
  - Config public directory: `{projectRoot}/config/public/locales`
110
111
  - Public directory configured via `server.publicDir`: `{projectRoot}/{publicDir}/locales`
@@ -331,27 +332,17 @@ export default defineRuntimeConfig({
331
332
 
332
333
  ### i18nInstance Configuration
333
334
 
334
- If you need to use a custom i18next instance, you can provide it in runtime configuration:
335
-
336
- ```ts
337
- import { defineRuntimeConfig } from '@modern-js/runtime';
338
- import i18next from 'i18next';
335
+ If you need to use a custom i18n instance, you can provide it in runtime configuration:
339
336
 
340
- // Create custom instance
341
- const customI18n = i18next.createInstance({
342
- // Custom configuration
343
- });
337
+ import CustomInstanceCode from '@site-docs/components/international/custom-instance-code';
344
338
 
345
- export default defineRuntimeConfig({
346
- i18n: {
347
- i18nInstance: customI18n,
348
- },
349
- });
350
- ```
339
+ <CustomInstanceCode />
351
340
 
352
341
  ### initOptions Configuration
353
342
 
354
- `initOptions` will be passed to i18next's `init` method and supports all i18next configuration options:
343
+ import InitOptionsDesc from '@site-docs/components/international/init-options-desc';
344
+
345
+ <InitOptionsDesc />
355
346
 
356
347
  :::info
357
348
  If `localePathRedirect` is enabled, the `detection` configuration should be set in CLI configuration, not in `initOptions`. This is because the server-side plugin needs to read the `detection` option from CLI configuration to perform language detection and path redirection.
@@ -10,14 +10,9 @@ This guide will help you quickly integrate internationalization functionality in
10
10
 
11
11
  First, install the necessary dependencies:
12
12
 
13
- ```bash
14
- pnpm add @modern-js/plugin-i18n i18next react-i18next
15
- ```
16
-
17
- :::info
18
- `i18next` and `react-i18next` are peer dependencies and need to be installed manually.
13
+ import InstallCommand from '@site-docs/components/international/install-command';
19
14
 
20
- :::
15
+ <InstallCommand />
21
16
 
22
17
  ## Basic Configuration
23
18
 
@@ -56,32 +51,9 @@ export default defineConfig({
56
51
 
57
52
  ### Configure Runtime Options in `src/modern.runtime.ts`
58
53
 
59
- Create the `src/modern.runtime.ts` file and configure i18n runtime options:
54
+ import InstanceCode from '@site-docs/components/international/instance-code';
60
55
 
61
- ```ts
62
- import { defineRuntimeConfig } from '@modern-js/runtime';
63
- import i18next from 'i18next';
64
-
65
- // It's recommended to create a new i18next instance to avoid using the global default instance
66
- const i18nInstance = i18next.createInstance();
67
-
68
- export default defineRuntimeConfig({
69
- i18n: {
70
- i18nInstance: i18nInstance,
71
- initOptions: {
72
- fallbackLng: 'en',
73
- supportedLngs: ['zh', 'en'],
74
- },
75
- },
76
- });
77
- ```
78
-
79
- :::info
80
- `modern.runtime.ts` is a runtime configuration file used to configure i18next initialization options. Even for the most basic configuration, it's recommended to create this file to ensure the plugin works correctly.
81
-
82
- It's recommended to use `i18next.createInstance()` to create a new instance instead of directly using the default exported `i18next`. This avoids global state pollution and ensures each application has an independent i18n instance.
83
-
84
- :::
56
+ <InstanceCode />
85
57
 
86
58
  ### Create Language Resource Files
87
59
 
@@ -40,7 +40,7 @@ If you want to find out the large libraries in the project, you can add the `BUN
40
40
  BUNDLE_ANALYZE=true pnpm build
41
41
  ```
42
42
 
43
- See the [performance.bundleAnalyze](/configure/app/performance/bundle-analyze.html) configuration for details.
43
+ This will generate a bundle analysis report to help you identify large dependencies.
44
44
 
45
45
  ## Adjust Browserslist
46
46
 
@@ -6,11 +6,25 @@ Before starting to use the React Compiler, it is recommended to read the [React
6
6
 
7
7
  ## How to Use
8
8
 
9
- The steps to use the React Compiler in Modern.js are as follows:
9
+ ### React 19
10
10
 
11
- 1. Modern.js does not officially support React 19 yet, but you can install `react-compiler-runtime@rc` in React 17 or 18 projects to allow the compiled code to run on versions before 19.
11
+ If you are using React 19, Modern.js has built-in support for React Compiler, and no additional configuration is required.
12
12
 
13
- 2. Currently, the React Compiler only provides a Babel plugin, so you need to install `babel-plugin-react-compiler`.
13
+ ### React 17 or 18
14
+
15
+ If you are using React 17 or 18, you need to configure it as follows:
16
+
17
+ 1. Install `react-compiler-runtime` to allow the compiled code to run on versions before 19:
18
+
19
+ ```bash
20
+ npm install react-compiler-runtime
21
+ ```
22
+
23
+ 2. Install `babel-plugin-react-compiler`:
24
+
25
+ ```bash
26
+ npm install babel-plugin-react-compiler
27
+ ```
14
28
 
15
29
  3. Register the Babel plugin in your Modern.js configuration file:
16
30
 
@@ -24,7 +38,7 @@ export default defineConfig({
24
38
  [
25
39
  'babel-plugin-react-compiler',
26
40
  {
27
- target: '18',
41
+ target: '18', // or '17', depending on your React version
28
42
  },
29
43
  ],
30
44
  ]);
@@ -73,7 +73,7 @@ export default defineConfig({
73
73
  ```
74
74
 
75
75
  :::tip
76
- When Rspack build is enabled, `babel-loader` is not enabled by default. If you need to add some babel plugins, you can configure it through [tools.babel](/configure/app/tools/babel). This will generate additional compilation overhead and slow down the Rspack build speed to a certain extent.
76
+ When Rspack build is enabled, `babel-loader` is not enabled by default. If you need to add some babel plugins, you can configure it through [babel plugin](https://rsbuild.rs/plugins/list/plugin-babel#babel-plugin). This will generate additional compilation overhead and slow down the Rspack build speed to a certain extent.
77
77
  :::
78
78
 
79
79
  ## The relationship between Rspack and Modern.js versions
@@ -73,11 +73,7 @@ Modern.js comes with a built-in default Monitor, where different events trigger
73
73
 
74
74
  ## Register Monitors
75
75
 
76
- Developers can register their own Monitors using the `push` API, but this can only be done in [server middleware](/guides/advanced-features/web-server#unstable-middleware) or server plugins. Registration is not available in Data Loaders, components, or init functions.
77
-
78
- :::note
79
- Server plugins are currently not available, and documentation will be added in the future.
80
- :::
76
+ Developers can register their own Monitors using the `push` API, but this can only be done in [server middleware](/guides/advanced-features/web-server#unstable-middleware) or [server plugins](/plugin/server-plugins/api). Registration is not available in Data Loaders, components, or init functions.
81
77
 
82
78
  ```ts title="server/modern.server.ts"
83
79
  import {
@@ -114,6 +110,67 @@ export default defineServerConfig({
114
110
  });
115
111
  ```
116
112
 
113
+ Register Monitor in server plugins:
114
+
115
+ ```ts title="server/plugins/my-monitor-plugin.ts"
116
+ import type { ServerPlugin } from '@modern-js/server-runtime';
117
+ import type { MonitorEvent } from '@modern-js/types';
118
+
119
+ const myMonitorPlugin = (): ServerPlugin => ({
120
+ name: '@my-org/my-monitor-plugin',
121
+ setup(api) {
122
+ api.onPrepare(() => {
123
+ const { middlewares } = api.getServerContext();
124
+
125
+ // Define monitor, ensuring it's only created once
126
+ const myMonitor = (event: MonitorEvent) => {
127
+ if (event.type === 'log') {
128
+ // Handle log events
129
+ console.log(`[${event.payload.level}] ${event.payload.message}`);
130
+ } else if (event.type === 'timing') {
131
+ // Handle timing events
132
+ console.log(
133
+ `Timing: ${event.payload.name} = ${event.payload.dur}ms`,
134
+ );
135
+ } else if (event.type === 'counter') {
136
+ // Handle counter events
137
+ console.log(`Counter: ${event.payload.name}`);
138
+ }
139
+ };
140
+
141
+ // Use a flag to ensure monitor is only registered once
142
+ let monitorRegistered = false;
143
+
144
+ middlewares.push({
145
+ name: 'inject-monitor',
146
+ handler: async (c, next) => {
147
+ const monitors = c.get('monitors');
148
+ // Only register monitor on the first request
149
+ if (!monitorRegistered) {
150
+ monitors.push(myMonitor);
151
+ monitorRegistered = true;
152
+ }
153
+ await next();
154
+ },
155
+ });
156
+ });
157
+ },
158
+ });
159
+
160
+ export default myMonitorPlugin;
161
+ ```
162
+
163
+ Then configure the plugin in `server/modern.server.ts`:
164
+
165
+ ```ts title="server/modern.server.ts"
166
+ import { defineServerConfig } from '@modern-js/server-runtime';
167
+ import myMonitorPlugin from './plugins/my-monitor-plugin';
168
+
169
+ export default defineServerConfig({
170
+ plugins: [myMonitorPlugin()],
171
+ });
172
+ ```
173
+
117
174
  ## Use Monitors
118
175
 
119
176
  Modern.js allows developers to invoke Monitors in Data Loaders and components.
@@ -2,14 +2,11 @@
2
2
  title: Data Caching
3
3
  sidebar_position: 4
4
4
  ---
5
+
5
6
  # Data Caching
6
7
 
7
8
  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), 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).
8
9
 
9
- :::info
10
- X.65.5 and above versions are required
11
- :::
12
-
13
10
  ## Basic Usage
14
11
 
15
12
  :::note
@@ -20,7 +17,6 @@ If you use the `cache` function in BFF, you should import the cache funtion from
20
17
 
21
18
  :::
22
19
 
23
-
24
20
  ```ts
25
21
  import { cache } from '@modern-js/runtime/cache';
26
22
  import { fetchUserData } from './api';
@@ -28,14 +24,13 @@ import { fetchUserData } from './api';
28
24
  const getUser = cache(fetchUserData);
29
25
 
30
26
  const loader = async () => {
31
- const user = await getUser(user); // When the parameters of the function changes, the function will be re-executed
27
+ const user = await getUser('123'); // When the parameters of the function changes, the function will be re-executed
32
28
  return {
33
29
  user,
34
30
  };
35
31
  };
36
32
  ```
37
33
 
38
-
39
34
  ### Parameters
40
35
 
41
36
  - `fn`: The data fetching or computation function to be cached
@@ -44,7 +39,7 @@ const loader = async () => {
44
39
  - `maxAge`: Cache validity period (milliseconds)
45
40
  - `revalidate`: Time window for revalidating the cache (milliseconds), similar to HTTP Cache-Control's stale-while-revalidate functionality
46
41
  - `getKey`: Simplified cache key generation function based on function parameters
47
- - `customKey`: Custom cache key function
42
+ - `customKey`: Custom cache key generation function, used to maintain cache when function references change
48
43
 
49
44
  The type of the `options` parameter is as follows:
50
45
 
@@ -62,7 +57,6 @@ interface CacheOptions {
62
57
  }
63
58
  ```
64
59
 
65
-
66
60
  ### Return Value
67
61
 
68
62
  The `cache` function returns a new function with caching capabilities. Multiple calls to this function will not re-execute the `fn` function.
@@ -76,7 +70,7 @@ EdenX's `cache` function can be used in any frontend or server-side code.
76
70
 
77
71
  ### Without options Parameter
78
72
 
79
- 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. EdenX will re-execute the `fn` function with each server request.
73
+ 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.
80
74
 
81
75
  :::info
82
76
  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.
@@ -96,7 +90,6 @@ const loader = async () => {
96
90
  };
97
91
  ```
98
92
 
99
-
100
93
  ### With options Parameter
101
94
 
102
95
  #### `maxAge` Parameter
@@ -113,12 +106,11 @@ const getDashboardStats = cache(
113
106
  return await fetchComplexStatistics();
114
107
  },
115
108
  {
116
- maxAge: CacheTime.MINUTE * 2, // Calling this function within 2 minutes will return cached data
117
- }
109
+ maxAge: CacheTime.MINUTE * 2, // Calling this function within 2 minutes will return cached data
110
+ },
118
111
  );
119
112
  ```
120
113
 
121
-
122
114
  #### `revalidate` Parameter
123
115
 
124
116
  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.
@@ -139,11 +131,10 @@ const getDashboardStats = cache(
139
131
  {
140
132
  maxAge: CacheTime.MINUTE * 2,
141
133
  revalidate: CacheTime.MINUTE * 1,
142
- }
134
+ },
143
135
  );
144
136
  ```
145
137
 
146
-
147
138
  #### `tag` Parameter
148
139
 
149
140
  The `tag` parameter identifies the cache with a tag, which can be a string or an array of strings.
@@ -158,7 +149,7 @@ const getDashboardStats = cache(
158
149
  },
159
150
  {
160
151
  tag: 'dashboard',
161
- }
152
+ },
162
153
  );
163
154
 
164
155
  const getComplexStatistics = cache(
@@ -167,13 +158,12 @@ const getComplexStatistics = cache(
167
158
  },
168
159
  {
169
160
  tag: 'dashboard',
170
- }
161
+ },
171
162
  );
172
163
 
173
- await revalidateTag('dashboard-stats'); // Invalidates the cache for both getDashboardStats and getComplexStatistics functions
164
+ await revalidateTag('dashboard'); // Invalidates the cache for both getDashboardStats and getComplexStatistics functions
174
165
  ```
175
166
 
176
-
177
167
  #### `getKey` Parameter
178
168
 
179
169
  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.
@@ -193,15 +183,15 @@ const getUser = cache(
193
183
  maxAge: CacheTime.MINUTE * 5,
194
184
  // Only use the first parameter (userId) as the cache key
195
185
  getKey: (userId, options) => userId,
196
- }
186
+ },
197
187
  );
198
188
 
199
189
  // The following two calls will share the cache because getKey only uses userId
200
- await getUser(123, { language: 'en' });
201
- await getUser(123, { language: 'fr' }); // Cache hit, won't request again
190
+ await getUser(123, { language: 'zh' });
191
+ await getUser(123, { language: 'en' }); // Cache hit, won't request again
202
192
 
203
193
  // Different userId will use different cache
204
- await getUser(456, { language: 'en' }); // Won't hit cache, will request again
194
+ await getUser(456, { language: 'zh' }); // Won't hit cache, will request again
205
195
  ```
206
196
 
207
197
  You can also use Modern.js's `generateKey` function together with getKey to generate the cache key:
@@ -223,21 +213,18 @@ const getUser = cache(
223
213
  {
224
214
  maxAge: CacheTime.MINUTE * 5,
225
215
  getKey: (userId, options) => generateKey(userId),
226
- }
216
+ },
227
217
  );
228
218
  ```
229
219
 
230
220
  Additionally, `getKey` can also return a numeric type as a cache key:
231
221
 
232
222
  ```ts
233
- const getUserById = cache(
234
- fetchUserDataById,
235
- {
236
- maxAge: CacheTime.MINUTE * 5,
237
- // Directly use the numeric ID as the cache key
238
- getKey: (id) => id,
239
- }
240
- );
223
+ const getUserById = cache(fetchUserDataById, {
224
+ maxAge: CacheTime.MINUTE * 5,
225
+ // Directly use the numeric ID as the cache key
226
+ getKey: id => id,
227
+ });
241
228
 
242
229
  await getUserById(42); // Uses 42 as the cache key
243
230
  ```
@@ -255,6 +242,7 @@ Its return value **directly becomes** the final cache key, **overriding** the de
255
242
  :::info
256
243
 
257
244
  Generally, the cache will be invalidated in the following scenarios:
245
+
258
246
  1. The function's input parameters change
259
247
  2. The maxAge condition is no longer satisfied
260
248
  3. The `revalidateTag` method has been called
@@ -270,16 +258,13 @@ import { cache } from '@modern-js/runtime/cache';
270
258
  import { fetchUserData } from './api';
271
259
 
272
260
  // Different function references, but share the same cache via customKey
273
- const getUserA = cache(
274
- fetchUserData,
275
- {
276
- maxAge: CacheTime.MINUTE * 5,
277
- customKey: ({ params }) => {
278
- // Return a stable string as the cache key
279
- return `user-${params[0]}`;
280
- },
281
- }
282
- );
261
+ const getUserA = cache(fetchUserData, {
262
+ maxAge: CacheTime.MINUTE * 5,
263
+ customKey: ({ params }) => {
264
+ // Return a stable string as the cache key
265
+ return `user-${params[0]}`;
266
+ },
267
+ });
283
268
 
284
269
  // Even if the function reference changes,
285
270
  // as long as customKey returns the same value, the cache will be hit
@@ -291,7 +276,7 @@ const getUserB = cache(
291
276
  // Return the same key as getUserA
292
277
  return `user-${params[0]}`;
293
278
  },
294
- }
279
+ },
295
280
  );
296
281
 
297
282
  // Now you can share cache across different function implementations
@@ -299,12 +284,9 @@ await getUserA(123); // Fetches data and caches with key "user-123"
299
284
  await getUserB(123); // Cache hit, returns cached data
300
285
 
301
286
  // You can utilize the generatedKey parameter to modify the default key
302
- const getUserC = cache(
303
- fetchUserData,
304
- {
305
- customKey: ({ generatedKey }) => `prefix-${generatedKey}`,
306
- }
307
- );
287
+ const getUserC = cache(fetchUserData, {
288
+ customKey: ({ generatedKey }) => `prefix-${generatedKey}`,
289
+ });
308
290
 
309
291
  // For predictable cache keys that can be managed externally
310
292
  const getUserD = cache(
@@ -314,7 +296,7 @@ const getUserD = cache(
314
296
  {
315
297
  maxAge: CacheTime.MINUTE * 5,
316
298
  customKey: ({ params }) => `app:user:${params[0]}`,
317
- }
299
+ },
318
300
  );
319
301
  ```
320
302
 
@@ -331,30 +313,31 @@ const stats = {
331
313
  hits: 0,
332
314
  misses: 0,
333
315
  stales: 0,
334
- hitRate: () => stats.hits / stats.total
316
+ hitRate: () => stats.hits / stats.total,
335
317
  };
336
318
 
337
- const getUser = cache(
338
- fetchUserData,
339
- {
340
- maxAge: CacheTime.MINUTE * 5,
341
- onCache({ status, key, params, result }) {
342
- // status can be 'hit', 'miss', or 'stale'
343
- stats.total++;
344
-
345
- if (status === 'hit') {
346
- stats.hits++;
347
- } else if (status === 'miss') {
348
- stats.misses++;
349
- } else if (status === 'stale') {
350
- stats.stales++;
351
- }
352
-
353
- console.log(`Cache ${status} for key: ${String(key)}`);
354
- console.log(`Current hit rate: ${stats.hitRate() * 100}%`);
319
+ const getUser = cache(fetchUserData, {
320
+ maxAge: CacheTime.MINUTE * 5,
321
+ onCache({ status, key, params, result }) {
322
+ // status can be 'hit', 'miss', or 'stale'
323
+ stats.total++;
324
+
325
+ if (status === 'hit') {
326
+ stats.hits++;
327
+ } else if (status === 'miss') {
328
+ stats.misses++;
329
+ } else if (status === 'stale') {
330
+ stats.stales++;
355
331
  }
356
- }
357
- );
332
+
333
+ console.log(
334
+ `Cache ${
335
+ status === 'hit' ? 'hit' : status === 'miss' ? 'miss' : 'stale'
336
+ } for key: ${String(key)}`,
337
+ );
338
+ console.log(`Current hit rate: ${stats.hitRate() * 100}%`);
339
+ },
340
+ });
358
341
 
359
342
  // Usage example
360
343
  await getUser(1); // Cache miss
@@ -375,6 +358,7 @@ The `onCache` callback receives an object with the following properties:
375
358
  This callback is only invoked when the `options` parameter is provided. When using the cache function without options, the `onCache` callback is not called.
376
359
 
377
360
  The `onCache` callback is useful for:
361
+
378
362
  - Monitoring cache performance
379
363
  - Calculating hit rates
380
364
  - Logging cache operations
@@ -432,7 +416,7 @@ configureCache({
432
416
 
433
417
  ##### Using `customKey` to Ensure Cache Key Stability
434
418
 
435
- :::note
419
+ :::warning Important Recommendation
436
420
 
437
421
  When using custom storage containers (such as Redis), **it's recommended to configure `customKey`** to ensure cache key stability. This ensures:
438
422
 
@@ -461,7 +445,7 @@ const getUser = cache(
461
445
  maxAge: CacheTime.MINUTE * 5,
462
446
  // Use stable identifiers related to the cached function as cache keys
463
447
  customKey: () => `fetchUserData`,
464
- }
448
+ },
465
449
  );
466
450
  ```
467
451
 
@@ -481,7 +465,7 @@ class RedisContainer implements Container {
481
465
  }
482
466
 
483
467
  async get(key: string): Promise<string | null> {
484
- const value = await this.redis.get(key);
468
+ const value = await this.client.get(key);
485
469
  return value ? JSON.parse(value) : null;
486
470
  }
487
471
 
@@ -524,7 +508,7 @@ configureCache({
524
508
  });
525
509
  ```
526
510
 
527
- ##### Important Notes
511
+ ##### Notes
528
512
 
529
513
  1. **Serialization**: All cached data will be serialized to strings for storage. The container only needs to handle string get/set operations.
530
514
 
@@ -8,10 +8,6 @@ Modern.js provides out-of-the-box data fetching capabilities. Developers can use
8
8
 
9
9
  ## What is Data Loader
10
10
 
11
- :::note
12
- In Modern.js v1 projects, data was fetched using `useLoader`. This is no longer the recommended approach; we suggest migrating to Data Loader.
13
- :::
14
-
15
11
  Modern.js recommends managing routes using [conventional routing](/guides/basic-features/routes/routes). Each route component (`layout.ts`, `page.ts`, or `$.tsx`) can have a same-named `.data` file. These files can export a `loader` function, known as Data Loader, which executes before the corresponding route component renders to provide data for the component. Here is an example:
16
12
 
17
13
  ```bash
@@ -39,15 +35,18 @@ export const loader = async (): Promise<ProfileData> => {
39
35
  ```
40
36
 
41
37
  :::warning Compatibility
38
+
42
39
  - In previous versions, Data Loader was defined in a `.loader` file. In the current version, we recommend defining it in a `.data` file, while maintaining compatibility with `.loader` files.
43
40
  - In `.loader` files, the Data Loader can be exported as default. In `.data` files, it should be named `loader` export.
41
+
44
42
  ```ts
45
- // xxx.loader.ts
46
- export default () => {}
43
+ // xxx.loader.ts
44
+ export default () => {};
47
45
 
48
46
  // xxx.data.ts
49
- export const loader = () => {}
47
+ export const loader = () => {};
50
48
  ```
49
+
51
50
  :::
52
51
 
53
52
  In the route component, you can use the `useLoaderData` function to fetch data:
@@ -100,7 +99,7 @@ export const loader = async ({ params }: LoaderFunctionArgs) => {
100
99
  `request` is an instance of [Fetch Request](https://developer.mozilla.org/en-US/docs/Web/API/Request). A common use case is to get query parameters from `request`:
101
100
 
102
101
  ```tsx
103
- import { LoaderFunctionArgs } from '@modern-js/runtime/router;
102
+ import { LoaderFunctionArgs } from '@modern-js/runtime/router';
104
103
 
105
104
  export const loader = async ({ request }: LoaderFunctionArgs) => {
106
105
  const url = new URL(request.url);
@@ -146,20 +145,22 @@ In SSR applications, the `loader` function runs only on the server, hence it is
146
145
 
147
146
  :::note
148
147
  Having the `loader` function run only on the server in SSR applications brings several benefits:
148
+
149
149
  - **Simplifies usage**: Guarantees consistent data-fetching methods in SSR applications, so developers don't have to distinguish between client and server code.
150
150
  - **Reduces client bundle size**: Moves logic code and dependencies from the client to the server.
151
151
  - **Improves maintainability**: Less direct influence of data logic on front-end UI and avoids issues of accidentally including server dependencies in the client bundle or vice versa.
152
152
 
153
153
  :::
154
154
 
155
- We recommend using the `fetch` API in `loader` functions to make requests. Since `fetch` works similarly on the client and server, you can fetch data in a consistent manner whether in CSR or SSR:
155
+ We recommend using the `fetch` API in `loader` functions to make requests. Modern.js provides a default polyfill for the `fetch` API, allowing it to be used on the server side. This means you can fetch data in a consistent manner whether in CSR or SSR:
156
156
 
157
157
  ```tsx
158
158
  export async function loader() {
159
159
  const res = await fetch('URL_ADDRESS');
160
+ const data = await res.json();
160
161
  return {
161
- message: res.message
162
- }
162
+ message: data.message,
163
+ };
163
164
  }
164
165
  ```
165
166
 
@@ -204,14 +205,14 @@ In the following example, the page's status code will match this `response`, and
204
205
  // routes/user/profile/page.data.ts
205
206
  export async function loader() {
206
207
  const user = await fetchUser();
207
- if(!user){
208
+ if (!user) {
208
209
  throw new Response('The user was not found', { status: 404 });
209
210
  }
210
211
  return user;
211
212
  }
212
213
 
213
214
  // routes/error.tsx
214
- import { useRouteError } from '@modern-js/runtime/router;
215
+ import { useRouteError } from '@modern-js/runtime/router';
215
216
  const ErrorBoundary = () => {
216
217
  const error = useRouteError() as { data: string };
217
218
  return <div className="error">{error.data}</div>;
@@ -240,7 +241,7 @@ export function UserLayout() {
240
241
  }
241
242
  ```
242
243
 
243
- `useRouteLoaderData` accepts a parameter `routeId`. In conventional routing, Modern.js automatically generates the `routeId`, which is the path of the corresponding component relative to `src/routes`. In the example above, the `routeId` for fetching data from `routes/user/layout.tsx`'s loader is `user/layout`.
244
+ `useRouteLoaderData` accepts a parameter `routeId`. In conventional routing, Modern.js automatically generates the `routeId`, which is the path of the corresponding component relative to `src/routes`. For example, in the example above, if a child component wants to get data returned by the loader in `routes/user/layout.tsx`, the `routeId` value is `user/layout`.
244
245
 
245
246
  In a multi-entry scenario, the `routeId` value needs to include the corresponding entry name, which is typically the directory name if not explicitly specified. For example, with the following directory structure:
246
247