Integrating Stylesheet Linting with Webpack

I converted my eslint setup to Webpack in the last article, so I figured it was time to go all the way and integrate my full lint and test environment into the Webpack workflow. I’m not sure about test (since my test files are completely separate), but linting can be incorporated easily. Since I’d already done eslint, sass-lint incorporation was next.

Unfortunately, herein lies problems. Firstly, sass-lint has issues – most notably, it has problems with certain rules around indentation that I happen to like. So, what are the alternatives? Well, there is scss-lint, which seems to be out of maintenance (one of my requirements to use a library is that it is actively maintained), and there is stylelint. I was very satisfied with stylelint from a command line point of view – it corrected all of the issues that I had with sass-lint.

Stylelint didn’t have a loader. Fortunately, those are relatively easy to write, so I wrote one. You can find it published on

Now that I have the loader, how do I use it? I need to install it from

npm install --save-dev stylelint-loader stylelint

My loader has stylelint as a peerDependency. You have to install those separately so I am installing stylelint at the same time. This allows one to use alternate versions of stylelint – you aren’t tied to the version provided withe the loader.

Onto configuration. As with all things Webpack, I am configuring this within the webpack.config.js file:

    module: {
        preLoaders: [
            // Javascript
            { test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/ },
            // Stylesheets
            { test: /\.s(a|c)ss$/, loader: 'stylelint' }
        loaders: [
            // Javascript
            { test: /\.jsx?$/, loader: 'babel', exclude: /node_modules/ },
            // Stylesheets
            { test: /\.css$/, loader: ExtractTextPlugin.extract( 'style', 'css?sourceMap') },
            { test: /\.s(a|c)ss$/, loader: ExtractTextPlugin.extract( 'style', 'css?sourceMap!sass?sourceMap') },
            // Font Definitions
            { test: /\.svg$/, loader: 'url?limit=65000&mimetype=image/svg+xml&name=public/fonts/[name].[ext]' },
            { test: /\.woff$/, loader: 'url?limit=65000&mimetype=application/font-woff&name=public/fonts/[name].[ext]' },
            { test: /\.woff2$/, loader: 'url?limit=65000&mimetype=application/font-woff2&name=public/fonts/[name].[ext]' },
            { test: /\.[ot]tf$/, loader: 'url?limit=65000&mimetype=application/octet-stream&name=public/fonts/[name].[ext]' },
            { test: /\.eot$/, loader: 'url?limit=65000&mimetype=application/[name].[ext]' }

This should be familiar syntax by now – the preloader doesn’t actually do any bundling, so it’s an ideal place to put linters. I need to configure my stylelint-loader – it requires me to specify the Stylelint configuration file location so that it can be passed into the library:

    stylelint: {
        configFile: path.join(__dirname, './.stylelint.config.js')

One of the nice things about stylelint is that they also publish standard configurations to npm. So I can do this:

npm install --save-dev stylelint-config-suitcss

And then include this with some overrides in my .stylelint.config.js file:

module.exports = {
    extends: [
    rules: {
        'function-url-quotes': 'single',
        'indentation': [ 4, { warn: true } ],
        'string-quotes': 'single'

Adding linting was relatively straight forward since I’d done most of the hard work when I did eslint. As always, find the code on my GitHub Repository. Both eslint and stylelint are run automatically when my project is built, allowing for an instant check on coding style and common errors.

9 thoughts

  1. Hi Adrian,

    thanks for this article. I’ve been trying to get your loader to work but I keep stumbling at the install stage.

    I run `npm install –save-dev stylelint-loader stylelint`

    But every time it completes I get the error `npm ERR! peer dep missing: stylelint@^3.2.0, required by stylelint-loader@0.2.0`

    When I check my node_modules folder I can see stylelint is at version 4.2.0.

    Any advice on how I can get this to work would be awesome.




  2. Ah, awesome! Thanks so much for the quick reply. That error has stopped now since grabbing your update 🙂

    However, I can’t get it to write any SCSS errors to the console.

    I’m running Eslint for my js which is working fine. But for some reason nothing happens with my scss no matter how badly I break the rules I set.

    I’m using the following in my webpack config:

    `stylelint: {
    configFile: path.join(__dirname, ‘./.stylelint.config.js’),
    rules: {
    ‘function-url-quotes’: ‘single’,
    ‘indentation’: [ 4, { warn: true } ],
    ‘string-quotes’: ‘single’

    but when I use double quotes or 2 space indentation nothing appears in the console.

    It also doesn’t throw an error if I change the config file name e.g:

    `configFile: path.join(__dirname, ‘./SOME_RANDOM_FILE.config.js’),`

    it doesn’t throw an error saying it can’t be found or anything. So I’m wondering if it’s even being initiated properly.


    • There was a couple of bugs in there that I have now fixed and published. Your problem was that the .stylelint.config.js file was not valid. However, my problem was that I was not reporting the fact. The new version of stylelint-loader now reports invalid rules and missing files (those were the two bugs).

      Thanks for the bug report!


      • Awesome, thanks so much man. It’s working now.

        I did have one other question. Is it possible to have it read from a .stylelintrc file that just contains a json object? That way it would be possible to use the same lint file for my text editor and build process.

        At the moment I’m having to duplicate it in both a .stylelint.config.js file and a .stylelintrc file

        Thanks again


      • I’d have to check the stylelint API. Have you tried just specifying the .stylelintrc file as the configFile option? (I haven’t – just mentioning it). If that doesn’t work, feel free to file an issue in the GitHub repository.


Comments are closed.