Search code examples
csslessbem

Validate less with gulp including BEM


so I have a fairly decent sized code base which is using less (many files). I want to convert the css to use BEM (actually a variant of BEM) and I would love to find a gulp way to lint the less files including naming conventions.

Is there any way to do this?

So basically I would like all the default css lint stuff and additionally define naming conventions that may not be broken.

E.g. classes need to start with c-, u- or o-, other classes are not permitted.


Solution

  • If postprocessors like https://github.com/necolas/postcss-bem-linter won't work for you for some reason. You can write your own, or possible create a Less Plugin. Less plugin can be visitors or postprocess, which can be used by you.

    E.g. classes need to start with c-, u- or o-, other classes are not permitted.

    Example of a visitor plugin that checks the above requirement:

     <!DOCTYPE html>
     <html>
     <head>
     <title>BEM Validation</title>
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link type="text/css" href="bem.less" rel="stylesheet/less">
    <script>
    var ValidateBEM = function(less) {
        this._visitor = new less.visitors.Visitor(this);
    };
    ValidateBEM.prototype = {
        isReplacing: true,
        run: function (root) {
        return this._visitor.visit(root);
        },
        visitRuleset: function (rulesetNode, visitArgs) {
            console.log(visitArgs);
            if(rulesetNode.selectors) {
    
            for (var i = 0; i < rulesetNode.selectors.length; i++) {
    
                if(rulesetNode.selectors[i].elements[0].value.match(/^\./)){
    
    
                    if(!rulesetNode.selectors[i].elements[0].value.match(/^\.[cuo]-/))
                    {
                    console.log(rulesetNode.selectors[i].elements[0]);
                    throw { type: 'BEM Validation',
                    message: "class names should start with c-, u- or o-",
                    filename: rulesetNode.selectors[i].elements[0].currentFileInfo.filename,
                    index: rulesetNode.selectors[i].elements[0].index };
                    }   
    
                }   
            }
    
            }   
    
            return rulesetNode;
        }
    };
    
    var ValidateBEMPlugin = {
        install: function(less, pluginManager) {
            pluginManager.addVisitor(new ValidateBEM(less));
        }
    }; 
    
    less = { 
        env: "development",
        plugins: [ValidateBEMPlugin]
    };
    </script> 
    <script src="//cdnjs.cloudflare.com/ajax/libs/less.js/2.4.0/less.min.js"></script>
    
    </head> 
    <body>
    <header>
        <h1>header</h1>
    </header>
    
    
    
    
    </body>
    </html>
    

    When bem.less contains the following class:

    .class {
    t:test;
    }
    

    in above will result in the error like that shown beneath:

    enter image description here

    Grunt-contrib-less allows you to use Less Plugin too:

    less: {
      production: {
        options: {
          paths: ["assets/css"],
          plugins: [
            new (require('less-plugin-bem'))({browsers: ["last 2 versions"]}),
          ] }
    }
    }
    

    The plugin used above only works in browser, see How to exend the Less compiler with a custom function leveraging a plugin how to create a CLI version.