Next.js 16 Cache Components 完全指南

基于 Next.js 16.0.1 官方文档整理

目录

  1. 什么是 Cache Components
  2. 核心工作原理
  3. 使用 Suspense 边界
  4. 使用 use cache
  5. 启用 Cache Components
  6. 从旧版本迁移
  7. 实战示例
  8. 最佳实践
  9. 和 Next-intl 结合
  10. 常见错误与解决方案
  11. FAQ
  12. 参考资料

这边文档主要是 AI 总结+我补充实际遇到的问题,大部分是 AI 写的。

注意,文档里不包含use cache: private的内容,在写的时候本来官方文档里说依赖unstable_prefetch,但是后来一看这个内容又被移除了,不知道后续会不会再改,先不写了,以官方文档为准。API Reference > Directives > use cache: private

注意,现在的 16.0 还在不断变化中,还是等 16.1,16.2 再用吧。这东西太不稳了。

Cache components除了方便的 PPR+显式缓存,另外一个就是在框架层面(主要是 dev 和构建的时候),防止用户写出动态内容卡住整个页面加载的事,这在之前很容易写出来,网上也有很多批评的文章和视频,一看连loading.tsxSuspense都不会用。😂
现在官方强制了,也是件好事吧。

什么是 Cache Components

Cache Components 是 Next.js 16 中一种新的渲染和缓存方法,通过 Partial Prerendering (PPR) 提供细粒度的缓存控制,同时确保出色的用户体验。

核心关系

1
Cache Components = PPR + use cache
  • PPR 提供静态外壳和流式传输基础设施
  • use cache 让你在外壳中包含优化的动态输出

解决的问题

在开发动态应用时,你需要在两种方式之间权衡:

  • 完全静态页面:加载快,但无法显示个性化或实时数据
  • 完全动态页面:可显示最新数据,但每次请求都需要渲染所有内容,导致初始加载慢

Read More

在容器中运行的mysql数据库定时备份脚本

单次备份直接跑:

1
docker exec -it mysql容器名/id mysqldump --all-databases -u用户 -p > ./mysql-backup/backup_$(date +%Y%m%d_%H%M).sql

命令行提示输入密码

注意使用--all-databases会连 mysql 本身内部数据库也导出。

批量定时让 AI 写了个脚本,改了几个版本,测试过没啥太大问题。

不过这个版本会把密码留在命令行里,我这里是单独建了个 localhost 能用的密码,不放心可以写临时文件/放环境变量等方法。

会创建当前时间的文件夹,里面按照每个数据库存放对应名字的 sql,设置了过期时间。

这个只能针对比较小的数据库备份,几 G 的无所谓,几十 G 上百 G 的就很慢了(这种业务量还是买云上的数据库吧)。

定时部分直接用 crontab 调这个脚本就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/bin/bash

# =================================================================
# Docker MySQL 数据库备份脚本
# - 为每次备份创建独立的、带时间戳的文件夹
# - 备份为纯 .sql 文件,不压缩
# - 仅在所有备份成功后,才清理旧的备份文件夹
# - 清理前,在日志中一次性记录所有将被删除的目录列表
# =================================================================

# --- 自定义配置 ---

# MySQL 容器名称
CONTAINER_NAME="your_mysql_container_name"

# MySQL 用户名 (推荐使用下面创建的 'backup' 用户)
MYSQL_USER="backup"

# MySQL 密码 (您为 'backup' 用户设置的密码)
MYSQL_PASSWORD="your_strong_password_here"

# 需要备份的数据库列表,多个数据库用空格隔开
# 例如: "db1 db2 db3"
DATABASE_NAMES="your_db_name1 your_db_name2"

# 备份文件存放的根目录
BACKUP_ROOT_DIR="/data/mysql_backups"

# 备份文件保留天数
RETENTION_DAYS=30

# 日志文件路径
LOG_FILE="${BACKUP_ROOT_DIR}/backup.log"

# --- 脚本主体 ---

# 1. 创建本次备份的专属文件夹
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
CURRENT_BACKUP_DIR="${BACKUP_ROOT_DIR}/${TIMESTAMP}"
mkdir -p ${CURRENT_BACKUP_DIR}

# --- 函数定义 ---
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> ${LOG_FILE}
}

# 2. 执行备份
log "开始备份任务,备份至目录: ${CURRENT_BACKUP_DIR}"
if [ -z "${DATABASE_NAMES}" ]; then
log "错误: 没有指定要备份的数据库 (DATABASE_NAMES 为空)。"
exit 1
fi

