How to use CSS linter in Meteor

CSS linting is a topic which is often overlooked and this is quite understandable because CSS formatting, providing rules for it, etc., are not so important in many teams and projects. But sometimes they are. We will take a look at how to prepare CSS linter in the Meteor app.

You are probably thinking — why do I need this if I use Sass or Less preprocessors? My CSS will be well formatted anyway. Yes, it’s true that when using preprocessors our CSS code is probably well formatted in the end. It is also true that even when we are not using any preprocessor, Meteor’s built in ‘css-stringifier’ will format our outputted CSS code and it will do it well too. But what if our team decided that we’re not using id’s in CSS code or we want to validate the format of our CSS class names using some kind of RegExp? And what if we don’t want to allow usage of some CSS functions like scale() or calc()? I know, these examples are really rare in projects because why would we ever want to disallow CSS functions usage? Regardless, there are many other rules which we might want to apply to keep our CSS code base unified. Even when you want to use two different preprocessors in one app you can still have control over it. You’ll find out more about it later.

So how do you lint CSS in the Meteor app?

Meteor uses its own CSS build processors. It will take any CSS code in the app and process it. It will also take any code processed by Scss or Less packages. So we need to plug it in at the end of this process. This is possible with the PostCSS tool. Some time ago I wrote a blog post about using PostCSS in Meteor. We will use the package mentioned there. If you need to know more about the package, you can read the article or you can read package’s readme file which you’ll find here: juliancwirko:postcss. And don’t worry. You can still use your favorite preprocessor with PostCSS. They can work together. Moreover, you’ll get Autoprefixer for free, because Autoprefixer is also a PostCSS plugin.

The second tool we need here is a PostCSS plugin called Stylelint (although this is also a standalone library, we will use it as a PostCSS plugin in Meteor).

Let’s create a demo Meteor app

It will be a very simple demo app created in a standard way with:

$ meteor create css-lint-app

We will also use Scss to show you that it works with it. You will find the final demo app here: meteor-stylelint-demo. So you can just clone it and play around with it.

We need to add two packages but first remove the standard-minifier-css package

$ meteor remove standard-minifier-css

This is because the PostCSS package is a copy with added PostCSS processing.

Then we can add the two mentioned packages:

$ meteor add fourseven:scss juliancwirko:postcss

The first package will add Scss support to our app and the second — PostCSS support. You can read about the packages on its Readme pages.

Let’s prepare PostCSS config files. 
You should have ‘package.json’ file in your root directory (from Meteor 1.3 and above), in this file you need to declare which PostCSS plugins you want to use. You always use this file when you want to download some Npm packages. In our case we need it because all PostCSS plugins are standard Npm packages.

See here how it should look. Here is an example of that kind of file:

package.json:

{
"name": "demo Stylelint app",
"version": "1.0.0",
"description": "",
"author": "",
"devDependencies": {
"autoprefixer": "^6.3.5",
"stylelint": "^5.2.1"
"postcss-reporter": "^1.3.3"
},
"postcss": {
"plugins": {
"autoprefixer": {"browsers": ["last 2 versions"]},
"stylelint": {
"rules": {
"string-quotes": "double",
"selector-no-id": true,
"function-blacklist": "scale",
"selector-class-pattern": "[a-z]+"
}
},
"postcss-reporter": {"clearMessages": true}
}
}
}

Ok so what have we got here? In the package.json file we have configured Npm packages to download which are PostCSS plugins. We need stylelint and postcss-reporter and also we use an autoprefixer. These packages will be downloaded to the standard node_modules folder.

You can add more PostCSS plugins here, but remember that stylelint and postcss-reporter should be the last PostCSS plugins in postcss.plugins key. This is because Stylelint needs to wait for all CSS processing to be finished and, with PostCSS package plugins, the order in the packages.json file is important.

Next we also need to configure our plugins. Autoprefixer will consider only the last 2 versions of browsers. For Stylelint we choose some of the rules, just for demo purposes. Also PostCSS Reporter needs a special flag which will clear messages and will not pass them to other tools. With Meteor this is really useful because we have cleaner output in the console. This is all we need to lint our CSS. Let’s take a closer look at a possible Stylelint configuration.

You can find all of the Stylelint rules with description pages here: Stylelint rules. You just need to provide it in the postcss.json in the rules key under stylelint.

In our example app, when you run Meteor you should see some messages in the server side console. It should be exactly something like:

client/main.css
7:16 ⚠ Unexpected function “scale” (function-blacklist) [stylelint]
7:24 ⚠ Unexpected function “scale” (function-blacklist) [stylelint]
8:9 ⚠ Expected double quotes (string-quotes) [stylelint]
client/main.scss.css
1:1 ⚠ Expected class selector “.TEST” to match specified pattern (selector-class-pattern) [stylelint]
3:3 ⚠ Expected class selector “.TEST” to match specified pattern (selector-class-pattern) [stylelint]
4:17 ⚠ Expected double quotes (string-quotes) [stylelint]
6:1 ⚠ Unexpected id selector (selector-no-id) [stylelint]

I think this is really readable and doesn’t need a big explanation. These are all our errors tracked in our main.scss and main.css files. You can go and see how they look here: Demo app styles.

Remember that here you see the columns and rows of the compiled files. As you can see, there is the main.scss.css file and not main.scss file, which we have in our app. This is because we are linting only CSS files so also the output from the preprocessors. This could sometimes be inconvenient but there are really good messages so finding the proper place in the main.scss file shouldn’t be hard even with a complicated structure (which is better to avoid with Scss anyway). This is also applicable to normal CSS files which are processed by other PostCSS plugins.

Remember to always place the stylelint and postcss-reporter at the end of the postcss.plugins key in the package.json file. So it will only run after all CSS processing.

Final words

This is a demo configuration of Stylelint which is a tool used as a PostCSS plugin. PostCSS integration is provided by the juliancwirko:postcss Meteor package.

CSS linting is just one example of the possibilities which PostCSS provides. The second could be Autoprefixer used here. This way of usage is the native one. All existing Meteor solutions with Autoprefixer actually use some workarounds created in the preprocessors environment such as the Less autoprefixer plugin or the Stylus autoprefixer plugin. But of course this is not the biggest advantage of PostCSS. What is most important — You can write your own plugins which can do whatever you want with CSS code.
Of course this is just an introduction to the topic. I haven’t tested it on large applications with many packages, etc.

You may also want to check an experiment in which I use PostCSS to compile .scss files from Bootstrap 4 Npm package.

If you have any questions or ideas, I am on Twitter. Also check out my blog julian.io and read about how to use PostCSS in the Meteor app.