Stylelint插件开发完全指南:从规则编写到测试发布
前言
Stylelint作为现代CSS/Less/Sass等样式表的强大检查工具,其插件系统允许开发者扩展自定义规则。本文将深入讲解如何开发高质量的Stylelint插件,涵盖规则编写、测试验证到发布共享的全流程。
插件基础概念
Stylelint插件本质上是自定义规则或规则集合的封装,主要用于:
- 支持特定方法论或工具集(如BEM规范检查)
- 处理非标准CSS特性(如CSS-in-JS语法)
- 满足特殊业务场景需求(如公司内部样式规范)
插件开发实战
1. 插件基本结构
以下是一个禁止选择器中包含"foo"的完整插件示例:
import stylelint from "stylelint";
const {
createPlugin,
utils: { report, ruleMessages, validateOptions }
} = stylelint;
// 规则名称必须包含命名空间
const ruleName = "foo-org/selector-no-foo";
// 定义错误消息模板
const messages = ruleMessages(ruleName, {
rejected: (selector) => `选择器"${selector}"中不允许包含"foo"`
});
// 元数据(文档链接等)
const meta = {
url: "https://example.com/stylelint-selector-no-foo"
};
/** @type {import('stylelint').Rule} */
const ruleFunction = (primary, secondaryOptions, context) => {
return (root, result) => {
// 验证选项
const validOptions = validateOptions(result, ruleName, {
actual: primary,
possible: [true]
});
if (!validOptions) return;
// 遍历所有规则节点
root.walkRules((ruleNode) => {
const { selector } = ruleNode;
if (!selector.includes("foo")) return;
// 报告错误
report({
result,
ruleName,
message: messages.rejected(selector),
node: ruleNode,
word: selector
});
});
};
};
// 设置规则属性
ruleFunction.ruleName = ruleName;
ruleFunction.messages = messages;
ruleFunction.meta = meta;
// 导出插件
export default createPlugin(ruleName, ruleFunction);
2. 关键开发要点
-
命名规范:
- 必须使用
命名空间/规则名
格式(如company/button-selector
) - 避免与内置规则冲突
- 必须使用
-
选项处理:
- 主选项(primary):通常为布尔值或数组
- 次选项(secondaryOptions):可选配置对象
- 必须使用
validateOptions
进行验证
-
AST遍历:
- 使用PostCSS提供的节点遍历方法(如
walkRules
) - 可访问选择器、声明、注释等节点类型
- 使用PostCSS提供的节点遍历方法(如
-
错误报告:
- 必须使用
stylelint.utils.report
- 禁止直接使用PostCSS的
warn
方法
- 必须使用
3. 异步规则处理
当需要异步操作时(如读取外部配置),可使用async/await:
const ruleFunction = (primary) => {
return async (root, result) => {
const config = await loadConfig();
root.walkDecls((decl) => {
if (config.disallowedProps.includes(decl.prop)) {
report(/*...*/);
}
});
};
};
测试策略
1. 使用专用测试工具
推荐使用stylelint-test-rule-node
进行规则测试:
import { testRule } from "stylelint-test-rule-node";
import plugin from "./plugin.js";
testRule({
plugins: [plugin],
ruleName: "plugin/rule-name",
config: true,
accept: [{ code: ".valid {}" }],
reject: [{
code: ".invalid {}",
message: "错误消息模板",
line: 1,
column: 1
}]
});
2. 直接集成测试
对于复杂场景可直接调用Stylelint API:
const { lint } = stylelint;
it("应检测错误", async () => {
const results = await lint({
code: ".foo {}",
config: {
plugins: ["./plugin.js"],
rules: { "plugin/rule-name": true }
}
});
expect(results.warnings).toHaveLength(1);
});
高级技巧
1. 复用内置规则
通过stylelint.rules
可复用现有规则:
const baseRule = await stylelint.rules["color-no-invalid-hex"];
const customRule = (primary) => {
return (root, result) => {
// 前置处理...
baseRule(primary)(root, result);
// 后置处理...
};
};
2. 规则组合检查
使用checkAgainstRule
可在规则中调用其他规则:
await checkAgainstRule({
ruleName: "at-rule-no-unknown",
ruleSettings: [true, { ignoreAtRules: ["custom"] }],
root
}, (warning) => {
// 处理警告
});
发布与共享
1. 包配置要点
在package.json
中需声明:
{
"peerDependencies": {
"stylelint": "^15.0.0"
},
"keywords": [
"stylelint",
"stylelint-plugin"
]
}
2. 规则包类型
- 单一规则:导出单个规则对象
- 规则集合:导出规则对象数组
- 配置预设:使用
stylelint-config
关键词
最佳实践建议
-
文档规范:
- 清晰说明规则用途和配置选项
- 提供正反示例代码
-
错误消息:
- 保持友好且具有指导性
- 使用
ruleMessages
统一格式
-
版本兼容:
- 准确声明支持的Stylelint版本范围
- 及时跟进主版本更新
-
性能优化:
- 避免不必要的AST遍历
- 复杂检查考虑使用缓存
通过遵循这些指南,您可以开发出高质量、易维护的Stylelint插件,有效提升团队的样式表代码质量。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考