1. 项目概述一个开发者专属的规则集如果你和我一样在开发这条路上摸爬滚打了几年肯定遇到过这样的场景新加入一个团队面对一个全新的代码库光是配置开发环境、统一代码风格、设置提交规范这些“基建”工作就能耗掉大半天。更别提那些因为团队规范不一致导致的代码冲突、风格混乱和沟通成本了。dev-rules这个项目就是为了解决这个痛点而生的。它不是一个具体的软件库而是一个高度可配置、开箱即用的“开发者规则集”模板或最佳实践集合。简单来说dev-rules就像是一个为现代软件开发团队量身定制的“开发环境宪法”。它把那些散落在各个角落、需要手动配置的规则——比如代码应该怎么格式化ESLint, Prettier、提交信息应该怎么写Commitlint、分支命名有什么约定、甚至代码审查的检查清单是什么——都集中到一个地方进行统一管理和版本控制。它的核心价值在于“一致性”和“自动化”。通过一套预先定义好的、经过验证的规则它能确保从项目初始化开始团队中的每一个成员都在同一个频道上工作极大减少了因个人习惯差异带来的摩擦让开发者能更专注于业务逻辑本身而不是在格式和规范上扯皮。这个项目适合谁呢首先是小到中型的技术团队负责人或技术骨干你们正在为团队寻找一套可复用的工程规范其次是独立开发者或开源项目维护者希望自己的项目从一开始就具备良好的工程化基础最后任何对提升开发效率、追求代码质量、并希望将最佳实践固化的开发者都能从中获得启发和可以直接复用的模块。2. 核心架构与设计哲学2.1 模块化与可插拔的设计思想dev-rules项目的精髓在于其模块化的设计。它没有试图创造一个庞大而笨重的“一体机”而是将开发流程中的各个环节解耦成独立的规则模块。你可以把它想象成一个乐高工具箱里面装着不同形状的积木规则集你可以根据当前项目的技术栈是 React TypeScript 的前端项目还是 Node.js 的后端服务或者是全栈应用和团队偏好自由地挑选和组合这些积木。一个典型的dev-rules仓库可能包含以下目录结构dev-rules/ ├── eslint-config/ # ESLint 规则配置 │ ├── base.js # 基础规则适用于所有JS │ ├── react.js # React 特定规则 │ ├── typescript.js # TypeScript 特定规则 │ └── node.js # Node.js 特定规则 ├── prettier-config/ # Prettier 代码格式化配置 │ └── index.js ├── commitlint-config/ # Git 提交信息规范配置 │ └── conventional.js ├── lint-staged-config/ # 针对暂存文件的 lint 配置 │ └── index.js ├── husky-config/ # Git 钩子配置 │ ├── pre-commit # 提交前自动 lint 和格式化 │ └── commit-msg # 提交时校验信息格式 └── README.md # 详细的使用和配置说明这种设计的优势非常明显。首先它极具灵活性。如果你的团队暂时不需要严格的提交信息规范你可以暂时不引入commitlint-config模块。当项目复杂度上升需要规范提交历史时再轻松地将其加入。其次它便于维护和升级。当 ESLint 或 Prettier 发布新版本或者某个插件的规则有更新时你只需要在dev-rules这个中心仓库里更新对应的配置模块然后所有引用该配置的子项目通过更新依赖版本即可同步升级避免了在每个项目中重复修改配置文件的繁琐和可能出现的遗漏。最后它降低了学习成本。新成员入职时不需要再去理解十几种不同的配置文件只需要知道团队使用的是统一的dev-rules并按照文档安装配置即可快速上手。2.2 约定优于配置与自动化执行dev-rules的另一个核心哲学是“约定优于配置”。它预先定义了一套经过团队讨论和验证的、被认为是“最佳”的默认规则。例如它可能规定缩进使用 2 个空格、字符串使用单引号、行尾必须有分号等。这些约定减少了团队成员在琐碎细节上争论的时间。当然这并不意味着完全不能配置。每个模块通常都提供了覆盖默认配置的选项但前提是需要有充分的理由并且这种覆盖行为本身也应该被记录和讨论以防止规则的碎片化。比约定更重要的是自动化。规则如果只写在文档里最终往往会流于形式。dev-rules通过集成一系列工具将规则检查无缝嵌入到开发工作流中实现“无感”执行。这里的关键工具是Git Hooks通常通过Husky管理和lint-staged。Git Hooks在代码提交的生命周期中插入自动化脚本。dev-rules通常会配置两个核心钩子pre-commit在执行git commit命令时触发。这个钩子会运行lint-staged只对本次提交中被修改并暂存staged的文件进行代码检查和格式化。这样做的好处是效率极高不会对全仓库代码进行 lint只关注本次改动。如果检查或格式化失败提交会被阻止开发者必须根据提示修复问题后才能成功提交。commit-msg在编写完提交信息后触发。这个钩子会调用commitlint根据预设的规范如流行的 Conventional Commits来校验提交信息的格式。例如要求信息必须以feat:、fix:、docs:等类型开头后面紧跟简短描述。这保证了提交历史的可读性和规范性便于后续生成 Change Log。lint-staged这是实现高效pre-commit检查的核心。它的配置文件定义了针对不同文件类型如*.js,*.tsx,*.md应该执行什么命令。一个典型的配置可能长这样// lint-staged.config.js module.exports { *.{js,jsx,ts,tsx}: [eslint --fix, prettier --write], *.{json,md}: [prettier --write] };这意味着当你尝试提交时所有暂存的 JavaScript 或 TypeScript 文件会先被 ESLint 自动修复可自动修复的问题然后再被 Prettier 重新格式化JSON 和 Markdown 文件则只进行 Prettier 格式化。整个过程在秒级内完成开发者几乎感知不到但提交的代码已经是整洁、规范的了。这种“提交即规范”的自动化流程是dev-rules项目能真正落地、发挥价值的基石。它把质量控制从靠人自觉的事后审查变成了无法绕过的自动化前置关卡。3. 核心规则模块深度解析3.1 代码静态检查与格式化ESLint Prettier 的黄金组合代码质量的第一道防线是静态检查。dev-rules在这个环节通常会深度集成 ESLint 和 Prettier但关键在于理清它们的分工与合作关系避免冲突。ESLint代码质量的“警察”。它负责检查代码中可能存在的错误、不推荐的写法、潜在的性能问题以及违反团队编码风格的行为如未使用的变量、错误的相等比较等。dev-rules中的 ESLint 配置通常是分层级的基础规则继承自社区公认的优质规则集如eslint:recommendedESLint 内置推荐或airbnb-baseAirbnb 风格指南。这提供了一个高标准的起点。框架/语言扩展根据项目技术栈添加例如typescript-eslint/eslint-plugin用于 TypeScripteslint-plugin-react和eslint-plugin-react-hooks用于 React。团队自定义规则这是dev-rules价值所在。团队可以根据自身经验在基础之上进行增删改。例如可能统一要求使用axios而非fetch进行 HTTP 请求或者对复杂的函数圈复杂度设置一个上限。Prettier代码格式的“美容师”。它只关心代码的“样子”——缩进、空格、换行、引号等。它的特点是“固执己见”几乎没有配置选项但关键的几个如printWidth,singleQuote等还是可配的这恰恰是它的优点彻底终结了关于代码格式的争论。关键注意事项解决 ESLint 与 Prettier 的冲突这是配置中最容易踩坑的地方。ESLint 的一些风格规则如indent,quotes和 Prettier 的格式化行为可能会产生冲突导致代码被来回修改形成死循环。标准的解决方案是使用eslint-config-prettier这个配置包。它会关闭所有与 Prettier 冲突的 ESLint 规则。使用eslint-plugin-prettier这个插件。它会将 Prettier 作为一个 ESLint 规则来运行这样你可以在 ESLint 的输出中直接看到格式问题并通过eslint --fix一键修复。 在dev-rules的 ESLint 配置中正确的做法是将eslint-config-prettier作为最后一个扩展引入以确保它覆盖所有冲突规则同时按需决定是否使用eslint-plugin-prettier。我个人更倾向于只使用eslint-config-prettier然后在lint-staged中分别顺序执行eslint --fix和prettier --write逻辑更清晰。3.2 提交规范与工作流Commitlint Husky规范的提交信息对于团队协作和项目维护至关重要。dev-rules通过 Commitlint 来强制执行提交规范。Commitlint 配置通常采用commitlint/config-conventional这个预设配置它基于 Conventional Commits 规范。该规范要求提交信息具有固定的结构type[optional scope]: description [optional body] [optional footer(s)]常见的type包括feat新功能、fix修复bug、docs文档、style不影响代码含义的格式修改、refactor重构、test测试、chore构建过程或辅助工具的变动。dev-rules可以在此基础上进行定制例如规定description必须以动词开头、使用中文或英文、或者添加团队特定的type如ui表示UI组件更新。Husky 的现代配置Husky 是管理 Git Hooks 的工具。在旧版本中它会在项目根目录的.git/hooks下创建钩子文件但这不利于版本控制。新版本v7推荐在package.json中直接配置或者使用独立的配置文件如.husky/目录并将该目录提交到版本库中。dev-rules通常会采用后者因为它更清晰、更易于管理。目录内包含具体的钩子脚本文件如.husky/pre-commit和.husky/commit-msg。实操心得钩子脚本的编写。在.husky/pre-commit中不要直接写入复杂的 lint 命令而是调用npx lint-staged。这样所有的逻辑都集中在lint-staged的配置文件中维护起来更方便。在.husky/commit-msg中命令通常是npx --no-install commitlint --edit $1其中$1是包含本次提交信息的临时文件路径。确保在package.json中正确安装了commitlint和husky并运行过npx husky install来启用钩子。3.3 分支管理与发布策略虽然dev-rules的核心可能集中在代码和提交层面但一个完整的开发规则集往往会延伸到 Git 工作流本身。这里可以包含分支命名规范和发布流程建议。分支命名规范一个好的规范能让人一眼看出分支的用途。dev-rules可以推荐如下模式feature/short-description用于开发新功能。fix/short-description用于修复 bug。hotfix/short-description用于生产环境紧急修复。release/version用于准备发布版本。docs/short-description用于文档更新。发布策略集成对于采用语义化版本SemVer和希望自动化生成变更日志CHANGELOG的项目dev-rules可以集成相关工具的建议配置。例如结合standard-version或release-it这类工具它们能够根据feat:和fix:等类型的提交自动决定下一个版本号是主版本、次版本还是修订版本。自动生成格式优美的CHANGELOG.md文件。自动创建 Git Tag。 通过在package.json的scripts中定义如npm run release这样的命令将发布流程也标准化和简化。4. 从零搭建与集成实战4.1 初始化一个全新的dev-rules仓库假设我们要为一个使用 React TypeScript 技术栈的团队创建一套dev-rules。我们首先创建一个独立的 Git 仓库。创建仓库并初始化mkdir my-team-dev-rules cd my-team-dev-rules git init npm init -y初始化后修改package.json将private字段设为true因为我们这个仓库是作为配置包被其他项目引用的本身不需要发布到公共 npm。安装核心依赖这里我们安装的是开发依赖-D因为规则集本身也是一个“项目”。npm install -D eslint prettier typescript-eslint/parser typescript-eslint/eslint-plugin eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier husky lint-staged commitlint commitlint/config-conventional这是一个基础组合涵盖了 JS/TS 代码检查、React 规则、格式化、Git钩子、提交校验等。构建模块化配置目录按照之前提到的结构创建目录和文件。例如创建eslint-config/base.js// eslint-config/base.js module.exports { parser: typescript-eslint/parser, // 使用 TS 解析器 plugins: [typescript-eslint, react, react-hooks], extends: [ eslint:recommended, plugin:typescript-eslint/recommended, plugin:react/recommended, plugin:react-hooks/recommended, prettier // 必须放在最后关闭冲突规则 ], settings: { react: { version: detect // 自动检测 React 版本 } }, rules: { // 这里可以添加或覆盖团队自定义规则 typescript-eslint/explicit-function-return-type: off, // 示例关闭强制返回类型声明 react/react-in-jsx-scope: off // 对于 React 17 的新 JSX 转换可以关闭此规则 } };配置 Prettier创建prettier-config/index.js。// prettier-config/index.js module.exports { semi: true, trailingComma: es5, singleQuote: true, printWidth: 100, tabWidth: 2, useTabs: false };配置 Commitlint创建commitlint-config/conventional.js。// commitlint-config/conventional.js module.exports { extends: [commitlint/config-conventional], rules: { // 可自定义规则例如要求 scope 不为空 scope-empty: [2, never] } };配置 Husky 和 lint-staged创建husky-config/目录和lint-staged-config/index.js文件。同时在项目根目录执行npx husky install来初始化 Husky。然后创建钩子文件如.husky/pre-commit注意这个文件在dev-rules仓库内用于演示和复制实际项目使用时需要重新安装 Husky。4.2 在具体业务项目中集成dev-rulesdev-rules仓库建好后如何在业务项目比如一个叫my-app的 React 应用中使用呢有几种方式方式一通过 npm 包发布推荐用于公司内部将dev-rules仓库发布到公司的私有 npm 仓库如 Verdaccio或使用npm link在本地测试。在my-app项目中安装npm install -D my-org/dev-rules。在my-app的package.json中扩展配置{ eslintConfig: { extends: [my-org/dev-rules/eslint-config/react] // 假设我们导出了针对React的配置 }, prettier: my-org/dev-rules/prettier-config, commitlint: { extends: [my-org/dev-rules/commitlint-config/conventional] } }将dev-rules中的husky-config和lint-staged-config内容复制到my-app项目的对应位置或通过postinstall脚本自动安装。方式二通过 Git Submodule 或直接复制适用于快速启动或开源项目将dev-rules作为 Git 子模块添加到my-app项目中git submodule add dev-rules-repo-url .dev-rules。在my-app中创建配置文件如.eslintrc.js直接引用子模块中的配置// .eslintrc.js module.exports require(./.dev-rules/eslint-config/react);同样复制或链接其他配置文件如.prettierrc.js,.commitlintrc.js以及.husky目录。方式三使用脚手架生成最自动化可以基于dev-rules创建一个项目脚手架例如使用plop或自定义的 CLI 工具。当开发者运行create-my-app命令时脚手架不仅生成项目骨架还会自动安装所有依赖并写入基于dev-rules的全套配置文件实现开箱即用的标准化项目初始化。4.3 配置的覆盖与扩展业务项目难免有特殊需求。dev-rules提供的应该是良好的默认值同时允许项目层进行合理的覆盖。以 ESLint 为例在业务项目的.eslintrc.js中可以在扩展了基础配置后再添加项目特定的规则// my-app/.eslintrc.js module.exports { extends: [my-org/dev-rules/eslint-config/react], rules: { // 覆盖基础配置中的某条规则 no-console: warn, // 基础配置可能是 error这里放宽为警告 // 添加项目特有规则 my-custom-rule: error }, overrides: [ { files: [*.test.tsx], rules: { // 针对测试文件放宽某些规则 typescript-eslint/no-explicit-any: off } } ] };这种模式既保证了团队基础规范的一致性又为特殊场景保留了灵活性。5. 常见问题、排查与演进维护5.1 集成过程中的典型问题与解决问题Husky 钩子不执行。排查首先检查.git/hooks/目录下是否存在对应的钩子脚本如pre-commit。如果没有说明 Husky 没有正确安装。运行npx husky install。如果钩子存在但没有执行权限在 Unix 系统上需要chmod x .husky/*。解决确保package.json中有prepare脚本prepare: husky install。这样每次npm install后都会自动初始化 Husky。同时确保.husky/目录已被提交到版本库。问题lint-staged只对部分文件类型生效或者命令执行失败。排查检查lint-staged的配置文件如.lintstagedrc.js中的模式匹配是否正确。例如*.{js,ts}不会匹配.jsx或.tsx文件。另外检查命令是否在项目环境中可用如eslint、prettier是否已安装为项目依赖。解决修正文件匹配模式例如使用*.{js,jsx,ts,tsx}。确保所有在lint-staged中调用的命令行工具如eslint,prettier都在项目的devDependencies中而不是全局安装。问题Commitlint 校验失败但信息看起来符合规范。排查使用npx commitlint --from HEAD~1 --to HEAD --verbose命令对上一条提交进行详细校验查看具体哪条规则未通过。常见原因是type不在默认列表中或者subject描述超过了长度限制、末尾有句号等。解决根据输出调整提交信息。如果团队使用了自定义的type需要在commitlint.config.js的rules中配置type-enum: [2, always, [feat, fix, docs, style, refactor, test, chore, ui]]来扩展枚举。问题ESLint 和 Prettier 格式化后代码风格不一致出现循环修复。排查这是典型的规则冲突。检查 ESLint 配置中是否正确引入了eslint-config-prettier并放在了extends数组的最后。确保没有其他插件或配置重新开启了被关闭的格式规则。解决在 VS Code 等编辑器中确保只启用一个格式化程序通常设为 Prettier并关闭editor.formatOnSave与eslint.autoFixOnSave同时开启的情况。在lint-staged中确保命令执行顺序是eslint --fix在前prettier --write在后。5.2dev-rules的版本管理与演进dev-rules本身也是一个需要维护的项目。随着技术栈更新、团队经验积累或遇到新的问题规则需要迭代。语义化版本对dev-rules的更改也应遵循 SemVer。补丁版本0.0.X修复现有配置中的错误更新某个依赖的小版本不影响现有项目集成。次版本0.X.0新增可选的规则模块如新增一个针对 Vue 的 ESLint 配置或对现有规则进行不影响默认行为的增强如增加一条新规则但其默认值是off或warn。现有项目升级后行为不变。主版本X.0.0进行不兼容的更改。例如将某条关键规则的默认值从off改为error或者修改了提交信息的规范格式。这会导致依赖它的项目在升级后可能需要调整代码或提交方式。变更日志与升级指南每次发布新版本都应在CHANGELOG.md中清晰记录变动的模块、具体更改内容如哪条规则被修改、以及升级影响和操作指南。例如“在eslint-config/basev2.0.0 中我们启用了typescript-eslint/no-floating-promises规则为error。如果你的项目中有未处理的 Promise升级后 lint 会失败。你需要为这些 Promise 添加.catch()或使用void操作符。”灰度发布与反馈收集对于重大的、可能引起广泛影响的变更如主版本升级可以先在一个试点项目或团队中先行升级收集反馈解决兼容性问题然后再推广到所有项目。建立一个反馈渠道如内部群、GitHub Issues鼓励团队成员报告规则使用中遇到的问题或不合理的约束。5.3 衡量规则集的效果与调整规则不是一成不变的铁律。定期评估其效果至关重要。量化指标代码审查效率引入规则后代码审查中关于风格和规范的争论是否减少了平均每次 PR 的评论数和往返次数是否有下降缺陷引入率静态检查如 ESLint 规则是否帮助提前捕获了潜在的 bug可以统计在 CI 环节被 ESLint 或 TypeScript 编译器阻断的提交数量。新人上手时间新成员从克隆项目到第一次成功提交代码的平均时间是否缩短了定性反馈定期如每季度与团队成员交流收集他们对现有规则的看法。哪些规则觉得很有用哪些规则过于严格、带来了不必要的负担哪些地方还缺少规范规则审计与精简基于数据和反馈对规则集进行“修剪”。过于宽松、形同虚设的规则可以考虑加强或删除过于严苛、频繁被禁用或导致开发体验很差的规则需要重新审视其必要性或者寻找更优的替代方案例如用自动化的代码转换工具来代替一条禁止使用某语法的 lint 规则。维护一个dev-rules项目的最终目标不是用规则束缚开发者而是通过合理的约束和强大的自动化为团队创造一个高效、顺畅、低内耗的开发环境让工程师的创造力聚焦在真正创造价值的地方。它是一项需要持续投入和精心打磨的团队基础设施其回报是团队整体研发效能和代码资产长期健康度的显著提升。