Stylelint:CSS 规则、custom syntax 与样式门禁
Stylelint 先要读懂文件,才能谈规则
Stylelint 检查 CSS 及通过 custom syntax/processor 支持的样式代码。普通 CSS、SCSS、Vue SFC、CSS-in-JS 不是同一语法入口;只把后缀加入 glob,可能得到大量伪语法错误,也可能让嵌入样式根本未被提取。确定性排版由 Prettier负责,JavaScript 语义由 ESLint负责。
本文实验锁定 Stylelint 17.14.1。当前主版本的规则与 Node.js 支持以官方 Release和迁移指南为准;共享配置、插件和 custom syntax 还有各自 peer dependency。版本只作为验证基线。
安装核心与标准配置
npm install --save-dev --save-exact stylelint@17.14.1 stylelint-config-standard
npm ci
npm exec -- stylelint --version
npm ls stylelint stylelint-config-standard普通 CSS 的 stylelint.config.mjs:
/** @type {import("stylelint").Config} */
export default {
extends: ["stylelint-config-standard"],
ignoreFiles: ["dist/**", "coverage/**", "generated/**"],
reportDescriptionlessDisables: true,
reportInvalidScopeDisables: true,
reportNeedlessDisables: true,
reportUnscopedDisables: true,
rules: {
"color-no-invalid-hex": true,
"declaration-block-no-duplicate-properties": true,
},
};共享配置提供起点,不是永久政策。项目覆盖规则要写清原因和 owner;升级共享配置时比较最终规则集合与问题差异,不能只看核心 Stylelint 版本。
custom syntax 是解析边界
SCSS、Vue、Svelte 或 CSS-in-JS 需要对应的受支持 custom syntax 与共享配置,并用 overrides 限定:
export default {
extends: ["stylelint-config-standard"],
overrides: [
{
files: ["**/*.scss"],
customSyntax: "postcss-scss",
extends: ["stylelint-config-standard-scss"],
},
{
files: ["**/*.vue"],
customSyntax: "postcss-html",
},
],
};这些包必须进入项目依赖并锁版本。为每种文件类型保留一个应通过样例和一个应失败样例;核心、custom syntax、共享配置或框架升级后全套复跑。若解析器只能看见 Vue 模板而没有提取 <style>,绿灯不代表样式被检查。
ignore 要能证明没有吞掉源码
大量排除放在 .stylelintignore:
dist/
coverage/
generated/
vendor/配置中的 ignoreFiles 适合少量稳定路径。CI 固定工作目录,Windows 与 Linux 的大小写和路径分隔差异进入验证。文件没有被检查时使用详细输出与一个故意违规对照,不靠“命令执行很快”判断 glob 是否为空。
正反样例与非零退出码
.card {
color: #12zz99;
display: block;
display: flex;
}执行:
npm exec -- stylelint .quality-smoke/stylelint-bad.css预期 color-no-invalid-hex 与重复属性规则命中,退出码非零。修正颜色并删除无效重复后,同一命令通过。若报告出现但 CI 绿灯,检查 shell 管道、|| true 和包装脚本;若没有报告,检查 glob、ignore、配置查找与 custom syntax。
项目脚本分开检查和修复:
{
"scripts": {
"lint:css": "stylelint \"src/**/*.{css,scss,vue}\" --max-warnings 0",
"lint:css:fix": "stylelint \"src/**/*.{css,scss,vue}\" --fix"
}
}glob 由引号交给 Stylelint 处理,降低不同 shell 展开差异。CI 只运行检查;--fix 在开发者或独立修复提交执行,并在前后查看 Git diff。
disable 注释是例外记录
Stylelint 支持文件、区间和单行 disable。reportDescriptionlessDisables 要求说明,reportNeedlessDisables 发现已不再需要的禁用,invalid scope 和 unscoped disable 也单独报告。例外必须指向具体规则、原因、owner 与移除条件,不能用无规则名的文件级 disable 消音。
升级后先运行报告模式,清理 needless disable;规则改名或删除时,旧注释可能失去作用或变成误导。生成 CSS 可在输入边界排除,但源码模板和手写样式不能因构建产物相似而一起进入 ignore。
与 Prettier 的冲突只保留一个 owner
Stylelint 适合 CSS 正确性、未知属性、选择器与团队约束;Prettier 负责缩进和换行。已从 Stylelint 核心移除的纯风格规则不要通过旧共享配置重新引入,与 Prettier 争夺同一文本。保存后反复变化时,关闭所有自动修复,分别运行 Prettier 与 Stylelint,定位冲突规则后从 Linter 侧移除格式职责。
Stylelint 的 --fix 仍可能改变代码。自动修复前保留未提交工作状态,只允许安全规则;修复后运行 stylelint、Prettier check、构建和视觉/组件测试,不能把“可自动修”解释成“语义不会变”。
插件、formatter 与报告边界
Stylelint 配置可执行 JavaScript,插件、custom syntax、共享配置和 formatter 都在当前进程运行。依赖精确锁定,只从受控制品源安装;外部 PR 的质量 Job 不持有发布或生产凭证。第三方 formatter 只改变输出并不意味着无风险,同样要审查来源。
JSON/SARIF/文本报告可能包含内部路径、选择器和源码片段,按 CI 制品授权与留存。IDE 扩展使用工作区 Stylelint 和仓库配置,编辑器未打开的文件仍由 CI 全量复核。
性能、缓存与多包仓库
复杂 custom syntax、插件和宽 glob 会放大耗时。记录实际文件数、P50/P95、峰值内存和各 package 分布;PR 可按受影响 package 快速反馈,主分支或定时任务运行全量。缓存是加速状态,不是历史违规 baseline,配置或插件变化后清理并做全量对照。
Monorepo 可以用根配置加 overrides,也可以每个 package 明确配置。选择取决于语法和发布边界,但最终必须能解释任一文件命中哪份配置、哪些插件和哪条规则。根命令成功而子包 glob 未匹配,属于门禁缺口。
升级与回滚
升级同时记录 Node.js、Stylelint、custom syntax、共享配置、插件、formatter 与实际文件集合。旧新组合在同一提交影子运行,差异按新增/消失违规、规则废弃、解析错误、自动修复 diff、耗时和 ignore 变化分类。
回滚恢复依赖清单、lockfile、配置、ignore、插件与缓存清理动作,再从干净安装运行普通 CSS 和每种扩展语法的正反样例。只有坏样例失败、修正后通过、disable 可审计、custom syntax 确实提取目标样式、CI 不吞退出码,Stylelint 门禁才具备长期可信度。
