Stylelint插件开发完全指南:从规则编写到测试发布

Stylelint插件开发完全指南:从规则编写到测试发布

stylelint A mighty CSS linter that helps you avoid errors and enforce conventions. stylelint 项目地址: https://gitcode.com/gh_mirrors/st/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. 关键开发要点

  1. 命名规范

    • 必须使用命名空间/规则名格式(如company/button-selector
    • 避免与内置规则冲突
  2. 选项处理

    • 主选项(primary):通常为布尔值或数组
    • 次选项(secondaryOptions):可选配置对象
    • 必须使用validateOptions进行验证
  3. AST遍历

    • 使用PostCSS提供的节点遍历方法(如walkRules
    • 可访问选择器、声明、注释等节点类型
  4. 错误报告

    • 必须使用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关键词

最佳实践建议

  1. 文档规范

    • 清晰说明规则用途和配置选项
    • 提供正反示例代码
  2. 错误消息

    • 保持友好且具有指导性
    • 使用ruleMessages统一格式
  3. 版本兼容

    • 准确声明支持的Stylelint版本范围
    • 及时跟进主版本更新
  4. 性能优化

    • 避免不必要的AST遍历
    • 复杂检查考虑使用缓存

通过遵循这些指南,您可以开发出高质量、易维护的Stylelint插件,有效提升团队的样式表代码质量。

stylelint A mighty CSS linter that helps you avoid errors and enforce conventions. stylelint 项目地址: https://gitcode.com/gh_mirrors/st/stylelint

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

裴才隽Tanya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值