ci / 质量门禁 (push) Canceled after 0s
背景:用户确认仓库只保留 main,不再创建任何远程分支或走 PR 合并。 改动: - 01-Git规范 V1.1:仅 main 直推,禁止非 main 分支推送、force push 与 Merge commit; - AGENTS V1.1:变更流程改为直接提交并推送 main; - 07-CodeReview:PR 模板改为提交说明,合并流程改为推送与推送后观察; - 03/06/工程规范 README 同步去除 PR 措辞; - CI 仅保留 push main 与 workflow_dispatch 触发。 影响面:仅流程与文档,无代码/数据/接口变更。 回滚方式:git revert 本提交即可恢复旧流程。 验证:format:check、lint、typecheck 全绿(10/10)。
5.8 KiB
5.8 KiB
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-03CI 执行pnpm format:check,失败即阻断。FMT-04禁止把格式化产生的无关改动混进功能提交(会产生冲突与 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 强制)
禁止导入(含子路径):
@douyinfe/semi-ui ← 只能用 @douyinfe/semi-ui-19
antd @ant-design/* @arco-design/*
@douyinfe/semi-icons @ant-design/icons react-icons lucide-react @heroicons/*
element-plus naive-ui @mui/* @chakra-ui/*
规则:
FMT-05图标只能import { IconXxx } from '@lingxi/ui/icons';禁止import * as Icons、禁止直接引remixicon/icons/...。FMT-06SVG 内联仅允许品牌 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.2) |
pre-push |
husky | 跑 pnpm typecheck(本地拦截类型错误,避免浪费 CI) |
FMT-08lint-staged只处理暂存文件,禁止在钩子里跑全量 lint / 全量测试(太慢会诱发--no-verify)。FMT-09禁止git commit --no-verify;如确因钩子故障,须在提交说明中说明并附 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-10CI 与本地必须使用同一份配置,禁止 CI 单独放宽规则。FMT-11覆盖率基线只升不降;下调须在提交说明说明理由并由技术负责人批准。
6 例外与豁免
| 场景 | 做法 |
|---|---|
| 生成代码(Prisma Client、OpenAPI 类型) | 在 eslint.config.mjs 中按路径 ignores,禁止在生成文件内加注释 |
| 第三方类型缺陷 | 文件级 /* eslint-disable rule -- 原因 */,必须写原因并在提交说明说明 |
| 单行特殊语法 | 行内 // eslint-disable-next-line rule -- 原因 |
| 全文件 disable | 禁止;确需则改为局部 disable 或调整规则配置 |
FMT-12任何eslint-disable都必须写明原因与到期处理方式(升级依赖 / 提 issue)。FMT-13规则调整(新增 / 降级 / 关闭)必须单独提交,说明影响文件数与整改计划。
7 检查清单
pnpm format:check通过,无格式化噪音混入pnpm lint --max-warnings=0通过pnpm typecheck通过- 无新增
eslint-disable;已有的都有原因 - 未引入禁用包 / 禁用图标库
- 无散落色值,样式走 token