Appearance
前端技术选型记录
技术选型讨论里最常见的问题是“React 还是 Vue?”“Webpack 还是 Vite?”。但这种问法默认假设了“存在一个天然更好的技术”。
实际工程里,技术选型的正确问题是:在当前约束下,哪个选择的总成本最低,且风险可控?
总成本的构成:
text
总成本 = 学习成本 × 团队规模
+ 开发成本 × 项目周期
+ 维护成本 × 预期寿命
+ 迁移成本(未来如果要换)
+ 招聘成本(现在和将来)
+ 生态风险溢价(该技术被淘汰的概率 × 迁移成本)每一项都是可估算的。技术选型不是做选择题,是做成本核算。
一个被忽略的前提:你真的需要选吗
很多选型讨论的起点是"我们要选一个 X"。但在讨论具体选项之前,先问一句:现有技术栈能不能做?
能做的标准:核心业务流程能跑通,性能在可接受范围内。如果能做,选新技术需要额外的理由来证明迁移成本值得——新技术的收益必须大于切换成本。
这个前置判断通常能过滤掉大量并不成立的选型需求,剩下的部分才值得继续做对比分析。
选型的四个约束维度
团队的约束
团队是技术选型里最硬的约束,因为人比代码难改。
- 现有技能栈:如果 5 人团队里 4 人熟 Vue,选 React 意味着至少 2-4 周的生产力真空。这个成本必须被新技术的收益覆盖。
- 团队规模:1-3 人的团队和 20+ 人的团队对工具链的要求截然不同。小团队可以容忍"配置多一点"因为没人需要共享配置;大团队需要"零配置"因为配置的一致性成本随人数指数增长。
- 是否有专人维护基础设施? 如果没有——大部分中小团队没有——就要避免需要深度定制的方案。选了需要自定义 plugin 的 Webpack 配置而没人在团队里真正了解 Webpack 内部机制,这是在给自己埋坑。
项目的约束
- 生命周期:3 个月的活动页和 3 年的管理系统,选型逻辑完全不同。短期项目可以忍受的技术债,长期项目会被复利放大。
- 性能要求:ToC 高流量(百万 UV)和 ToB 后台管理(几百 UV)对 bundle size、首屏加载、运行时性能的要求差 1-2 个数量级。
- 交互复杂度:富文本编辑器、实时协作、拖拽、大量表单、数据可视化——每一种都对技术栈有特定的要求(比如拖拽需要细粒度 DOM 控制,实时协作需要 CRDT/OT 库的生态支持)。
- SEO 需求:如果需要 SSR/SSG,框架选择空间会大幅缩小(Next.js / Nuxt 成为强绑定选项)。
- 浏览器兼容性:需要支持 IE11?你的选型空间是 2015 年的前端生态。
生态的约束
生态不只是"npm 包多不多"。更关键的指标:
- 维护活跃度:issue 响应时间、PR merge 速度、release 频率。一个半年没发版的项目,即使 GitHub stars 再多也是有风险的。
- Breaking change 频率和迁移成本:Angular 从 1 到 2 的重写,React Router 从 v4 到 v6 的 API 变更——大版本升级的平滑程度是生态成熟度的重要指标。
- 和现有技术栈的兼容性:选了某个构建工具,它和现有的 ESLint/Prettier/TypeScript 配置是否冲突?
长期的约束
- 技术生命周期位置:在 Gartner Hype Cycle 的哪个阶段?炒作期的新技术有最高风险——大部分炒作期的技术会在 2-3 年内消失。
- 迁移成本预估:如果未来要换,代价多大?这取决于该技术在架构中的"接触面积"——框架的接触面积最大(换框架=重写),工具链次之(换构建工具=改配置),状态管理库更小(换状态管理=逐步替换)。
- 招聘市场:该技术的人才供给是否充足?招聘难度和成本直接转化为项目的长期人力成本。
框架选型:Runtime Model 才是深层差异
React 和 Vue 的对比远不止"JSX vs 模板语法"。两者的运行时模型有根本差异,而这个差异决定了大型项目中的代码组织方式和性能特征。
React: Fiber Reconciler + Lane Model
React 的运行时核心是 Fiber reconciler——一个可中断的协调器。
text
状态更新 → 创建 update 对象 → 分配 lane(优先级)
→ scheduler 调度 → 时间切片执行 Fiber 遍历
→ render 阶段(可中断)→ commit 阶段(不可中断)→ DOM 更新关键特性:
- 可中断渲染:render 阶段可以被更高优先级的更新打断(concurrent mode 的基础)。用户输入可以跳过正在渲染的列表更新。
- Lane 优先级模型:不同类型更新分配不同 lane。useTransition 把高优先级的 UI 更新标记为低优先级,让出主线程给用户交互——这是 React 18+ concurrent features 的核心。
- 重新执行整个组件函数:每次状态变化,React 重新执行组件函数。hooks 必须在每次渲染中以相同顺序调用。这导致了"闭包陷阱"(stale closure)——useEffect 的依赖数组是手动管理的,漏了依赖就是 bug。
- 虚拟 DOM diff:O(N) 的树比较。React 19 的 React Compiler(React Forget)通过编译时优化自动 memoize,减少了不必要的 re-render——但从运行时 diff 到编译时优化的转变本身说明虚拟 DOM 有性能成本。
Vue 3: Proxy Reactivity + Scheduler
Vue 3 的运行时核心是 Proxy-based 响应式系统 + effect scheduler。
text
状态定义(ref/reactive)→ Proxy 拦截读写 → track(收集依赖)
→ 状态变更 → trigger(通知 effect)
→ scheduler 入队 → nextTick flush → DOM 更新关键特性:
- 精确的依赖追踪:编译时就知道哪个模板片段依赖哪个状态。状态变化时只更新依赖该状态的部分,不需要 diff 整棵树。
- 自动依赖收集:不需要手动管理依赖数组。effect 执行期间读取的响应式状态自动被追踪。这意味着没有 stale closure 问题。
- Scheduler 的微妙行为:同一个 tick 内的多次状态修改被合并。
nextTick是所有同步修改完成后的一个微任务。这在复杂组件树中的表现和 React 的并发模式不同——Vue 是"同步收集 + 异步 flush",React 是"时间切片 + 优先级中断"。 - 编译时优化:
<script setup>+ SFC 编译让 Vue 编译器可以做静态分析——静态节点提升、patch flag、block tree。这些编译时优化减少的是运行时 diff 的开销。
这个差异在选型中意味着什么
React 更适合:需要细粒度调度控制的场景(大量并发更新、需要区分优先级的 UI)、需要利用并发特性(Suspense、Transitions)的场景、以及团队已经在 React 生态中有深厚积累的场景。
Vue 更适合:追求开发效率的场景(自动依赖追踪减少心智负担)、中小型项目快速迭代、以及团队偏好模板/声明式语法而非 JSX 的场景。
但关键是:这个选择在项目启动后 6-12 个月才会真正表现出差异。大多数项目的技术挑战不在框架层,在业务逻辑层。选错框架的损失远小于选错架构的损失。
构建工具:Vite 为什么赢了
当前这类构建工具的格局已经比较清晰:
- 新项目默认 Vite。ESM 按需编译 + esbuild 预打包,开发服务器冷启动 < 1s。生产构建用 Rollup(Vite 6+ 已切换到 Rolldown)。
- 老项目保留 Webpack。存量项目迁移构建工具的成本(配置重写 + plugin 兼容 + 团队学习)通常大于收益。
- Next.js 项目默认 Turbopack。Rust 实现,增量编译速度是 Webpack 的 10-100x。但独立使用 Turbopack 的场景还不多——它主要作为 Next.js 的内置引擎。
选择逻辑不是“哪个更快”,而是“哪个和项目生命周期更匹配”。如果是一个 Webpack 老项目,继续保留 Webpack 往往也是合理选择,因为迁移到 Vite 省下的冷启动时间,未必能覆盖迁移本身的成本。
状态管理的选型逻辑也类似,但围绕另一个核心矛盾展开。
状态管理:从必需品到可选品
2026 年,状态管理库的定位发生了根本变化。React 的 useContext + useReducer、Vue 的 reactive() + provide/inject 已经覆盖了大量原本需要状态管理库的场景。
选择状态管理库之前,先问:你面临的是状态共享问题,还是状态管理问题?
状态共享(跨组件共享数据):Context / provide/inject 就够了。 状态管理(复杂的状态转换、中间件、持久化、跨 Tab 同步):需要库。
如果确定需要库,按复杂度递减排列:
- Redux Toolkit:老项目大量存在,新项目很少选。Redux 的核心问题是概念负担——actions、reducers、middleware、selectors——每个都是可独立移除的复杂度,但加起来就是显著的认知负担。
- Zustand:React 社区的轻量首选。没有 Provider 嵌套,没有 action type 常量,API 就是
create((set) => ({...}))。TypeScript 支持好。适合大多数需要状态管理的场景。 - Pinia:Vue 3 官方推荐。和 Composition API 的 setup store 语法天然贴合。模块化设计让每个 store 独立。
- Jotai:原子化路线。状态被拆分为最小的原子(atom),每个 atom 独立更新。适合需要细粒度更新、组件只需要特定数据切片的场景。
- Valtio:Proxy 路线。直接 mutate 对象,框架自动追踪变化。API 直觉化但"魔法感"强,大型项目中调试较难。
一个常见现象是:状态管理库的复杂度并不会随着项目规模线性增长。很多大型项目(100+ 开发者)用 Context + custom hooks 就够了,而一些小型项目却引入了 Redux + Saga + Toolkit + RTK Query 的完整组合。过度使用状态管理库,本质上还是过度设计。
选型方法:PoC + ADR + 风险备案
PoC 必须验证什么
任何影响超过一个模块的技术选择,必须先做 PoC。但不是所有的 PoC 都有价值。
有效的 PoC 验证 3 件事:
- 核心业务流程能跑通。不是 demo,是你项目里最复杂的那个业务流程。
- 性能瓶颈点可接受。不是"感觉不卡",是有 profiling 数据。
- 团队学习成本符合预期。给团队 1-3 天时间用新技术做一个真实功能(不是 todo list),看实际耗时。
PoC 时间上限:3 天。3 天还跑不通核心流程,说明要么技术选型有问题,要么团队学习曲线太陡。两种情况都应该重新评估。
ADR 怎么写才有用
大部分 ADR(Architecture Decision Record)写了等于白写——记录了"选了 X"但没有记录"为什么选 X 而不是 Y"以及"在什么条件下重新评估"。
有效的 ADR 至少包含:
markdown
// ADR-001: 选择 React 18+ 作为前端框架
## 约束
- 团队 5 人:4 人 React 经验 1-3 年,1 人无前端经验
- 项目预期 3 年维护周期
- 包含复杂表单(100+ 字段)和实时数据面板
- 需要 SEO → SSR 必选
- 招聘市场:团队在深圳,React 人才供给充足
## 决策
React 18+ + Next.js 14(App Router)
## 考虑过但未选择的方案
- Vue 3 + Nuxt 3:性能更优,自动依赖追踪减少 bug,但团队经验不足(需要 2-3 周学习期)
- Angular 17:过于重型,项目不需要 DI / RxJS 的复杂度
## 代价
- React hooks 的闭包陷阱需要团队培训
- 需要选择 SSR 方案 → 额外 ADR
- Concurrent features 的学习成本
## 风险备案
- React 框架版本升级:React 大版本间 API 变化小,迁移成本低(已验证)
- Next.js 版本升级:App Router 仍在快速迭代,需关注 breaking change
## 复审触发条件
- 团队 Vue 经验积累到 ≥3 人 → 重新评估迁移可能性
- Next.js 出现重大安全/性能缺陷 → 评估 Remix 或其他方案
- 项目规模扩大至 20+ 开发者 → 评估微前端/MF 架构
## 复审日期
最迟 2027 年 Q2关键:ADR 最重要的是"复审触发条件"。技术环境在变,团队在变,项目需求在变。当时正确的决策,2 年后可能是错的。ADR 的价值不是固化决策,是提供重新评估的起点。
风险备案不是走过场
每个选型决策的风险备案要回答三个问题:
- 如果该技术 2 年后停止维护,Plan B 是什么? 具体到可以用什么替代、迁移路径多长。
- 如果关键成员离职导致该技术无人深入理解,怎么办? 至少要保证有 2 个人对该技术达到"能独立排障"的水平。如果做不到,该技术不应该被引入。
- 如果大版本升级 breaking change 太大,怎么平滑迁移? 这决定了是选"激进升级频繁"的技术还是"保守但稳定"的技术。
这件事通常没有完美答案,但必须提前备案。技术选型最大的风险不是某次判断失误,而是决策时根本没有为失误预留退路。
选型陷阱:我在生产里见过最多的 5 个
1. 为 3 个页面选了微前端
症状:一个 5 人的团队,做一个 3 页面的运营平台,选了 qiankun + Module Federation。
根因通常是把“大厂在用”直接等同于“当前项目需要”。微前端解决的是多团队协作下的治理问题,而不是单纯的技术问题。如果组织里并不存在多个独立团队分别维护不同模块,微前端大多只会增加复杂度。
2. 在炒作期引入了未验证的技术
判断一个技术是否"经过了生产验证",看一点:是否有 ≥2 个与你项目规模和场景相似的公司,在生产环境用了 ≥6 个月。如果没有,它就是早期采用者风险。
Bun 在 2023-2024 年很热,但到 2026 年,真正在生产中大面积使用 Bun 替代 Node.js 的公司依然不多。不是说 Bun 不好,是说它的风险溢价高于更成熟的方案。你愿意为"开发速度快 2x"付出"遇到 bug 时 Google 不到答案"的代价吗?对创业公司可能是 yes,对金融机构是 no。
3. 过度设计状态管理
为 5 个 API 接口、3 个表单的状态引入 Redux + Saga + RTK Query。实际用 Context + react-query(或 VueUse + Pinia)就够。
诊断方法:数一下你的 action type 常量有几个。如果 < 10 个,你不需要 Redux。
4. "团队成员都不会"的技术被选中
选了 Elm 或 ReasonML——技术上可能很好,但:
- 团队需要 3 个月的陡峭学习曲线
- 招到合格候选人的周期是 6 个月
- 离职一个人,整个技术栈的知识断层就出现了
这种技术选择的真实成本不是技术本身,是人力市场的供需失衡。
5. 技术栈"组合爆炸"
一个项目同时引入:React 19 + Next.js 15 + TypeScript 5 + Tailwind 4 + Zustand + TanStack Query + React Hook Form + Zod + Framer Motion + Radix UI + ...(继续列出 20 个依赖)
每一个库都是合理的,但合在一起构成了"学习债务"——新成员 onboard 需要理解 20+ 个库的 API 和它们之间的交互。技术选型的一个隐性原则:每引入一个新依赖,必须有一个人能说清楚它解决什么问题是现有依赖解决不了的。
技术选型的生命周期管理
技术选型不是一次性决策,是一个持续过程:
text
立项选型 → 团队试用 → 试点项目 → 全面推广 → 稳定运行 → 技术债积累
│ │ │
└── 否决:0 成本 ─────┘ │
│ │
└── 失败:回退(试点成本可控)───────┘
│
┌────────────┘
▼
评估替代方案 → 迁移 or 继续每一步都有退出机制。越靠前的阶段否决成本越低。立项阶段否决一个技术只需要一次会议;试点项目失败需要回退代码;全面推广后替换的代价是重写。
所以选型流程是前紧后松:
- 立项选型应该是最严格的:所有约束条件必须明确,所有备选方案必须穷举,PoC 必须跑通核心流程。
- 试点项目的目标是验证,不是证明:如果过程里只在寻找支持该技术的证据,而忽略反证,试点本身就已经偏离了验证目的。
- 全面推广后,除非触发复审条件(安全事故、性能瓶颈、生态凋零),否则继续使用。每 12 个月做一次技术栈健康检查,但不要因为"新技术更好"就启动迁移。
量化选型:一个粗糙但有用的模型
技术选型很难量化,但可以用一个简化模型来辅助判断:
text
技术价值 = 收益 / (成本 + 风险溢价)
收益 = 对核心业务指标的提升(开发效率、用户体验、运维成本等)
成本 = 学习成本 + 开发成本 + 维护成本 + 招聘成本
风险溢价 = 迁移成本 × 被淘汰概率这个公式的精度不重要——你很难精确量化"开发效率提升 20%"。重要的是它强迫你把决策拆解为可讨论的要素,而不是笼统地说"这个技术更好"。
实际操作用一个简单的评分表:
| 要素 | 权重 | 方案 A | 方案 B | 方案 C |
|---|---|---|---|---|
| 团队匹配度 | 30% | 8 | 4 | 6 |
| 生态成熟度 | 20% | 7 | 5 | 8 |
| 长期风险 | 20% | 6 | 8 | 4 |
| 项目匹配度 | 20% | 7 | 6 | 5 |
| 招聘市场 | 10% | 8 | 3 | 6 |
| 加权总分 | 100% | 7.1 | 5.3 | 5.8 |
注意权重是这个模型里最有价值的部分——它反映了团队和项目的优先级。对创业公司,团队匹配度可能占 40%;对银行,长期风险可能占 40%。权重本身就是决策依据。
最重要的是:如果评分结果和你直觉不一致,不要修改评分来迎合直觉。去查为什么直觉和评分不同——可能有你潜意识在考虑的、没被纳入评分表的重要因素。
性能维度:技术选型中的量化对比
技术选型如果不看性能数据,就纯靠口碑和营销。以下是 2026 年主流技术栈的性能基准(数据来源:公开 benchmark + 社区报告,具体数值因测试条件而异,但相对关系稳定)。
框架运行时性能
| 指标 | React 19 | Vue 3.5 | Svelte 5 | Solid 2 |
|---|---|---|---|---|
| 初始 bundle(KB gzipped) | ~12 | ~10 | ~4 | ~5 |
| 首次渲染 1K 行(ms) | ~35 | ~25 | ~15 | ~12 |
| 更新单行(μs) | ~120 | ~80 | ~40 | ~30 |
| 内存占用 1K 行(MB) | ~18 | ~14 | ~9 | ~7 |
Source: js-framework-benchmark 2026 Q1, Chrome 132
关键解读:
- Solid 和 Svelte 在性能上领先——编译时优化 + 无虚拟 DOM 路线的优势在基准测试中很明显。
- Vue 3 在 React 19 之前有约 30% 的性能优势;React Compiler(Forget)在 React 19 中缩小了这个差距。
- 但这些基准差异在实际项目中感知不强。1K 行的渲染差异是 10-20ms——用户感知不到。选型时性能数据是参考,不是决定因素,除非你的场景正好命中某个框架的性能短板。
构建工具性能
| 场景 | Vite 6 | Turbopack | Webpack 5 | Rspack |
|---|---|---|---|---|
| 冷启动(中型项目) | 0.8s | 0.4s | 12s | 0.6s |
| HMR(修改 1 个文件) | 15ms | 8ms | 200ms | 12ms |
| 生产构建(中型项目) | 18s | 12s | 45s | 15s |
2026 年构建工具的选择已经主要不是性能问题——所有主流工具都能做到可接受的开发体验。选择 Vite 的最大理由不是"比 Webpack 快 15x",而是"配置复杂度低 5x"。
Core Web Vitals 影响
不同技术栈对 Core Web Vitals 的直接影响:
- LCP:SSR 框架(Next.js / Nuxt)比纯 CSR 方案快 40-60%(因为首屏 HTML 在服务端生成)。但 hydration 成本不可忽视——React 的 hydration 在高复杂度页面上可能耗费 200-500ms。
- INP:React concurrent mode 和 Vue scheduler 都能有效降低交互延迟,但效果取决于具体使用方式。Svelte/Solid 因无虚拟 DOM,INP 天然更低。
- CLS:和框架关系不大,主要取决于图片/广告/动态内容的尺寸管理。但 Tailwind CSS 的原子化方案天然降低 CLS(class 变更不触发布局偏移)。
性能数据在技术选型中的价值不是"选最快的那个",而是建立各选项的性能边界认知——知道每一项技术的性能上限和下限,然后判断你的项目场景落在哪个区间。
生产实践:技术迁移的真实案例
迁移模式:Strangler Fig Pattern
技术选型的后续是技术迁移——从旧技术栈向新技术栈过渡。最安全的模式是 Strangler Fig(绞杀榕模式):
text
阶段 1: 新旧共存
App Router
├── /new-feature/* → 新框架(Vue 3)
└── /* → 旧框架(Vue 2)
阶段 2: 逐步替换
App Router
├── /new-feature/* → 新框架
├── /migrated/* → 已迁移的旧页面
└── /legacy/* → 尚待迁移的旧页面
阶段 3: 切除旧系统
App → 全部新框架实现方式:
- Nginx 路由层:按 path 将请求分发到不同应用。适合完全独立的两套应用。
- Module Federation:运行时加载远程模块,新旧框架组件可以在同一页面共存。适合渐进式迁移。
- iframe / Web Component:最彻底的隔离,但通信成本高。适合"短期内不可能迁移完成"的大型模块。
关键操作细节
- 数据层先行:在迁移 UI 层之前,先把数据层(API 接口、状态管理逻辑)抽取为框架无关的纯 JS/TS 模块。新框架和旧框架共享同一套数据层,迁移时只需要改 UI 层。
- Feature flag 灰度:新版本通过 feature flag 控制,先内部灰度(1% 员工 → 5% → 20%),再逐步放量。每个阶段观察至少 48 小时的错误率和性能指标。错误率上升 >10% 立即回滚。
- 双写 + 比对:迁移期间新旧系统同时运行(对读流量),比对输出结果。不一致的 case 是迁移 bug 的早期信号。这个模式的后端双写更常见,前端可以走"渲染结果截图比对"的路线。
- 监控先行:在迁移之前,先把新系统的监控埋好。首屏加载时间、渲染错误率、API 调用成功率——这些指标在新旧系统上的对比是迁移质量的唯一客观判断。
迁移失败案例
一个团队从 AngularJS 迁移到 React 的案例:
错误做法:试图一次性重写整个应用。90 个页面,计划 6 个月完成。实际花了 18 个月,期间旧系统还在迭代,新系统上线时业务需求已经变了 30%——追赶移动靶。
正确做法(他们后来采用的):先识别出独立性最高的 10 个页面(不依赖旧系统的全局状态),用 Strangler Fig 模式逐个替换。10 个页面花了 6 周。验证可行后加速到每周迁移 3-5 个页面。12 个月完成全量迁移,期间旧系统一直在正常服务。
教训:迁移的单位不是"整个系统",是"单个页面/模块"。大爆炸式迁移几乎总是失败。
几个 Principal 级别的判断
1. 技术选型最大的成本不是选错,是迟迟不选。
一个团队花了 3 周讨论 React vs Vue,最终选了 React。但 3 周的讨论时间已经相当于选错技术之后的部分返工成本了。对大多数项目来说,React 和 Vue 之间的差异远小于项目需求的差异。快速选一个合理的、开始写代码,比花大量时间选出"最优方案"更经济。
决策的时间上限和决策影响范围成正比:选框架(影响整个项目),可以花 1 周。选一个工具库(影响一个模块),花 1 小时就够了。选一个 npm 包(影响一个功能),5 分钟。
2. 技术栈的"一致性"比"最优性"重要。
一个团队同时用 React 和 Vue(A 项目 React,B 项目 Vue)的隐性成本:任何跨项目复用的代码(工具函数、组件库、CI 配置、lint 规则)都需要维护两套。Context switching 的成本在人员跨项目流动时会爆发。
除非有压倒性的理由(比如收购了另一家公司,它的技术栈不一样),在同一个组织内保持技术栈一致性的长期收益大于每个项目各自选"最优技术"的收益。
3. "简单"是技术选型中最高级的评价。
一个技术被描述为"功能强大但复杂"时,通常意味着团队会在非业务逻辑上消耗大量时间。被描述为"简单但够用"时,通常意味着它找到了正确的抽象边界。
在技术选型讨论中,把"简单"作为一个独立维度来评分——往往比"功能丰富度"更能预测团队的长期满意度。
4. 招聘市场的语言偏好决定了技术栈的人才池。
2026 年的中国前端市场:React 岗位 > Vue 岗位 > 其他。如果一个团队在成都(React 人才少),全部用 React 可能面临招聘困难。如果一个团队在深圳(React 人才多),用 Vue 则可能限制候选人池。
技术选型的"招聘维度"不分地域的量化数据可以看:各大招聘网站的岗位数量对比、社区活跃度(GitHub contributors 地域分布)、技术会议的话题分布。这些都是滞后指标,但对选型决策是强信号。
5. 每一个被引入的技术依赖,都增加了一个潜在的"单点故障"。
npm 生态的安全事件(left-pad、event-stream、colors.js 作者删库)反复证明:每个依赖都是一个信任边界。技术选型的"依赖树深度"应该作为一个风险指标来追踪。依赖越深、越广,被供应链攻击或意外断更的风险越大。
具体做法:在选择一个库之前,检查它的依赖数(npm info <pkg> dependencies --json | jq 'length')。如果一个简单的工具库有 50+ 个传递依赖,就值得找更轻量的替代方案。
技术选型的延伸问题
Q1: 你说选型要看"迁移成本",但迁移成本怎么估算?
迁移成本不是拍脑袋的"大概 3 个月"。它是可分解的:
text
迁移成本 = 分析成本(理解新旧系统的差异)
+ 实现成本(写新代码、改配置)
+ 测试成本(全量回归 + 性能对比)
+ 部署成本(灰度发布、监控观察、回滚预案)
+ 团队适应成本(学习新技术栈的生产力真空)
+ 机会成本(迁移期间原计划的新功能被推迟)每一项都有估算方法。实现成本可以通过"先迁移一个中等复杂度的页面,测实际耗时,然后乘以页面数并加 30% 缓冲"来估算。团队适应成本可以通过"前 2 周团队产出下降百分比 × 团队人数 × 平均日薪"来量化。
关键是:迁移成本的估算不应该由支持迁移的人来做(他们有动机低估成本)。让团队里对迁移持怀疑态度的人来做成本估算,取两方的中位数。
Q2: 如果团队内部对技术选型有分歧(一半人要 React,一半人要 Vue),怎么决策?
这不是技术问题,是决策机制问题。几个实用原则:
- 把分歧转化为可讨论的要素:不要讨论"React 好还是 Vue 好",讨论"在这个项目的约束条件下,哪个方案的哪个方面更有优势"。
- PoC 是最有效的化解方式:两派各用自己偏好的技术,在 1-3 天内实现同一个中等复杂度的功能。产出对比通常能直接解决分歧。
- 设立"决策者"而不是"投票":技术选型不是民主投票。指定一个人(通常是 Tech Lead)做最终决策,其他人提供输入。决策者需要对决策后果负责。
- 接受"另一方可能也是对的":在 React 和 Vue 之间,没有任何一个选择是"明显错误"的。分歧双方都可能是对的——只是优先级不同。
Q3: 什么时候该主动发起技术栈升级/迁移?什么时候该"不折腾"?
升级的触发条件(同时满足 ≥2 个):
- 当前版本已停止维护(安全补丁不再发布)
- 性能问题已实际影响业务指标(不是"可以更快",是"已经影响了转化率/用户留存")
- 团队招聘因技术栈过时而困难
- 新版本的关键特性能解决现有架构的一个硬伤
"不折腾"的条件(满足任意 1 个):
- 当前版本仍在活跃维护,有安全补丁
- 系统已稳定运行 ≥6 个月,无性能投诉
- 升级的回归测试成本 > 升级收益
- 项目将在 6 个月内下线或被替代
大部分技术栈升级的动机是"新技术更好",但"更好"本身不是充分的升级理由。升级的充分理由是"旧技术的问题正在伤害业务"。
Q4: 对于中小团队(<10 人),技术选型和大团队有什么不同的策略?
中小团队的一个核心约束:人能覆盖的技术广度有限。
大团队可以并行维护 React 和 Vue 两套技术栈,因为每个栈都有至少 2-3 个专家。小团队如果维护两套栈,结果是两套都半懂——每套栈的深度都不够应对复杂问题。
所以中小团队的技术选型策略是:
- 减少技术多样性:全公司统一技术栈(至少统一框架和构建工具)
- 选成熟度高的方案:选社区最大的方案而不是最新最酷的方案——因为没人帮你 debug,社区是你的唯一支持
- 选官方生态完整的方案:Next.js / Nuxt 这种全栈框架,而不是把 Router + SSR + State Management + Data Fetching 分别从不同库拼起来——少做集成决策 = 少出集成 bug
- 避免引入需要专人维护的基础设施:如果团队里没有 SRE 或 DevOps 角色,需要自维护服务器/CI/CD 的方案通常要谨慎评估
Q5: 如何评估一个 npm 包是否值得引入?
除了常规的 stars/downloads/maintenance 指标外,几个更深入的检查:
- 依赖链深度:
npm ls <pkg> --depth=10 | wc -l。依赖树越深,供应链攻击面越大。 - Breaking change 历史:看 CHANGELOG。如果过去 3 个大版本每次都有 ≥5 个 breaking change,未来也会如此。你的升级成本可预测。
- 维护者 bus factor:如果该库 ≥80% 的 commits 来自同一个人,它就是一个 bus factor=1 的依赖。那个人休假或离职,这个库就进入了实质上的无维护状态。
- 和框架的耦合度:
react-xxx只能在 React 中使用,xxx则可能是框架无关的。如果未来存在换框架的可能,依赖耦合度需要单独评估。 - 代码量和使用功能量的比例:如果只用了库 5% 的功能,却引入了 100KB 的 bundle,就需要重新审视是否存在更轻量的替代方案。
bundlephobia.com这类工具通常可以直接辅助判断。
