Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Some Gulp.js which reworks a tad of BEM CSS so you can use multiple Modifiers in a single BEM class
/*
Some Gulp.js which reworks a tad of BEM CSS so you can use multiple Modifiers in a single BEM class
Some BEM CSS like this:
.__block{display: block;}
.__block__element{display: inline-block;}
.__block__element_color-1{color: yellow;}
.__block__element_background-2{background: Green;}
.__block__element_font-3{font-family: Arial;}
Becomes:
.__block {display: block; color: red; }
.__block__element, *[class^="__block__element_"][class*="color-1"], *[class^="__block__element_"][class*="background-2"], *[class^="__block__element_"][class*="font-3"] {display: inline-block; }
.__block__element_color-1, *[class^="__block__element_"][class*="color-1"] {color: yellow; }
.__block__element_background-2, *[class^="__block__element_"][class*="background-2"] {background: Green; }
.__block__element_font-3, *[class^="__block__element_"][class*="font-3"] {font-family: Arial; }
So you can do: __block__element_color-1_background-2_font-3
Mind you, will bloat your CSS. But nothing gzip can not fix
*/
var _ = require("underscore");
var gulp = require('gulp');
var sass = require('gulp-ruby-sass');
var through = require('through2');
var gutil = require('gulp-util');
var fs = require('fs');
gulp.task('betterbem', function () {
return gulp.src('css/bem.scss')
.pipe(betterBEM());
});
gulp.task('default', ['betterbem'], function () {
return gulp.src('css/better_bem.scss')
.pipe(sass())
.pipe(gulp.dest('css'));
});
// produce the CSS so you can use multiple Modifiers in a single BEM class
function betterBEM(){
var stream = through.obj(function(file, enc, cb) {
var css = fs.readFileSync(file.path, 'utf-8');
var CSSOM = require('cssom');
var CSSTree = CSSOM.parse(css);
var bemList = bemListing(CSSTree.cssRules);
var sass = require('node-sass');
var scss = [], betterSCSS;
_.each(bemList, function(modifiers, blockElement){
_.each(modifiers, function(modifier){
scss.push('*[class^="' + blockElement + '_"][class*="' + modifier.substring(1) + '"]{@extend .' + blockElement + ' !optional; @extend .' + blockElement + modifier + ' !optional;}');
});
});
betterSCSS = css + scss.join('');
fs.writeFileSync('./css/better_bem.scss', betterSCSS);
var file2 = new gutil.File({
path: './css/better_bem.scss'
});
this.push(file2);
cb();
})
return stream;
}
// create a list of Block/Elements plus their accompanying Modifiers
function bemListing(cssRules){
var bemList = {};
_.each(cssRules, function(rule){
selector = rule.selectorText;
bem = bemParts(selector);
if(_.has(bem, 'be')){
if(!_.has(bemList, bem.be)){
bemList[bem.be] = [];
}
if(_.has(bem, 'm')){
bemList[bem.be].push(bem.m);
}
}
});
return bemList;
}
// rip apart a selector for it Block/Element/Modifier parts
function bemParts(selector){
if(selector.indexOf('.') == 0){
selector = selector.substring(1);
}
if(selector.indexOf('__') != 0){
return {selector: selector};
}
// Only get the actual BEM classname, not particularly graceful
selector = selector.split(',')[0];
selector = selector.split(' ')[0];
selector = selector.split(':')[0];
// Some extensive splitting due to kaBEM class starting with '__' (yes, i should use a better Block prefix ;) )
var BE = selector.split('__');
var M = BE.pop().split('_');
BE.push(M.shift());
var ret = {be: BE.join('__'), selector: selector};
if(M.length > 0){
ret.m = '_' + M[0];
}
return ret;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.