ALL_BACKUPS_SUCCEEDED=true
for DB_NAME in ${DATABASE_NAMES}
do
log "正在备份数据库: ${DB_NAME}"
BACKUP_FILE="${CURRENT_BACKUP_DIR}/${DB_NAME}.sql"
docker exec ${CONTAINER_NAME} /usr/bin/mysqldump -u${MYSQL_USER} -p${MYSQL_PASSWORD} --databases ${DB_NAME} --single-transaction > ${BACKUP_FILE}
if [ $? -eq 0 ]; then
log "数据库 ${DB_NAME} 备份成功, 文件: ${BACKUP_FILE}"
else
log "错误: 数据库 ${DB_NAME} 备份失败。"
ALL_BACKUPS_SUCCEEDED=false
rm -f ${BACKUP_FILE}
fi
done
log "所有数据库备份操作执行完毕"

# 3. 清理旧备份 (仅在所有备份都成功时执行)
if [ "${ALL_BACKUPS_SUCCEEDED}" = true ]; then
log "本次所有备份任务均成功,开始清理 ${RETENTION_DAYS} 天前的旧备份文件夹"

# --- 这里是修改的核心部分 ---
# 先找到所有要删除的目录,存入变量
DIRS_TO_DELETE=$(find ${BACKUP_ROOT_DIR} -type d -name "20[0-9][0-9]*_*" -mtime +${RETENTION_DAYS})

if [ -n "${DIRS_TO_DELETE}" ]; then
# 如果找到了需要删除的目录,则先记录日志,然后执行删除
log "将要删除以下旧备份目录:"
log "${DIRS_TO_DELETE}"
# 使用 xargs 来处理目录列表并删除
echo "${DIRS_TO_DELETE}" | xargs rm -rf
log "旧备份文件夹清理完成"
else
# 如果没有找到,也记录一下
log "没有找到需要清理的旧备份目录。"
fi
else
log "警告: 本次备份任务中存在失败项,将跳过清理旧备份的操作以确保数据安全。"
log "由于备份失败,本次创建的文件夹 ${CURRENT_BACKUP_DIR} 可能包含不完整的备份。"
fi

log "=========================================================="

timestamp存取差几小时? mysql timestamp的timezone问题以及如何在mysql2设置

在 Node.js 应用中使用 MySQL 时,时间戳(TIMESTAMP)字段出现的“8 小时差异”是一个经典难题。这个问题的根源并非单一因素,而是由 MySQL 自身的时区机制、mysql2 驱动的特定行为,以及一个极具迷惑性的默认配置共同造成的。

本文将澄清 MySQL TIMESTAMP 的存储与转换原理,并深入剖析 mysql2 驱动中 timezone 配置项的真正含义及其默认值'local'所带来的陷阱,最终提供两套清晰的最佳实践方案。

Read More

drizzle如何处理mysql的bit类型

mysql 的 boolean 类型其实是 tinyint(1)的别名,一些 ORM 工具无法识别把他识别到对应语言的 boolean 类型,日常实践有时候会选择用bit(1)这个类型,比如javaJOOQ,boolean 类型会变为 java 的Byte,而bit(1)则是 java 的Boolean

但是 drizzle 的 mysql 内置类型中没有bit(1)。你用他的drizzle-kit pull之后会返回这个结果:

1
2
// Warning: Can't parse bit(1) from database
// bit(1)Type: bit(1)("deleted").notNull(),

但是如果是已经建好的表,其他逻辑在用的话,把bit(1)改成boolean并不方便。

需要我们自己定义一个类型。

bit(1)这个类型不同驱动返回不同,有些可能是作为整数,有些可能是作为 Buffer。所以扩展一下就行:

Read More

Next.js 如何在客户端导航时获取上一页(referer)

想给之前上线的工具站做个博客数据统计: blogs

理所当然用到了document.referer,最方便的获取上一个页面的方式,结果发现获取到的都是第一次 load 的页面,而不是导航前的那个页面。

为什么会这样?

Next.js 在生产环境中默认采用前端导航(Client-side Navigation)的方式。这意味着页面加载完之后,在网站内部点击链接时,浏览器并不会执行一次完整的页面刷新。相反,Next.js 会在客户端通过 JavaScript 异步加载新页面的数据和组件,然后更新 DOM。

这种类似 单页应用(SPA) 的行为导致了一个关键问题:
document.referrer 的值在页面首次加载后保持不变。当通过内部链接从blog/zh/1导航到 blog/zh/post/[slug] 时,由于没有发生完整的页面重载,document.referrer 的值仍然会是最初访问网站的那个值,而不是blog/zh/1

