03 · 格式化与 Lint
| 项 |
内容 |
| 文档版本 |
V1.0(2026-11-02) |
| 依据 |
技术架构 §2.2(前端)、§10.1(工程约定)、§4.6(CI/CD) |
| 适用范围 |
全仓库可执行文件 |
| 强制级别 |
强制(CI 门禁,不允许「先合并后修」) |
1 一句话原则
格式交给工具,评审只看逻辑。 任何格式争论都应由配置解决,禁止在 Review 中讨论空格与换行。
2 Prettier(唯一格式化器)
| 配置项 |
值 |
说明 |
printWidth |
100 |
与技术架构示例行宽一致 |
tabWidth |
2 |
|
useTabs |
false |
|
semi |
true |
|
singleQuote |
true |
|
trailingComma |
all |
|
arrowParens |
always |
|
endOfLine |
lf |
跨平台一致 |
plugins |
prettier-plugin-tailwindcss(仅 apps/web) |
若引入 Tailwind;未引入则不加 |
规则:
FMT-01 只允许一个 Prettier 版本、一个根配置;子包不得覆盖。
FMT-02 禁止在文件中写 prettier-ignore,除非是生成代码或大段 markdown 表格,并注明原因。
FMT-03 CI 执行 pnpm format:check,失败即阻断。
FMT-04 禁止把格式化产生的无关改动混进功能 PR(会产生冲突与 Review 噪音)。
3 ESLint(ESLint 9 flat config)
| 项 |
约定 |
| 配置位置 |
根 eslint.config.mjs,按 apps/*、packages/* 分层 export |
| 基础 |
@eslint/js recommended + typescript-eslint 的 strictTypeChecked + stylisticTypeChecked |
| 前端附加 |
eslint-plugin-react-hooks、eslint-plugin-react-refresh、jsx-a11y |
| 导入排序 |
eslint-plugin-simple-import-sort |
| 命名检查 |
@typescript-eslint/naming-convention(对应 02 §1) |
3.1 必须为 error 的规则
| 规则 |
目的 |
@typescript-eslint/no-explicit-any |
禁 any |
@typescript-eslint/no-floating-promises |
禁未处理 Promise |
@typescript-eslint/no-misused-promises |
禁 async 传入非异步回调位 |
@typescript-eslint/consistent-type-imports |
类型导入用 import type |
@typescript-eslint/no-unnecessary-condition |
消除冗余判断(strict 下有效) |
no-restricted-imports |
UI / 图标白名单(见 §3.2) |
no-console |
业务代码禁用,scripts/** 与 worker 的 logger 除外 |
import/no-cycle |
禁循环依赖 |
react-hooks/rules-of-hooks / exhaustive-deps |
Hooks 正确性 |
jsx-a11y/* 关键项 |
可访问性底线 |
3.2 白名单(no-restricted-imports 强制)
禁止导入(含子路径):
规则:
FMT-05 图标只能 import { IconXxx } from '@lingxi/ui/icons';禁止 import * as Icons、禁止直接引 remixicon/icons/...。
FMT-06 SVG 内联仅允许品牌 Logo(packages/ui/brand/),其他一律走图标出口。
FMT-07 颜色字面量(#rrggbb、rgb()在 apps/web 内禁用,除非在 packages/ui/theme/ 的 token 定义文件。
3.3 允许 warn 的规则
@typescript-eslint/no-non-null-assertion(须注释证明非空)、complexity(> 15 警告)、max-lines-per-function(> 50 警告)。
4 提交钩子(本地)
| 钩子 |
工具 |
行为 |
pre-commit |
husky + lint-staged |
仅对暂存文件跑 eslint --fix + prettier --write |
commit-msg |
commitlint |
校验 Conventional Commits(见 01 §2) |
pre-push |
husky |
跑 pnpm typecheck(本地拦截类型错误,避免浪费 CI) |
FMT-08 lint-staged 只处理暂存文件,禁止在钩子里跑全量 lint / 全量测试(太慢会诱发 --no-verify)。
FMT-09 禁止 git commit --no-verify;如确因钩子故障,须在 PR 描述说明并附 CI 结果。
5 CI 门禁(阻断项)
| 阶段 |
命令 |
失败后果 |
| 安装 |
pnpm install --frozen-lockfile |
阻断(lock 不一致直接失败) |
| 格式 |
pnpm format:check |
阻断 |
| Lint |
pnpm lint --max-warnings=0 |
阻断 |
| 类型 |
pnpm typecheck |
阻断 |
| 单测 |
pnpm test -- --coverage |
阻断(覆盖率不得低于基线) |
| 迁移 |
prisma migrate diff 校验 schema 与迁移一致 |
阻断 |
| 构建 |
pnpm build |
阻断 |
| 安全 |
依赖审计 + 镜像高危漏洞 |
阻断(高危 0) |
FMT-10 CI 与本地必须使用同一份配置,禁止 CI 单独放宽规则。
FMT-11 覆盖率基线只升不降;下调须在 PR 说明理由并由技术负责人批准。
6 例外与豁免
| 场景 |
做法 |
| 生成代码(Prisma Client、OpenAPI 类型) |
在 eslint.config.mjs 中按路径 ignores,禁止在生成文件内加注释 |
| 第三方类型缺陷 |
文件级 /* eslint-disable rule -- 原因 */,必须写原因并在 PR 说明 |
| 单行特殊语法 |
行内 // eslint-disable-next-line rule -- 原因 |
| 全文件 disable |
禁止;确需则改为局部 disable 或调整规则配置 |
FMT-12 任何 eslint-disable 都必须写明原因与到期处理方式(升级依赖 / 提 issue)。
FMT-13 规则调整(新增 / 降级 / 关闭)必须单独 PR,说明影响文件数与整改计划。
7 检查清单