pre-commit钩子中stylelint应仅校验暂存区css文件,通过git diff --cached提取变动文件、cd至仓库根目录、用正则兼容utility类和bem规范,并辅以html-validate和eslint校验jsx/html中的class名。

pre-commit 钩子里 stylelint 只校验暂存区 CSS 文件
直接跑 stylelint "**/*.css" 会扫全量文件,既慢又误报——CI 或本地提交时,真正要检查的只是 git add 进暂存区的那几个改动文件。
实操脚本关键三步:
- 用
git diff --cached --name-only --diff-filter=ACM提取本次提交新增/修改/重命名的文件 - 加
| grep '\.css$'过滤出 CSS 类型(注意单引号防 shell 展开) - 开头必须
cd $(git rev-parse --show-toplevel)切到仓库根,否则stylelint找不到配置文件
漏掉任一环,钩子要么不生效,要么报路径错误。尤其 cd 这步,本地开发常因工作目录在子文件夹而失败。
selector-class-pattern 正则必须覆盖 utility 类和嵌套 modifier
官方文档给的正则太理想化,实际项目里混着 u-margin-top-16 这类工具类,或 card__header--large--dark 这种非法嵌套修饰符,硬套默认规则会放行或误杀。
推荐正则写法(兼容 utility + 基础 BEM):
^(u-[a-z][a-zA-Z0-9]+|([a-z][a-zA-Z0-9]+(__[a-z][a-zA-Z0-9]+)?(--[a-z][a-zA-Z0-9]+)?))$
注意点:
- 禁止写
card__header--large--dark,BEM 不允许修饰符嵌套,应拆成两个 class:card__header--large card__header--dark -
--和__是硬性锚点,写成_或-单字符,工具链就识别不了 - 禁用
selector-max-id等无关规则,它们和 BEM 无关,只增加误报
JS 中手拼 className 是最高危破规点
本地开发看着能跑通,但 CI 构建环境对空格、大小写、连字符更敏感,button__icon_error 少个 - 或多一个空格,就变成无效类名,样式失效且无提示。
安全做法只有两种:
- 封装常量函数:
const cn = (e, m) => `${BLOCK}${e ? '__' + e : ''}${m ? '--' + m : ''}`,调用cn('input', 'disabled')得到search-form__input--disabled - 用
clsx或classnames,传对象:clsx(styles.button, { [styles['button--primary']]: isPrimary })
绝对避免:className={`button button--${variant} ${hasIcon ? 'button__icon' : ''}`——缺空格、无校验、脱离 block 上下文。
ESLint + HTML 校验构成第二道防线
stylelint 管 CSS 文件,但 class 名也可能写在 JSX/HTML 里,比如 <div class="card__title"> 写错,stylelint 压根看不到。
<p>必须补两层检查:</p>
<ul>
<li>用 <code>html-validate 规则校验所有 class 属性值,正则同上,拒绝含 _ 单下划线或 __ 后接大写字母的提交
eslint-plugin-css-modules 检查 .module.scss 文件:比如 button.module.scss 里只允许出现 button、button__icon、button--loading,禁止 card__title 这类跨 block 类名最易被忽略的是 HTML 层校验——开发者改 JSX 时绕过 CSS 文件,直接写 class 字符串,这正是破规高发区。











