gulp-webp-css-splitter
Version:
Duplicate background images with webp. Add .webp and .no-webp classes. Minify result css
115 lines (104 loc) • 5.36 kB
JavaScript
const pluginName = 'gulp-webp-css-splitter';
const PluginError = require('gulp-util/lib/PluginError');
const through = require('through2');
var CSSParser = require('css');
var supportsRender = function (rulesArr) {
return rulesArr.join("");
}
module.exports = function(extensions){
var extensions = extensions || ['.jpg','.png'];
return through.obj(function(file, enc, cb) {
if (file.isNull()) {
cb(null, file);
return;
}
if (file.isStream()) {
cb(new PluginError(pluginName, 'Streaming not supported'));
return;
}
try {
var css = file.contents.toString();
var obj = CSSParser.parse(css);
if (!obj) return;
var getWebpRulesArr = function (arr) {
var webpLine = function(selectors, rule){
var line = selectors + ' {\n' + rule + '}\n';
return line;
}
var retn = {
webpArrStr: [],
originalArrStr: [],
media: {},
mediaOrig: {}
}
Object.keys(arr).forEach(function (k) {
var rule = arr[k];
// Если CSS правило
if(rule.type == 'rule'){
var declarations = rule.declarations;
// Перебираем декларации
var regularRules = '';
var currentSelector = '';
Object.keys(declarations).forEach(function (i) {
var declaration = declarations[i];
// Если находим background: url без .webp или .svg
if ((declaration.property.indexOf('background') + 1) && (declaration.value.indexOf('url') + 1) && !(declaration.value.indexOf('.webp') + 1) && !(declaration.value.indexOf('.svg') + 1)){
var newValue = declaration.value;
// Заменяем на webp
for(ext in extensions){
newValue = newValue.replace(extensions[ext],'.webp');
}
// Формируем строку и пушим в массив дополнений
currentSelector = rule.selectors.join(',');
var newRule = '\t' + declaration.property + ':' + newValue;
var pushStr = webpLine('.webp ' + currentSelector,newRule);
retn.webpArrStr.push(pushStr);
var oldRule = '\t' + declaration.property + ':' + declaration.value;
var pushStr = webpLine('.no-webp ' + currentSelector,oldRule);
retn.webpArrStr.push(pushStr);
}
else {
currentSelector = rule.selectors.join(',');
regularRules = regularRules + '\t' +declaration.property + ':' + declaration.value + ';\n';
}
});
if(regularRules != '') {
var pushStr = webpLine(currentSelector, regularRules);
retn.originalArrStr.push(pushStr);
}
// Если медиа-запрос
}else if(rule.type == 'media'){
var retnStr = getWebpRulesArr(rule.rules);
if (!!retn.media[rule.media]){
retn.media[rule.media] = retn.media[rule.media].concat(retnStr.webpArrStr);
}else{
retn.media[rule.media] = retnStr.webpArrStr;
}
if (!!retn.mediaOrig[rule.media]){
retn.mediaOrig[rule.media] = retn.mediaOrig[rule.media].concat(retnStr.originalArrStr);
}else{
retn.mediaOrig[rule.media] = retnStr.originalArrStr;
}
}
});
return retn;
}
// Получаем доп правила
var newrules = getWebpRulesArr(obj.stylesheet.rules);
// Собираем строку с webp
var newRulesStr = supportsRender(newrules.webpArrStr);
// Собираем строку с оригинальными картинками
var oldRulesStr = supportsRender(newrules.originalArrStr);
// Добавляем медиа-правила
for(k in newrules.media){
newRulesStr += "\n @media " + k + "{\n" + supportsRender(newrules.media[k]) + "}\n";
}
const data = oldRulesStr.concat(newRulesStr);
file.contents = new Buffer(data);
this.push(file);
} catch (err) {
this.emit('error', new PluginError(pluginName, err));
}
cb();
});
};