Custom Stylelint Rules — Writing Your First one
At Testim.io we care about code quality and UX. For this reason, we use various tools that make development easier and more accurate. Among others, we use Stylelint to lint our SCSS and CSS files. One of the powerful features of stylelint is the ability to add rules of your own, which will fit your project’s needs. While stylelint provides an API for adding custom rules, it can be a bit confusing when doing so for the first time.
In this blog post, we will go through the steps for adding a new custom stylelint rule to your project:
- Declaring and creating the plugin
- Adding a rule to the plugin
- Implementing the linting function along with auto-fix support
- Integrating the plugin with your project’s Stylelint configuration
Background story
In our application’s codebase, we store commonly used colors in variables. This makes color theme changes very quick and easy. While developing a visual component, we use Invision’s mockups as a reference. Invision isn’t aware of the color variables we use. Thus, Copying styles from Invision involves searching for the colors’ variables (e.g. replace #ff6363
with $color-red1
).
This seems like an easy thing to do: use “find anywhere” and look for this color. Yet, the process becomes cumbersome — especially if we include many colors. Additionally, in some cases of legacy code, the variable ($color-red1
) was not used. Hence, we can find the same color (#ff6363
) scattered in the codebase. In such cases, the developer has to find the correct declaration in all search results.
In order to solve this inconvenience, we wrote a custom stylelint rule. It suggests the correct variable name, and even auto-fixes the errors. How convenient!
In the following paragraphs, we will describe the steps for adding a custom rule of your own. As an abbreviated example, we’ll write a rule which will replace the expression blue
with the hex value #0000FF
.
Writing the Plugin — First Steps
Let’s start with creating a file that will contain the rule itself — in our case, it’s no-color-blue.js
.
Next, you’ll need to define your rule. This way stylelint will know what to run when the rule appears in the configurations:
Your file will need to export three things: the rule name, the messages that it shows, and the rule itself.
If it still doesn’t make much sense to you, that’s ok! In the next sections we’ll explain each part.
Creating a Plugin
We use stylelint.createPlugin
to create and register a stylelint rule. It receives two arguments: the rule name, and the ruleFunction itself.
stylelint calls ruleFunction
if the rule is used in the linting process. The function receives the configured options, along with the linting context
object.
The lint function (that ruleFunction
returns) will run on each file that is being linted. This is the actual core of the rule which will report the output for the linting process.
Let’s take a deeper look at ruleFunction
and lint
.
Adding a Rule to the Plugin
As mentioned before, stylelint calls ruleFunction for each single linting “process”. Stylelint’s rule support options. These can be used to customize the rule’s behavior from the stylelint’s configuration. For example, most rules support the severity option. When using your rule, the ruleFunction
will be called with the matching options (primary and secondary).
Furthermore, stylelint provides a handy validateOptions
function. Use it to automatically report errors if the user passed invalid options. Stylelint will add the errors to the linting result (called here postcssResult
). The documentation isn’t too extensive, but the source code has some good comments.
The third argument of ruleFunction
is the context
object. It is mainly used for supporting auto-fix (more on that later).
The following snippet should make things clearer:
We’re done with setting up the rule. Now, let’s write the lint
function which holds the core logic of the rule.
Performing the Linting
After creating your rule, stylelint will run PostCSS on each linted file. Next, in the linting phase, stylelint will call the custom rule’s lint
function. The lint
function is at the core of your rule. It receives two arguments:
postcssRoot
— the parsed AST. It “represents a CSS file and contains all its parsed nodes”.postcssResult
— the LazyResult which will accumulate the output of your rule’s linting.
Usually, the lint
function will:
- “Walk” through the AST (the parsed CSS nodes). Use one of the
root.walk
methods for this task. - Detect invalid nodes.
- Report these nodes (or fix them, depending on the “fix” flag).
Let’s examine the complete example of our rule. Reminder — the rule forbids the color name blue
and expects it to be replaced with the hex RGB color #0000FF
.
That’s it! All that’s left is adding the rule to stylelint’s config.
Custom Rule Integration
Edit your project’s stylelint configuration (e.g. .stylelintrc.json
). Under the “plugins” configuration value, add a path to your plugin’s file. All that’s left is activating your rule, so stylelint will actually run it. Do this by adding your rule to the “rules” configuration value.
A minimal .stylelintrc
file will look like so:
Please note that for enabling a rule, stylelint requires passing options to it. Even if the rule has no options (like our no-color-blue
example), it is still required to pass a true
option to it. Without it, stylelint will ignore the rule.
That’s it! You and your team can now enjoy your custom linting errors.
Summary
Stylelint is a very useful linting tool. It has many advantages when collaborating on common SCSS and CSS files. It comes with a vast variety of existing rules. Yet, they can’t always answer all your needs. At some point, you’ll need a linting rule that is yet to exist. It might be the project’s structure, your team’s conventions, or anything else. In these cases, custom rules will be very helpful.
I hope that after reading this post, you will be able to quickly create and integrate your own stylelint rules. This way, you will keep a higher level of code quality while respecting your project’s requirements.
Further reading
- Stylelint’s plugins documentation
- Awesome Stylelint — A list of awesome stylelint configs, plugins, etc. [EDIT] — This post is now in Awesome List!
- Stylelint’s guidelines for creating robust rules
- PostCSS AST API
🕵️♂️ Psst… If you enjoyed this, follow me on Twitter (@omril321) — I tweet regularly about cool things I learn.