@modern-js/main-doc 2.67.3 → 2.67.5
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.
- package/docs/en/apis/app/hooks/src/routes.mdx +70 -0
- package/docs/en/configure/app/output/filename.mdx +8 -3
- package/docs/en/configure/app/plugins.mdx +13 -33
- package/docs/en/configure/app/runtime/master-app.mdx +1 -5
- package/docs/en/configure/app/runtime/plugins.mdx +58 -0
- package/docs/en/configure/app/usage.mdx +1 -3
- package/docs/en/guides/advanced-features/_meta.json +1 -0
- package/docs/en/guides/advanced-features/bff.mdx +1 -1
- package/docs/en/guides/advanced-features/compatibility.mdx +1 -1
- package/docs/en/guides/advanced-features/custom-server.mdx +218 -0
- package/docs/en/guides/advanced-features/page-performance/inline-assets.mdx +2 -0
- package/docs/en/guides/advanced-features/page-performance/optimize-bundle.mdx +1 -1
- package/docs/en/guides/advanced-features/web-server.mdx +174 -1
- package/docs/en/guides/basic-features/data/data-cache.mdx +216 -1
- package/docs/en/guides/basic-features/data/data-fetch.mdx +2 -1
- package/docs/en/guides/basic-features/deploy.mdx +3 -1
- package/docs/en/guides/basic-features/html.mdx +3 -3
- package/docs/en/guides/basic-features/render/ssr.mdx +2 -2
- package/docs/en/guides/concept/entries.mdx +1 -1
- package/docs/en/guides/get-started/quick-start.mdx +1 -1
- package/docs/en/plugin/cli-plugins/api.mdx +6 -0
- package/docs/en/plugin/runtime-plugins/api.mdx +37 -12
- package/docs/en/tutorials/first-app/c05-loader.mdx +1 -1
- package/docs/zh/configure/app/output/filename.mdx +8 -0
- package/docs/zh/configure/app/plugins.mdx +3 -24
- package/docs/zh/configure/app/runtime/master-app.mdx +1 -5
- package/docs/zh/configure/app/runtime/plugins.mdx +58 -0
- package/docs/zh/configure/app/usage.mdx +1 -2
- package/docs/zh/guides/advanced-features/_meta.json +1 -0
- package/docs/zh/guides/advanced-features/custom-server.mdx +216 -0
- package/docs/zh/guides/advanced-features/web-server.mdx +174 -1
- package/docs/zh/guides/basic-features/data/data-cache.mdx +205 -1
- package/docs/zh/guides/basic-features/routes.mdx +72 -0
- package/docs/zh/plugin/cli-plugins/api.mdx +6 -0
- package/docs/zh/plugin/runtime-plugins/api.mdx +37 -12
- package/package.json +2 -2
- package/src/i18n/index.ts +1 -1
- /package/docs/en/configure/app/source/{mainEntryName.mdx → main-entry-name.mdx} +0 -0
- /package/docs/zh/configure/app/source/{mainEntryName.mdx → main-entry-name.mdx} +0 -0
@@ -4,7 +4,7 @@ sidebar_position: 4
|
|
4
4
|
---
|
5
5
|
# 数据缓存
|
6
6
|
|
7
|
-
`cache`
|
7
|
+
`cache` 函数可以让你缓存数据获取或计算的结果,相比整页[渲染缓存](/guides/basic-features/render/ssr-cache),它提供了更精细的数据粒度控制,并且适用于客户端渲染(CSR)、服务端渲染(SSR)、API 服务(BFF)等多种场景。
|
8
8
|
|
9
9
|
:::info
|
10
10
|
需要 x.65.5 及以上版本
|
@@ -12,6 +12,14 @@ sidebar_position: 4
|
|
12
12
|
|
13
13
|
## 基本用法
|
14
14
|
|
15
|
+
:::note
|
16
|
+
|
17
|
+
如果在 BFF 中使用 `cache` 函数,应该从 `@modern-js/server-runtime/cache` 导入相关函数
|
18
|
+
|
19
|
+
`import { cache } from '@modern-js/server-runtime/cache'`
|
20
|
+
|
21
|
+
:::
|
22
|
+
|
15
23
|
```ts
|
16
24
|
import { cache } from '@modern-js/runtime/cache';
|
17
25
|
import { fetchUserData } from './api';
|
@@ -33,6 +41,8 @@ const loader = async () => {
|
|
33
41
|
- `tag`: 用于标识缓存的标签,可以基于这个标签使缓存失效
|
34
42
|
- `maxAge`: 缓存的有效期 (毫秒)
|
35
43
|
- `revalidate`: 重新验证缓存的时间窗口(毫秒),与 HTTP Cache-Control 的 stale-while-revalidate 功能一致
|
44
|
+
- `getKey`: 简化的缓存键生成函数,根据函数参数生成缓存键
|
45
|
+
- `customKey`: 自定义缓存键生成函数,用于在函数引用变化时保持缓存
|
36
46
|
|
37
47
|
`options` 参数的类型如下:
|
38
48
|
|
@@ -41,6 +51,12 @@ interface CacheOptions {
|
|
41
51
|
tag?: string | string[];
|
42
52
|
maxAge?: number;
|
43
53
|
revalidate?: number;
|
54
|
+
getKey?: <Args extends any[]>(...args: Args) => string;
|
55
|
+
customKey?: <Args extends any[]>(options: {
|
56
|
+
params: Args;
|
57
|
+
fn: (...args: Args) => any;
|
58
|
+
generatedKey: string;
|
59
|
+
}) => string | symbol;
|
44
60
|
}
|
45
61
|
```
|
46
62
|
|
@@ -146,6 +162,193 @@ const getComplexStatistics = cache(
|
|
146
162
|
revalidateTag('dashboard-stats'); // 会使 getDashboardStats 函数和 getComplexStatistics 函数的缓存都失效
|
147
163
|
```
|
148
164
|
|
165
|
+
#### `getKey` 参数
|
166
|
+
|
167
|
+
`getKey` 参数用于自定义缓存键的生成方式,例如你可能只需要依赖函数参数的一部分来区分缓存。它是一个函数,接收与原始函数相同的参数,返回一个字符串作为缓存键:
|
168
|
+
|
169
|
+
```ts
|
170
|
+
import { cache, CacheTime } from '@modern-js/runtime/cache';
|
171
|
+
import { fetchUserData } from './api';
|
172
|
+
|
173
|
+
const getUser = cache(
|
174
|
+
async (userId, options) => {
|
175
|
+
// 这里 options 可能包含很多配置,但我们只想根据 userId 缓存
|
176
|
+
return await fetchUserData(userId, options);
|
177
|
+
},
|
178
|
+
{
|
179
|
+
maxAge: CacheTime.MINUTE * 5,
|
180
|
+
// 只使用第一个参数(userId)作为缓存键
|
181
|
+
getKey: (userId, options) => userId,
|
182
|
+
}
|
183
|
+
);
|
184
|
+
|
185
|
+
// 下面两次调用会共享缓存,因为 getKey 只使用了 userId
|
186
|
+
await getUser(123, { language: 'zh' });
|
187
|
+
await getUser(123, { language: 'en' }); // 命中缓存,不会重新请求
|
188
|
+
|
189
|
+
// 不同的 userId 会使用不同的缓存
|
190
|
+
await getUser(456, { language: 'zh' }); // 不会命中缓存,会重新请求
|
191
|
+
```
|
192
|
+
|
193
|
+
你也可以使用 Modern.js 提供的 `generateKey` 函数配合 getKey 生成缓存的键:
|
194
|
+
|
195
|
+
:::info
|
196
|
+
|
197
|
+
Modern.js 中的 `generateKey` 函数确保即使对象属性顺序发生变化,也能生成一致的唯一键值,保证稳定的缓存
|
198
|
+
|
199
|
+
:::
|
200
|
+
|
201
|
+
```ts
|
202
|
+
import { cache, CacheTime, generateKey } from '@modern-js/runtime/cache';
|
203
|
+
import { fetchUserData } from './api';
|
204
|
+
|
205
|
+
const getUser = cache(
|
206
|
+
async (userId, options) => {
|
207
|
+
return await fetchUserData(userId, options);
|
208
|
+
},
|
209
|
+
{
|
210
|
+
maxAge: CacheTime.MINUTE * 5,
|
211
|
+
getKey: (userId, options) => generateKey(userId),
|
212
|
+
}
|
213
|
+
);
|
214
|
+
```
|
215
|
+
|
216
|
+
|
217
|
+
#### `customKey` 参数
|
218
|
+
|
219
|
+
`customKey` 参数用于定制缓存的键,它是一个函数,接收一个包含以下属性的对象,返回值必须是字符串或 Symbol 类型,将作为缓存的键:
|
220
|
+
|
221
|
+
- `params`:调用缓存函数时传入的参数数组
|
222
|
+
- `fn`:原始被缓存的函数引用
|
223
|
+
- `generatedKey`:框架基于入参自动生成的原始缓存键
|
224
|
+
|
225
|
+
:::info
|
226
|
+
|
227
|
+
一般在以下场景,缓存会失效:
|
228
|
+
1. 缓存的函数引用发生变化
|
229
|
+
2. 函数的入参发生变化
|
230
|
+
3. 不满足 maxAge
|
231
|
+
4. 调用了 `revalidateTag`
|
232
|
+
|
233
|
+
`customKey` 可以用在函数引用不同,但希望共享缓存的场景,如果只是自定义缓存键,推荐使用 `getKey`
|
234
|
+
|
235
|
+
:::
|
236
|
+
|
237
|
+
这在某些场景下非常有用,比如当函数引用发生变化时,但你希望仍然返回缓存的数据。
|
238
|
+
|
239
|
+
```ts
|
240
|
+
import { cache } from '@modern-js/runtime/cache';
|
241
|
+
import { fetchUserData } from './api';
|
242
|
+
|
243
|
+
// 不同的函数引用,但是通过 customKey 可以使它们共享一个缓存
|
244
|
+
const getUserA = cache(
|
245
|
+
fetchUserData,
|
246
|
+
{
|
247
|
+
maxAge: CacheTime.MINUTE * 5,
|
248
|
+
customKey: ({ params }) => {
|
249
|
+
// 返回一个稳定的字符串作为缓存的键
|
250
|
+
return `user-${params[0]}`;
|
251
|
+
},
|
252
|
+
}
|
253
|
+
);
|
254
|
+
|
255
|
+
// 即使函数引用变了,只要 customKey 返回相同的值,也会命中缓存
|
256
|
+
const getUserB = cache(
|
257
|
+
(...args) => fetchUserData(...args), // 新的函数引用
|
258
|
+
{
|
259
|
+
maxAge: CacheTime.MINUTE * 5,
|
260
|
+
customKey: ({ params }) => {
|
261
|
+
// 返回与 getUserA 相同的键
|
262
|
+
return `user-${params[0]}`;
|
263
|
+
},
|
264
|
+
}
|
265
|
+
);
|
266
|
+
|
267
|
+
// 即使 getUserA 和 getUserB 是不同的函数引用,但由于它们的 customKey 返回相同的值
|
268
|
+
// 所以当调用参数相同时,它们会共享缓存
|
269
|
+
const dataA = await getUserA(1);
|
270
|
+
const dataB = await getUserB(1); // 这里会命中缓存,不会再次发起请求
|
271
|
+
|
272
|
+
// 也可以使用 Symbol 作为缓存键(通常用于共享同一个应用内的缓存)
|
273
|
+
const USER_CACHE_KEY = Symbol('user-cache');
|
274
|
+
const getUserC = cache(
|
275
|
+
fetchUserData,
|
276
|
+
{
|
277
|
+
maxAge: CacheTime.MINUTE * 5,
|
278
|
+
customKey: () => USER_CACHE_KEY,
|
279
|
+
}
|
280
|
+
);
|
281
|
+
|
282
|
+
// 可以利用 generatedKey 参数在默认键的基础上进行修改
|
283
|
+
const getUserD = cache(
|
284
|
+
fetchUserData,
|
285
|
+
{
|
286
|
+
customKey: ({ generatedKey }) => `prefix-${generatedKey}`,
|
287
|
+
}
|
288
|
+
);
|
289
|
+
```
|
290
|
+
|
291
|
+
#### `onCache` 参数
|
292
|
+
|
293
|
+
`onCache` 参数允许你跟踪缓存统计信息,例如命中率。这是一个回调函数,接收有关每次缓存操作的信息,包括状态、键、参数和结果。
|
294
|
+
|
295
|
+
```ts
|
296
|
+
import { cache, CacheTime } from '@modern-js/runtime/cache';
|
297
|
+
|
298
|
+
// 跟踪缓存统计
|
299
|
+
const stats = {
|
300
|
+
total: 0,
|
301
|
+
hits: 0,
|
302
|
+
misses: 0,
|
303
|
+
stales: 0,
|
304
|
+
hitRate: () => stats.hits / stats.total
|
305
|
+
};
|
306
|
+
|
307
|
+
const getUser = cache(
|
308
|
+
fetchUserData,
|
309
|
+
{
|
310
|
+
maxAge: CacheTime.MINUTE * 5,
|
311
|
+
onCache({ status, key, params, result }) {
|
312
|
+
// status 可以是 'hit'、'miss' 或 'stale'
|
313
|
+
stats.total++;
|
314
|
+
|
315
|
+
if (status === 'hit') {
|
316
|
+
stats.hits++;
|
317
|
+
} else if (status === 'miss') {
|
318
|
+
stats.misses++;
|
319
|
+
} else if (status === 'stale') {
|
320
|
+
stats.stales++;
|
321
|
+
}
|
322
|
+
|
323
|
+
console.log(`缓存${status === 'hit' ? '命中' : status === 'miss' ? '未命中' : '陈旧'},键:${String(key)}`);
|
324
|
+
console.log(`当前命中率:${stats.hitRate() * 100}%`);
|
325
|
+
}
|
326
|
+
}
|
327
|
+
);
|
328
|
+
|
329
|
+
// 使用示例
|
330
|
+
await getUser(1); // 缓存未命中
|
331
|
+
await getUser(1); // 缓存命中
|
332
|
+
await getUser(2); // 缓存未命中
|
333
|
+
```
|
334
|
+
|
335
|
+
`onCache` 回调接收一个包含以下属性的对象:
|
336
|
+
|
337
|
+
- `status`: 缓存操作状态,可以是:
|
338
|
+
- `hit`: 缓存命中,返回缓存内容
|
339
|
+
- `miss`: 缓存未命中,执行函数并缓存结果
|
340
|
+
- `stale`: 缓存命中但数据陈旧,返回缓存内容同时在后台重新验证
|
341
|
+
- `key`: 缓存键,可能是 `customKey` 的结果或默认生成的键
|
342
|
+
- `params`: 传递给缓存函数的参数
|
343
|
+
- `result`: 结果数据(来自缓存或新计算的)
|
344
|
+
|
345
|
+
这个回调只在提供 `options` 参数时被调用。当使用无 options 的缓存函数时,不会调用 `onCache` 回调。
|
346
|
+
|
347
|
+
`onCache` 回调对以下场景非常有用:
|
348
|
+
- 监控缓存性能
|
349
|
+
- 计算命中率
|
350
|
+
- 记录缓存操作
|
351
|
+
- 实现自定义指标
|
149
352
|
|
150
353
|
### 存储
|
151
354
|
|
@@ -164,3 +367,4 @@ configureCache({
|
|
164
367
|
maxSize: CacheSize.MB * 10, // 10MB
|
165
368
|
});
|
166
369
|
```
|
370
|
+
|
@@ -495,6 +495,78 @@ import Motivation from '@site-docs/components/convention-routing-motivation';
|
|
495
495
|
|
496
496
|
<Motivation />
|
497
497
|
|
498
|
+
## 升级到 react-router v7
|
499
|
+
|
500
|
+
React Router v7 相比 React Router v6 减少了包体积(小约 15%),提供了更高效的路由匹配算法,对 React 19 和 TypeScript 也提供了更好的支持,
|
501
|
+
相比 React Router v6 breaking change 非常少,同时 Modern.js 也对两个版本做了兼容,只需在项目中安装并注册相应的插件即可无缝升级。
|
502
|
+
|
503
|
+
:::info
|
504
|
+
|
505
|
+
更多 react router v6 到 react router v7 的变更,请查看[文档](https://reactrouter.com/upgrading/v6#upgrade-to-v7)
|
506
|
+
|
507
|
+
:::
|
508
|
+
|
509
|
+
### 环境要求
|
510
|
+
|
511
|
+
React Router v7 对环境有一定要求:
|
512
|
+
|
513
|
+
- Node.js 20+
|
514
|
+
- React 18+
|
515
|
+
- React DOM 18+
|
516
|
+
|
517
|
+
### 安装插件
|
518
|
+
|
519
|
+
首先,安装 Modern.js 的 React Router v7 插件:
|
520
|
+
|
521
|
+
```bash
|
522
|
+
pnpm add @modern-js/plugin-router-v7
|
523
|
+
```
|
524
|
+
|
525
|
+
### 配置插件
|
526
|
+
|
527
|
+
在 `modern.config.ts` 中注册插件:
|
528
|
+
|
529
|
+
```ts title="modern.config.ts"
|
530
|
+
import { routerPlugin } from '@modern-js/plugin-router-v7';
|
531
|
+
|
532
|
+
export default {
|
533
|
+
runtime: {
|
534
|
+
router: true,
|
535
|
+
},
|
536
|
+
plugins: [routerPlugin()],
|
537
|
+
};
|
538
|
+
```
|
539
|
+
|
540
|
+
### 修改代码
|
541
|
+
|
542
|
+
在 react router v7 中,不需要再使用 `defer` API 了,直接在 data loader 中返回数据即可:
|
543
|
+
|
544
|
+
```ts title="routes/page.data.ts"
|
545
|
+
import { defer } from '@modern-js/runtime/router';
|
546
|
+
|
547
|
+
export const loader = async ({ params }) => {
|
548
|
+
// 推荐的 v7 风格
|
549
|
+
const user = fetchUser(params.id)
|
550
|
+
return { user };
|
551
|
+
|
552
|
+
// v6 风格,Modern.js 做了兼容,仍然可以继续使用
|
553
|
+
return defer({ data: 'hello' });
|
554
|
+
};
|
555
|
+
```
|
556
|
+
|
557
|
+
react router v7 同样废弃了 `json` API:
|
558
|
+
|
559
|
+
```ts title="routes/page.data.ts"
|
560
|
+
export const loader = async ({ params }) => {
|
561
|
+
// 推荐的 v7 风格
|
562
|
+
return { data: 'hello' };
|
563
|
+
|
564
|
+
// v6 风格,Modern.js 做了兼容,仍然可以继续使用
|
565
|
+
return json({ data: 'hello' });
|
566
|
+
};
|
567
|
+
```
|
568
|
+
|
569
|
+
|
498
570
|
## 常见问题
|
499
571
|
|
500
572
|
1. 为什么要提供 `@modern-js/runtime/router` 来导出 React Router API ?
|
@@ -2,6 +2,12 @@
|
|
2
2
|
|
3
3
|
Modern.js 的 Runtime 插件允许您在应用程序的 React 代码运行时扩展和修改其行为。通过 Runtime 插件,您可以轻松地执行初始化任务、实现 React 高阶组件(HOC)封装等功能。
|
4
4
|
|
5
|
+
:::info
|
6
|
+
|
7
|
+
Runtime 插件需要通过 `src/modern.runtime.ts` 中的 [`plugins`](/configure/app/runtime/plugins) 字段配置。
|
8
|
+
|
9
|
+
:::
|
10
|
+
|
5
11
|
## 插件结构
|
6
12
|
|
7
13
|
一个典型的 Runtime 插件如下所示:
|
@@ -151,16 +157,35 @@ await hooks.onBeforeRender.call(myContext);
|
|
151
157
|
您可以组合使用多个钩子来实现更复杂的功能。例如,您可以使用 `onBeforeRender` 获取数据,然后使用 `wrapRoot` 将数据通过 Context 传递给整个应用:
|
152
158
|
|
153
159
|
```ts
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
});
|
158
|
-
|
159
|
-
|
160
|
-
return
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
import { RuntimePluginFuture, RuntimeReactContext } from '@modern-js/runtime';
|
161
|
+
import { useContext, createContext } from 'react';
|
162
|
+
|
163
|
+
export const ThemeContext = createContext<{ theme: string } | null>(null);
|
164
|
+
|
165
|
+
export const themePlugin = (): RuntimePluginFuture => {
|
166
|
+
return {
|
167
|
+
name: 'theme-plugin',
|
168
|
+
setup: api => {
|
169
|
+
api.onBeforeRender(async context => {
|
170
|
+
const userPreference = await fetch('/api/user/theme-settings').then(
|
171
|
+
res => res.json(),
|
172
|
+
);
|
173
|
+
context.data = {
|
174
|
+
theme: userPreference.theme,
|
175
|
+
};
|
176
|
+
});
|
177
|
+
|
178
|
+
api.wrapRoot(App => {
|
179
|
+
return props => {
|
180
|
+
const context = useContext(RuntimeReactContext);
|
181
|
+
return (
|
182
|
+
<ThemeContext.Provider value={context.data}>
|
183
|
+
<App {...props} />
|
184
|
+
</ThemeContext.Provider>
|
185
|
+
);
|
186
|
+
};
|
187
|
+
});
|
188
|
+
},
|
189
|
+
};
|
190
|
+
};
|
166
191
|
```
|
package/package.json
CHANGED
@@ -15,14 +15,14 @@
|
|
15
15
|
"modern",
|
16
16
|
"modern.js"
|
17
17
|
],
|
18
|
-
"version": "2.67.
|
18
|
+
"version": "2.67.5",
|
19
19
|
"publishConfig": {
|
20
20
|
"registry": "https://registry.npmjs.org/",
|
21
21
|
"access": "public"
|
22
22
|
},
|
23
23
|
"dependencies": {
|
24
24
|
"mermaid": "^11.4.1",
|
25
|
-
"@modern-js/sandpack-react": "2.67.
|
25
|
+
"@modern-js/sandpack-react": "2.67.5"
|
26
26
|
},
|
27
27
|
"devDependencies": {
|
28
28
|
"@rspress/shared": "1.43.11",
|
package/src/i18n/index.ts
CHANGED
File without changes
|
File without changes
|