Read More

Next.js RSC _rsc参数丢失的那些坑以及解决方案

最近在用 Next.js 的 RSC(React Server Component)时遇到了一个比较隐晦的问题,记录一下踩坑过程和应对方案。

如果你在项目里既使用了 CDN(并且缓存了 html),又使用了middleware的重定向(middleware 会处理 rsc 请求),又用了 RSC 特性(开启了 prefetch 等情况),如果你发现部分页面 html 变成了一大串“乱码”(其实是 rsc 请求的返回结果),可以仔细看看。

RSC 请求是怎么工作的?

Next.js 在请求 RSC 和 HTML 页面时,路径和方法其实是一样的,唯一的区别在于它会带上一个 _rsc 的参数和一些特定 header。

比如你访问页面 /about

  • HTML 请求
    GET /about
  • RSC 请求
    GET /about?_rsc=<随机字符串> 以及特定的 header

这里的 _rsc 参数是 Next.js 内部用来标识“这是一次 RSC 请求”,header 里也有类似 Next-Router-State-Tree, rsc 等用于数据请求和分割的内容。

Read More

[翻译]我如何使用 Claude Code

原文出处: https://spiess.dev/blog/how-i-use-claude-code

一个月前,我订阅了 Claude Max。在此之前,我已经使用包括 Claude Code 在内的 AI 代理一段时间了,但随着统一价格的推出,我的使用量猛增,它已成为我许多任务的日常驱动力。我发现自己现在去 VS Code 的次数少了很多。

由于 AI 代理目前对每个人来说都是新事物,我想分享一些我最近注意到模式可能会很有趣。以下是我如何使用 Claude code。

开始新对话 (Start New Threads)

如果说我希望你从这篇文章中学到一件事,那就是你应该更频繁地调用 /clear

AI 代理往往随着对话时间的延长而变得更不可预测。当你提出不同问题时尤其如此。我发现即使这意味着重复一些指令,创建一个新的提示通常会更有效。

一旦我开始更积极地这样做,我的结果就显著改善了。而且我绝对不是唯一一个提出这个建议的人。

Read More

Next.js使用auth.js+dirzzle+postgresql报错分析

在自己的测试项目里想着做登录功能,看到authjs就接到项目里去,本身就使用的drizzle,在不配置 db adapter 的情况下运行正常,但只要配置就会报错:

1
2
3
4
5
6
7
8
⨯ Error [TypeError]: Cannot read properties of undefined (reading 'reduce')
at <unknown> (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:709:27)
at runModuleExecutionHooks (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:755:9)
at instantiateModule (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:707:9)
at getOrInstantiateModuleFromParent (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:640:12)
at esmImport (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:143:20)
at [project]/src/db/db.ts [middleware-edge] (ecmascript) (.next\server\edge\chunks\[root of the server]__a687996d._.js:28:218)
at <unknown> (.next\server\edge\chunks\edge-wrapper_c7ecd8c0.js:709:27)

无法启动

Read More

显卡的TOPS AI算力比较

虽然自己没设备但喜欢聊 😀,和别人讨论的时候经常要反复查,查询一下汇总,有可能填错了。。。到时候发现错误再订正吧。

AMD 的没找到哪个表/文档里有算 TOPS 的…就不列了

N 卡

20 系到 40 系

GeForce RTX 20 系列

型号 架构 制程 (nm) 显存大小 显存类型 显存位宽 显存带宽 (GB/s) 峰值单精度 (FP32) TOPS (AI) TDP (W)
RTX 2080 Ti Turing 12 11GB GDDR6 352-bit 616 13.45 TFLOPS 114 TOPS 260
RTX 2080 Super Turing 12 8GB GDDR6 256-bit 496 11.15 TFLOPS 89 TOPS 250
RTX 2080 Turing 12 8GB GDDR6 256-bit 448 10.07 TFLOPS 81 TOPS 225
RTX 2070 Super Turing 12 8GB GDDR6 256-bit 448 9.06 TFLOPS 72 TOPS 215
RTX 2070 Turing 12 8GB GDDR6 256-bit 448 7.47 TFLOPS 65 TOPS 175
RTX 2060 Super Turing 12 8GB GDDR6 256-bit 448 7.19 TFLOPS 57 TOPS 175
RTX 2060 Turing 12 6GB GDDR6 192-bit 336 6.45 TFLOPS 52 TOPS 160

Read More