为什么我放弃了 Next.js Server Actions
1 min read

最近在重构一个中型项目时,我把所有的 Next.js Server Actions 都换掉了。这篇记录一下为什么。
一开始很美好
Server Actions 让你能在组件里”直接”调用服务端函数,省去了手写 API route 的样板代码:
async function createPost(formData: FormData) {
'use server';
await db.post.create({ title: formData.get('title') });
} 写 demo 的时候确实丝滑。但项目长大以后,问题开始浮现。
真正的痛点
- 类型边界模糊:客户端和服务端的代码混在一个文件里,重构时很容易把不该泄漏的依赖带到客户端。
- 错误处理割裂:表单提交失败时的状态管理,比传统的请求-响应模型更难统一。
- 可测试性下降:把数据访问藏在组件里,单元测试变得别扭。
我现在的做法
退回到清晰的分层:UI 只管渲染,数据访问集中在独立的模块里,边界一目了然。少了一点”魔法”,多了很多确定性。
// 组件里直接调用服务端,边界模糊
async function createPost(formData: FormData) {
'use server';
await db.post.create({ title: formData.get('title') });
} // 数据访问集中在独立模块,边界清晰
// lib/posts.ts
export async function createPost(input: PostInput) {
return db.post.create({ data: input });
}工具的便利,不该以牺牲架构的清晰为代价。
// related
开发日志
把博客搬到 SvelteKit + Cloudflare
从 WordPress 一路重做到 SvelteKit:记录这次站点重构的选型与取舍——静态、快、可维护。
开发日志
最好的备份,是没有需要备份的东西
2024 年,我把博客弄丢了两次——先是图床,后是数据库。两次我都怪「以后再备份」,可后来想明白,真正该删掉的不是侥幸心理,而是那些需要被备份的状态。
AI / 思考
LLM 是最后手段,不是默认手段
我本来打算把整个项目交给 agent 跑,结果 Codex 的套餐没撑过几个视频就见底了。这篇记一下那之后我是怎么一处一处把 LLM 从流水线里请下神坛,退回到无聊的死代码——以及我至今不敢确定,这到底是工程判断,还是只是我钱包的形状。
yen@harvey:~$ exit 0