Next.js 不是默认答案:我的前端框架选型思路
新建项目的时候,手已经习惯性敲出 create-next-app 了。
但我最近开的三个项目都没有用它。
不是因为它不好,而是因为它擅长解决的问题,恰好不是我要解决的问题。
先问三个问题,再谈框架
选框架之前,我更愿意先把这三件事定下来。它们比「哪个框架更流行」重要得多, 而且一旦定了,候选范围会自己缩小。
- 首屏内容需不需要被搜索引擎和分享卡片抓到?
- 第一屏渲染出来的东西,是不是每个人都一样?
- 部署环境允许什么——只放静态文件,还是可以有常驻的 Node 进程?
三个答案基本决定了渲染模式,而渲染模式基本决定了框架。 很多人反过来做——先选框架,再想办法把需求塞进去,最后在构建配置和缓存上面花掉大把时间。
四种形态,四种选择
| 形态 | 典型场景 | 渲染模式 | 我会选 |
|---|---|---|---|
| 纯内容 | 博客、文档、产品落地页 | 构建期静态生成 | Astro,或者干脆手写 HTML |
| 营销站 + 动态数据 | 首屏要个性化、又要被收录 | SSR / ISR | Next.js(App Router) |
| 后台与内部工具 | 登录后才看得到的数据表格 | 客户端渲染 | Vite + React Router |
| 交互密集的小应用 | 编辑器、看板、实时面板 | 客户端为主,必要时补 SSR | SvelteKit |
Next.js:强,但复杂度是要付账的
App Router 那套服务端组件加流式渲染确实强, 它把「数据在服务端取,UI 在客户端流式到达」变成了一件顺手的事。 但代价是:「这段代码在哪里执行」从一件不用想的事,变成了要一直想的事。
一个文件是 Server Component 还是 Client Component,决定了它能不能用 useState、
能不能直接读数据库、能不能拿到 window。
我见过不少项目,一半的沟通成本花在「这个组件为什么会报 hooks 错误」上。
另外两处需要提前想清楚的地方:
-
部署形态会被绑定。
standalone输出需要一个常驻 Node 进程(或 edge runtime); 想走纯静态托管,就得用静态导出,而那样大部分动态能力又用不上了。 -
缓存语义要专门学一遍。
fetch的默认缓存加上revalidate的组合, 在「数据一天变几次」的场景非常好用;但在「必须实时」的页面上需要显式关掉, 而这个开关很容易忘,忘了就是线上看到旧数据。
这些都不是缺点,是复杂度税。 当项目确实需要 SSR/ISR、也确实从中受益时,这笔税值得交; 当你只是需要一个三页的后台表格时,就是白交。
Astro:内容站的默认赢家
默认输出零 JavaScript,交互组件作为「岛」按需水合。 Markdown 进去、HTML 出来,构建产物就是一堆静态文件,扔给任何 nginx 都能跑。 博客、文档、落地页这类场景,它几乎没什么可挑的。
但它的优势来自「没有交互」。一旦页面上出现拖拽、实时筛选、复杂的表单联动, 岛与岛之间的状态共享就变得别扭,反而不如一开始就上 React。
Vite + React:后台工具的最优解
心智负担最低的一档:一个 index.html、一个入口文件,
构建产物是一堆静态资源。没有服务端渲染、没有运行时、没有缓存策略。
代价是路由、数据请求、鉴权拦截这些要自己补一遍。 但对后台来说,这些代价换来的东西根本用不上—— 用户登录之后才进来,不需要被搜索引擎收录,首屏白几百毫秒也无所谓。 为了一个内部表格引入 SSR,是我这几年做过最没必要的决定之一。
SvelteKit:写起来最舒服,但要考虑协作
响应式和状态是一等公民,同样的界面代码量明显更少,产物也小。 自己一个人做小应用时,它的开发体验是最好的。
需要权衡的是生态和人力:遇到冷门问题时答案更少, 团队里会用的人也更少。如果是长期多人维护的项目,这一条要算进去。
这个站点为什么是手写 HTML
十来个静态页面、零构建、零依赖。改一篇文章就是改一个文件,
传上去就生效,不需要 npm install,
也不会某天因为某个依赖的主版本升级导致构建失败。
它没用任何框架,不是因为框架不好,而是因为它的复杂度还没到需要框架的程度。 引入框架是为了解决「组件复用和状态管理」,而这个站点没有状态。
反过来说,如果哪天我要在这里加全文搜索、分页、或者几十篇文章, 我会先换 Astro —— 它能在保持「产物是静态 HTML」的前提下, 把重复的布局抽成组件。这个方向是对的:先保证产物形态不变,再谈工具升级。
两个实际踩过的坑
1. 把只读后台塞进 SSR 框架
那个后台一共三个页面,数据来自两个只读接口。 用了 SSR 框架之后,多了一个常驻进程、一套部署脚本, 还有一堆「为什么服务端渲染时拿不到 window」的问题。 最后换成 Vite 打包的静态文件,部署从「构建 + 重启服务」变成「覆盖一个目录」。
2. 在内容站上用了 SPA
首屏要等 JS 下载并执行完才出现内容,分享到聊天软件里没有摘要卡片, 搜索引擎抓到的几乎是一个空壳。改成构建期生成之后再没管过, 问题不是被优化掉的,是根本不存在了。
结论
先定渲染模式,再定部署形态,最后才选框架。 框架是可替换的,形态不是。
三五年后想换框架,只要产物还是「静态文件 + 一层接口」, 换起来大概是一周的事;但如果形态错了—— 该静态的做成了 SSR、该 SSR 的做成了纯客户端—— 换什么框架都救不回来。
所以现在我的默认动作不是敲 create-next-app,
而是先把上面那三个问题的答案写下来。写完之后,选型往往只剩一个候选。