Skip to content

Commit e69fd38

Browse files
committed
docs: update documentation translations
1 parent e64abb1 commit e69fd38

File tree

299 files changed

+42980
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

299 files changed

+42980
-0
lines changed

apps/docs/content/zh-hans/blog/building-apis-with-nextjs.mdx

Lines changed: 394 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
---
2+
source-updated-at: 2025-05-29T18:05:49.000Z
3+
translation-updated-at: 2025-05-29T19:43:25.738Z
4+
title: Next.js 的可组合式缓存方案
5+
description: 深入了解 'use cache' 的 API 设计及其优势
6+
author:
7+
- name: Lee Robinson
8+
image: /static/team/lee.jpg
9+
date: 2025-01-03T14:00:00.507Z
10+
image: >-
11+
https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/composable-caching/twitter-card.png
12+
---
13+
14+
我们正在为 Next.js 开发一套简单而强大的缓存模型。在之前的文章中,我们探讨了[缓存探索之旅](/blog/our-journey-with-caching)以及如何最终实现 `'use cache'` 指令。
15+
16+
本文将重点讨论 `'use cache'` 的 API 设计及其优势。
17+
18+
[什么是 `'use cache'`](#what-is-use-cache)
19+
--------------------------------------------
20+
21+
`'use cache'` 通过按需缓存数据或组件来提升应用性能。
22+
23+
这是一个 JavaScript "指令"——您添加到代码中的字符串字面量——它会告知 Next.js 编译器进入不同的"边界"。例如,从服务端切换到客户端。
24+
25+
这与 React 的 `'use client'``'use server'` 等指令理念相似。指令是定义代码运行位置的编译器指示,让框架能为您优化和编排各个代码片段。
26+
27+
[工作原理](#how-does-it-work)
28+
--------------------------------------
29+
30+
从一个简单示例开始:
31+
32+
```
33+
async function getUser(id) {
34+
'use cache';
35+
let res = await fetch(`https://api.vercel.app/user/${id}`);
36+
return res.json();
37+
}
38+
```
39+
40+
在底层,由于 `'use cache'` 指令,Next.js 会将此代码转换为服务端函数。编译期间,会找到该缓存条目的"依赖项"并将其作为缓存键的一部分。
41+
42+
例如,`id` 成为缓存键的一部分。如果我们多次调用 `getUser(1)`,会返回缓存服务端函数的记忆化输出。更改此值将在缓存中创建新条目。
43+
44+
再看一个在服务端组件中使用缓存函数和[闭包](https://v0.dev/chat/5kD47RIecQK?b=b_rCP4CvfbFFW)的例子:
45+
46+
```
47+
function Profile({ id }) {
48+
async function getNotifications(index, limit) {
49+
'use cache';
50+
return await db
51+
.select()
52+
.from(notifications)
53+
.limit(limit)
54+
.offset(index)
55+
.where(eq(notifications.userId, id));
56+
}
57+
58+
return <User notifications={getNotifications} />;
59+
}
60+
```
61+
62+
这个例子更复杂。您能找出需要作为缓存键的所有依赖项吗?
63+
64+
参数 `index``limit` 很直观——如果这些值改变,我们会选择通知的不同分片。但用户 `id` 呢?它的值来自父组件。
65+
66+
编译器能理解 `getNotifications` 也依赖于 `id`,其值会自动包含在缓存键中。这避免了因缓存键中依赖项错误或缺失导致的整个缓存问题类别。
67+
68+
[为何不使用缓存函数?](#why-not-use-a-cache-function)
69+
--------------------------------------------------------------
70+
71+
回顾上一个例子。我们是否可以用 `cache()` 函数替代指令?
72+
73+
```
74+
function Profile({ id }) {
75+
async function getNotifications(index, limit) {
76+
return await cache(async () => {
77+
return await db
78+
.select()
79+
.from(notifications)
80+
.limit(limit)
81+
.offset(index)
82+
// 糟糕!如何将 id 包含在缓存键中?
83+
.where(eq(notifications.userId, id));
84+
});
85+
}
86+
87+
return <User notifications={getNotifications} />;
88+
}
89+
```
90+
91+
`cache()` 函数无法查看闭包并识别 `id` 值应作为缓存键的一部分。您需要手动指定 `id` 为键的一部分。如果忘记或操作不当,可能导致缓存冲突或数据过时。
92+
93+
闭包可以捕获各种局部变量。简单处理可能会意外包含(或遗漏)您未预期的变量。这会导致缓存错误数据,或者如果敏感信息泄露到缓存键中,可能引发缓存污染风险。
94+
95+
`'use cache'` 为编译器提供了足够上下文来安全处理闭包并正确生成缓存键。纯运行时方案(如 `cache()`)需要您手动完成所有操作——很容易出错。相比之下,指令可通过静态分析可靠处理所有底层依赖。
96+
97+
[如何处理不可序列化的输入值?](#how-are-non-serialized-input-values-handled)
98+
--------------------------------------------------------------------------------------------
99+
100+
我们有两种不同类型的缓存输入值:
101+
102+
* **可序列化**:指输入可转换为稳定、基于字符串的格式且不丢失意义。虽然很多人首先想到 `JSON.stringify`,但我们实际使用 React 的序列化(如通过服务端组件)处理更广泛的输入——包括 Promise、循环数据结构和其它复杂对象。这超出了普通 JSON 的能力范围。
103+
* **不可序列化**:这些输入不是缓存键的一部分。尝试缓存这些值时,我们会返回服务端"引用"。Next.js 在运行时使用该引用恢复原始值。
104+
105+
假设我们记得在缓存键中包含 `id`
106+
107+
```
108+
await cache(async () => {
109+
return await db
110+
.select()
111+
.from(notifications)
112+
.limit(limit)
113+
.offset(index)
114+
.where(eq(notifications.userId, id));
115+
}, [id, index, limit]);
116+
```
117+
118+
如果输入值可序列化,这能正常工作。但如果 `id` 是 React 元素或更复杂的值,我们就需要手动序列化输入键。考虑一个基于 `id` 属性获取当前用户的服务端组件:
119+
120+
```
121+
async function Profile({ id, children }) {
122+
'use cache';
123+
const user = await getUser(id);
124+
125+
return (
126+
<>
127+
<h1>{user.name}</h1>
128+
{/* 更改 children 不会破坏缓存...为什么? */}
129+
{children}
130+
</>
131+
);
132+
}
133+
```
134+
135+
逐步解析其工作原理:
136+
137+
1. 编译期间,Next.js 看到 `'use cache'` 指令并将代码转换为支持缓存的特殊服务端函数。编译时不进行缓存,而是 Next.js 建立运行时缓存所需的机制。
138+
2. 当代码调用"缓存函数"时,Next.js 序列化函数参数。任何不能直接序列化的内容(如 JSX)会被替换为"引用"占位符。
139+
3. Next.js 检查给定序列化参数是否存在缓存结果。如果未找到结果,函数会计算新值进行缓存。
140+
4. 函数完成后,返回值被序列化。返回值的不可序列化部分会转换回引用。
141+
5. 调用缓存函数的代码反序列化输出并评估引用。这使得 Next.js 能用实际对象或值替换引用,意味着像 `children` 这样的不可序列化输入可以保持其原始、未缓存的值。
142+
143+
这意味着我们可以安全地仅缓存 `<Profile>` 组件而不缓存子组件。在后续渲染中,不会再次调用 `getUser()``children` 的值可能是动态的,或是具有不同缓存生命周期的单独缓存元素。这就是可组合式缓存。
144+
145+
[似曾相识...](#this-seems-familiar)
146+
--------------------------------------------
147+
148+
如果您觉得"这感觉与服务端和客户端组合的模式相同"——完全正确。这有时被称为"甜甜圈"模式:
149+
150+
* **外层**甜甜圈是处理数据获取或重型逻辑的服务端组件
151+
* **中间**孔洞是可能具有交互性的子组件
152+
153+
```tsx filename="app/page.tsx"
154+
export default function Page() {
155+
return (
156+
<ServerComponent>
157+
{/* 创建一个通向客户端的孔洞 */}
158+
<ClientComponent />
159+
<ServerComponent />
160+
);
161+
}
162+
```
163+
164+
`'use cache'` 同理。甜甜圈是外层组件的缓存值,孔洞是在运行时填充的引用。这就是为什么更改 `children` 不会使整个缓存输出失效。子组件只是稍后填充的引用。
165+
166+
[标签与失效机制](#what-about-tagging-and-invalidation)
167+
----------------------------------------------------------------------------
168+
169+
您可以通过不同[配置文件](/docs/app/api-reference/functions/cacheLife)定义缓存生命周期。我们提供一组默认配置,但您也可以根据需要定义自定义值。
170+
171+
```
172+
async function getUser(id) {
173+
'use cache';
174+
cacheLife('hours');
175+
let res = await fetch(`https://api.vercel.app/user/${id}`);
176+
return res.json();
177+
}
178+
```
179+
180+
要使特定缓存条目失效,您可以[标记缓存](/docs/app/api-reference/functions/cacheTag)然后调用 `revalidateTag()`。一个强大模式是您可以在获取数据后(例如从 CMS)标记缓存:
181+
182+
```
183+
async function getPost(postId) {
184+
'use cache';
185+
let res = await fetch(`https://api.vercel.app/blog/${postId}`);
186+
let data = await res.json();
187+
cacheTag(postId, data.authorId);
188+
return data;
189+
}
190+
```
191+
192+
[简单而强大](#simple-and-powerful)
193+
-------------------------------------------
194+
195+
我们设计 `'use cache'` 的目标是让缓存逻辑编写既简单又强大。
196+
197+
* **简单**:您可以通过局部推理创建缓存条目。无需担心全局副作用,如遗忘缓存键条目或意外更改代码库其它部分。
198+
* **强大**:您可以缓存不仅仅是静态可分析代码。例如,运行时可能变化的值,但您仍希望缓存评估后的输出结果。
199+
200+
`'use cache` 在 Next.js 中仍处于**实验阶段**。我们期待您试用后的早期反馈。
201+
202+
[查阅文档了解更多](/docs/app/api-reference/directives/use-cache)。
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
source-updated-at: 2025-05-29T18:05:49.000Z
3+
translation-updated-at: 2025-05-29T19:42:29.584Z
4+
title: 介绍 Create Next App
5+
description: >-
6+
今天我们很高兴推出全新的 Create Next App。通过一条命令,Create Next App 就能搭建一个基于 Next.js 的现代化 React 应用。
7+
author:
8+
- name: Joe Haddad
9+
image: /static/team/timer.jpg
10+
- name: Tim Neutkens
11+
image: /static/team/tim.jpg
12+
date: 2019-10-09T15:02:30.543Z
13+
image: >-
14+
https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/create-next-app/twitter-card.png
15+
---
16+
17+
今天我们很高兴向大家介绍全新的 Create Next App。
18+
19+
通过一条命令,Create Next App 就能搭建一个基于 Next.js 的现代化 React 应用。
20+
21+
只需运行以下命令即可开始使用:
22+
23+
```bash filename="Terminal"
24+
npx create-next-app
25+
```
26+
27+
Create Next App 经过彻底重构,旨在提供最佳的开发者体验:
28+
29+
* **交互式体验**:现在运行不带参数的 `npx create-next-app` 会启动交互式引导流程,帮助您完成项目设置。
30+
* **零依赖**:项目初始化现在最快只需 **1 秒**。Create Next App 零依赖,安装包仅 **604 kB**。优化前的旧版本为 **5.38 MB**,体积减少了超过 **4.7 MB**
31+
* **离线支持**:Create Next App 会自动检测离线状态,并使用本地包缓存来初始化项目。
32+
* **新的默认项目模板**:采用专为现代 Next.js 应用设计的新模板。由于 Create Next App 现在与 Next.js 同步维护,该模板将始终与最新版 Next.js 保持同步!
33+
* **示例支持**:可以从 [Next.js 示例库](https://github.com/vercel/next.js/tree/canary/examples) 中选择示例来初始化应用(例如 `npx create-next-app --example api-routes`)。
34+
* **经过测试**:该包属于 Next.js 单体仓库,使用与 Next.js 相同的集成测试套件进行测试,确保每个版本都能如期工作。
35+
36+
Create Next App 之前是一个由 [社区维护](https://open.segment.com/create-next-app/) 的项目,但我们认为有必要精心打造用户对 Next.js 的第一印象。特别是当我们在 [Next.js 示例库](https://github.com/vercel/next.js/tree/canary/examples) 中推荐它时。
37+
38+
我们与 [Segment](https://segment.com/) 合作完成了包的归属权转移,特别感谢 [Fouad Matin](https://twitter.com/fouadmatin) 等人前期的维护工作。
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
source-updated-at: 2025-05-29T18:05:49.000Z
3+
translation-updated-at: 2025-05-29T19:42:36.412Z
4+
title: 渐进式采用 Next.js
5+
description: >-
6+
了解将 Next.js 逐步引入开发工作流的不同策略。
7+
author:
8+
- name: Lee Robinson
9+
image: /static/team/lee.jpg
10+
date: 2020-11-18T14:00:00.507Z
11+
image: >-
12+
https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/incremental-adoption/twitter-card.png
13+
---
14+
15+
[Next.js](https://nextjs.org/) 专为渐进式采用而设计。通过 Next.js,您可以继续使用现有代码并按需添加任意多(或少)的 React 功能。从小规模开始并逐步添加更多页面,可以避免完全重写导致的功能开发脱轨。
16+
17+
许多公司需要现代化其技术栈以降低成本、提高开发效率并为客户提供最佳体验。组件驱动开发显著提升了现代代码库的部署速度和可复用性。
18+
19+
凭借每月超过 [800 万次下载量](https://www.npmtrends.com/react),React 已成为开发者首选的组件驱动方案。作为生产级 React 框架,Next.js 让您能够逐步采用 React。
20+
21+
[动机](#motivation)
22+
-------------------------
23+
24+
在移动优先的时代,优化和追踪 [核心网页指标](/analytics) 对成功至关重要。您的客户可能分布在全球各地,网络速度参差不齐。页面加载或操作完成每多花一秒(甚至毫秒),都可能影响销售、展示或转化效果。
25+
26+
若您正在现代化技术栈,可能面临以下挑战:
27+
28+
* 应用存在多年遗留代码,难以维护且完全重写需耗费数年(及数百万美元)
29+
* 随着应用规模和复杂度增长,页面加载时间持续增加,简单营销页与复杂页面同样缓慢
30+
* 尝试扩展开发团队时,难以在现有代码库中新增开发人员
31+
* CI/CD 和 DevOps 流程过时,降低开发效率且难安全可靠地发布变更
32+
* 应用未针对移动设备优化,且无法更新全局样式而不破坏其他部分
33+
34+
您知道需要采取行动,但可能对[从何开始](https://www.psychologytoday.com/us/blog/mindfully-present-fully-alive/201804/the-only-way-eat-elephant)感到茫然。通过渐进式采用 Next.js,您可以逐步解决上述问题并改造应用。下面探讨几种在现有技术栈中引入 Next.js 的策略。
35+
36+
[策略](#strategies)
37+
-------------------------
38+
39+
### [子路径](#subpath)
40+
41+
首项策略是配置服务器或代理,使特定子路径下的所有内容指向 Next.js 应用。例如,现有网站位于 `example.com`,可配置代理使 `example.com/store` 提供 Next.js 电商应用。
42+
43+
使用 [`basePath`](/docs/pages/api-reference/next-config-js/basePath) 可配置 Next.js 应用的资源与链接,使其自动适配新子路径 `/store`。由于 Next.js 中每个页面都是[独立路由](/docs/pages/building-your-application/routing)`pages/products.js` 等页面将路由至应用内的 `example.com/store/products`
44+
45+
```js filename="next.config.js"
46+
module.exports = {
47+
basePath: '/store',
48+
};
49+
```
50+
51+
了解更多关于 `basePath` 的信息,请参阅[文档](/docs/pages/api-reference/next-config-js/basePath)
52+
53+
**注意:** 此功能需 Next.js 9.5 及以上版本。若使用旧版,请先升级。)
54+
55+
### [重定向](#rewrites)
56+
57+
第二项策略是创建指向域名根 URL 的新 Next.js 应用,然后在 `next.config.js` 中使用 [`rewrites`](/docs/pages/api-reference/next-config-js/rewrites) 将部分子路径代理至现有应用。
58+
59+
例如,假设您创建了从 `example.com` 提供服务的 Next.js 应用,并配置如下 `next.config.js`。现在,已添加到该 Next.js 应用的页面请求(如添加了 `pages/about.js` 后的 `/about`)将由 Next.js 处理,其他路由请求(如 `/dashboard`)将代理至 `proxy.example.com`
60+
61+
```js filename="next.config.js"
62+
module.exports = {
63+
async rewrites() {
64+
return [
65+
// 需定义无操作重定向以优先检查所有页面/静态文件
66+
{
67+
source: '/:path*',
68+
destination: '/:path*',
69+
},
70+
{
71+
source: '/:path*',
72+
destination: `https://proxy.example.com/:path*`,
73+
},
74+
];
75+
},
76+
};
77+
```
78+
79+
了解更多关于重定向的信息,请参阅[文档](/docs/pages/api-reference/next-config-js/rewrites)
80+
81+
### [微前端与单体仓库及子域名](#micro-frontends-with-monorepos-and-subdomains)
82+
83+
Next.js 与 [Vercel](https://vercel.com) 能轻松实现[微前端](https://martinfowler.com/articles/micro-frontends.html)架构,并支持以[单体仓库](https://vercel.com/blog/monorepos)形式部署。这允许通过[子域名](https://zh.wikipedia.org/wiki/子域名)逐步引入新应用。微前端的优势包括:
84+
85+
* 更小、内聚性更强且更易维护的代码库
86+
* 组织结构更灵活,团队可解耦自治
87+
* 能以渐进方式升级、更新甚至重写部分前端
88+
89+
![](https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/incremental-adoption/light-arch.png)
90+
91+
> 部署至 Vercel 的单体仓库架构示例
92+
93+
设置好单体仓库后,照常推送更改至 Git 仓库,您将看到提交被部署到已连接的 Vercel 项目。告别过时的 CI/CD 流程。
94+
95+
![](https://h8DxKfmAPhn8O0p3.public.blob.vercel-storage.com/static/blog/incremental-adoption/dark-comment.png)
96+
97+
> Git 集成提供的部署 URL 示例
98+
99+
[结论](#conclusion)
100+
-------------------------
101+
102+
Next.js 专为渐进式融入现有技术栈而设计。Vercel 平台通过与 GitHub、GitLab 和 Bitbucket 无缝集成,为每次代码变更提供部署预览,使其成为协作式体验。
103+
104+
* 通过[快速刷新](/docs/architecture/fast-refresh)即时本地预览变更,提升开发效率
105+
* 推送变更创建[分支预览](https://vercel.com/github),优化与利益相关者的协作
106+
* 合并 PR 后通过 [Vercel](https://vercel.com) 部署至生产环境,无需复杂 DevOps
107+
108+
了解更多,请阅读关于[子路径](/docs/pages/api-reference/next-config-js/basePath)[重定向](/docs/pages/api-reference/next-config-js/rewrites)的文档,或[部署微前端示例](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/with-zones)

0 commit comments

Comments
 (0)