大家好,我是 一步梅。做前端开发这些年,我写过不少业务代码,但花心思最多的,其实是怎样把文档和架构理清楚。
不知道大家在接手一个迭代了两三年的前端老项目时,有没有遇到过这些灵魂拷问:
- 为什么这个项目里既有 Axios 封装,又有原生的 Fetch 拦截?
- 为什么当时不用社区最火的方案,而是自己造了个轮子做表单联动?
- 当时从 Webpack 迁到 Vite,遗留的那几个插件配置究竟是干什么用的?
去翻 Git Commit,满屏都是 feat: update、fix: bug;去翻群聊记录,当事人早就离职了。技术选型和架构演进的上下文完全丢失,新人只能靠猜,老人不敢重构。
要彻底解决这个问题,成本最低也最有效的方式,就是引入 ADR(Architecture Decision Record,架构决策记录)。今天这篇文章,我就分步骤带大家把 ADR 在前端工程中落地,让每一次技术决策都能像代码一样版本化、可追溯。
一、什么是 ADR?
简单来说,ADR 就是一份给关键技术决策立的“字据”。
它是一组简短的 Markdown 文本,存放在代码仓库中,和业务代码同生共死。每当团队要引入重大依赖、调整目录规范、重构核心流程或者做技术栈选型时,就提一份 ADR。
一份合格的 ADR 通常包含 5 个核心要素:
- Title(标题):编号加简短描述。
- Status(状态):提议中(Proposed)、已通过(Accepted)、已废弃(Deprecated)、被取代(Superseded)。
- Context(背景):我们遇到了什么问题,促使我们必须做决定。
- Decision(决定):我们决定怎么做,选了哪个方案,放弃了哪些方案。
- Consequences(影响与后果):这个决定带来的好处是什么,要付出的代价(Trade-off)又是什么。
二、前端实战:一份标准的 ADR 模板长什么样?
别把 ADR 写成几万字的长篇大论,开发人员最怕形式主义。文档必须短小、结构化、直奔主题。
以我们前端常见的「引入 Tailwind CSS 替换原有 Less 方案」为例,来看看具体写法:
# 0003. 引入 Tailwind CSS 作为团队统一的原子化 CSS 解决方案
- **状态**:Accepted
- **决策人**:一步梅、前端核心组
- **日期**:2024-03-15
## 1. 背景(Context)
当前项目使用 Less + CSS Modules,随着业务组件快速增长,暴露出以下问题:
1. 样式文件与组件文件强绑定,产生大量无意义的类名(如 `.content-wrapper`、`.inner-box`),命名心智负担重。
2. 团队成员重复手写高频样式(Padding、Margin、Flex 居中),导致打包后的 CSS 体积线性膨胀,目前线上 CSS 已达到 320KB。
3. 主题色与间距规范无法强约束,存在大量魔数(Magic Number,如 `margin: 13px`)。
## 2. 备选方案(Options Considered)
- **方案 A:继续使用 Less,但制定更严格的 Code Review 规范**
- 优点:零迁移成本。
- 缺点:纯靠人肉 Review 无法杜绝类名泛滥和魔数问题。
- **方案 B:UnoCSS**
- 优点:性能极高,配置灵活。
- 缺点:生态成熟度略逊于 Tailwind CSS,部分 VS Code 插件体验不稳定。
- **方案 C:Tailwind CSS v3**
- 优点:生态庞大、JIT 引擎成熟、VS Code 自动补全体验优秀,设计规范约束力强。
- 缺点:HTML 类名较长,有上手学习成本。
## 3. 决定(Decision)
我们决定**选用 Tailwind CSS 作为项目统一的原子化样式方案**,并做如下约束:
1. 配置统一的 `tailwind.config.js`,将设计系统(Spacing、Color、Font)固化为系统 Token。
2. 存量页面保持 Less 不变,禁止全量激进重构;所有新页面与新组件必须使用 Tailwind CSS。
3. 配合 ESLint 插件 `eslint-plugin-tailwindcss` 强制类名排序。
## 4. 后果与影响(Consequences)
### 正向影响:
- 终结 CSS 类名命名烦恼,提升切图效率。
- 借由 PurgeCSS 机制,预估最终打包 CSS 体积能压缩至 50KB 以内。
- 保证了跨团队开发时的视觉一致性。
### 负向代价与风险:
- 团队新成员需要 1~2 天熟悉 Tailwind 的常用缩写。
- HTML/JSX 结构看起来相对冗长,需依靠 Prettier 插件自动折行。
看,逻辑非常清楚:问题是什么 -> 选了什么放弃了什么 -> 做了什么妥协。两年后任何人来看,都知道当时为什么走这条路。
三、工程化落地四步法:如何融入 Git 工作流?
光有模板还不够,如果只靠自觉,写两篇大家就忘了。我们要用工程化手段把 ADR 变成流程的一部分。
步骤 1:规范目录结构
在前端项目根目录建立 docs/adr 文件夹,所有的记录统一放在这里,按序号递增命名:
my-frontend-app/
├── docs/
│ └── adr/
│ ├── 0001-record-architecture-decisions.md
│ ├── 0002-state-management-with-zustand.md
│ └── 0003-adopt-tailwind-css.md
├── src/
├── package.json
└── README.md
步骤 2:用 npm script 降低新建成本
开发人员最讨厌找模板复制粘贴,我们在 package.json 里加个生成脚本:
安装辅助工具(推荐使用现成的轻量 CLI):
npm install -D adr-log
在 package.json 的 scripts 中配置:
{
"scripts": {
"adr:new": "node ./scripts/create-adr.js",
"adr:index": "adr-log -d docs/adr -o docs/adr/README.md"
}
}
你自己写个简单的 create-adr.js 脚本,自动读取当前目录最大的数字编号,生成 0004-xxx.md,把模板填充进去。开发者只需要跑一行 npm run adr:new -- 引入-Zustand-替代-Redux 就能开始写正文。
步骤 3:绑定 PR(Pull Request)流程
把 ADR 的产出与 Git 严格挂钩。
在 GitHub / GitLab 的 Pull Request 模板(.github/pull_request_template.md)里加上这一条:
### 架构与技术选型变更
- [ ] 本次 PR 引入了新的核心依赖或架构变更?
- 如果是,请确认是否已在 `docs/adr` 下提交对应的 ADR 文档。
- 关联 ADR:#____
Code Review 时,大家不仅要看代码写得好不好,还要先看 ADR 里的思路对不对。思路没对齐,代码不要 Merge。
步骤 4:自动化生成文档索引
随着项目迭代,ADR 会变成几十篇。可以用上面提到的 adr-log,配合 Husky 在 Git Commit 时自动扫描 docs/adr,在目录根部生成一个 README.md 索引目录表:
| 编号 | 标题 | 状态 | 日期 |
|---|---|---|---|
| 0001 | 决定引入 ADR 机制 | Accepted | 2024-01-10 |
| 0002 | 全局状态管理选型收敛至 Zustand | Accepted | 2024-02-01 |
| 0003 | 引入 Tailwind CSS 原子化方案 | Accepted | 2024-03-15 |
四、实践中的三个避坑建议
在带团队推行 ADR 的过程中,我踩过不少坑,提炼出三条原则供大家参考:
- 不要事无巨细,只抓核心分水岭 写一个公共格式化函数、调个接口,不需要写 ADR。只有**「替换基础设施」、「引入体积庞大的第三方包」、「重构整体数据流」、「修改团队约定的编码范式」** 时,才需要动笔。
- 记录「为什么」,而不是贴大段代码实现 具体的代码实现,Git Diff 会忠实记录;ADR 最大的价值在于解释 Context(当时为什么没得选)和 Trade-off(为了收益放弃了什么)。
- 只增不改,旧决策标记为「废弃」或「被替代」
如果一年后团队发现 Tailwind CSS 不好用,决定换到 Panda CSS,千万不要直接去改
0003号文档! 正确的做法是:新建一篇0015-migrate-to-panda-css.md,在里面声明取代了0003;同时把0003的状态改成Superseded by 0015。这才是完整的演进链条。
总结
很多团队把「没有文档」归咎于业务迭代太忙,但真正的痛点往往不是忙,而是文档系统和代码仓库脱节了,谁也不想在第三方 Wiki 工具上找半天账号去写一篇没人看的大文。
把 ADR 放在 Git 仓库里,用写代码的逻辑来管文档:有版本控制、有 Code Review、有自动化检查。
花 15 分钟写清一个决定的来龙去脉,换来的是未来半年、一年甚至换了三茬队员后,项目依然拥有极高的透明度与可维护性。这笔时间账,算下来绝对是前端工程里最划算的买卖。
License: CC BY-NC 4.0
Updated 13 hours ago
Was this article helpful? Give it a like.
0 comments


