Skip to content

Commit

Permalink
merge removeUnusedStyles plugin with minifyStyles
Browse files Browse the repository at this point in the history
  • Loading branch information
lahmatiy committed Jan 12, 2017
1 parent fd5a8ca commit da6a40d
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 157 deletions.
158 changes: 130 additions & 28 deletions plugins/minifyStyles.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,147 @@
'use strict';

exports.type = 'perItem';
exports.type = 'full';

exports.active = true;

exports.description = 'minifies styles and removes unused styles based on usage data';

exports.params = {
svgo: {}
};
// ... CSSO options goes here
svgo: {},

exports.description = 'minifies existing styles in svg';
// additional
usage: {
ids: true,
classes: true,
tags: true
}
};

var csso = require('csso');

/**
* Minifies styles (<style> element + style attribute) using svgo
*
* @param {Object} item current iteration item
* @return {Boolean} if false, item will be filtered out
* Minifies styles (<style> element + style attribute) using CSSO
*
* @author strarsis <[email protected]>
*/
exports.fn = function(item, svgoOptions) {

if(item.elem) {
if(item.isElem('style') && !item.isEmpty()) {
var styleCss = item.content[0].text || item.content[0].cdata || [],
DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text';
if(styleCss.length > 0) {
var styleCssMinified = csso.minify(styleCss, svgoOptions);
item.content[0][DATA] = styleCssMinified.css;
exports.fn = function(ast, options) {
options = options || {};

var minifyOptionsForStylesheet = cloneObject(options);
var minifyOptionsForAttribute = cloneObject(options);
var elems = findStyleElems(ast);

minifyOptionsForStylesheet.usage = collectUsageData(ast, options);
minifyOptionsForAttribute.usage = null;

elems.forEach(function(elem) {
if (elem.isElem('style')) {
// <style> element
var styleCss = elem.content[0].text || elem.content[0].cdata || [];
var DATA = styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0 ? 'cdata' : 'text';

elem.content[0][DATA] = csso.minify(styleCss, minifyOptionsForStylesheet).css;
} else {
// style attribute
var elemStyle = elem.attr('style').value;

elem.attr('style').value = csso.minifyBlock(elemStyle, minifyOptionsForAttribute).css;
}
});

return ast;
};

function cloneObject(obj) {
var result = {};

for (var key in obj) {
result[key] = obj[key];
}

return result;
}

function findStyleElems(ast) {

function walk(items, styles) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];

// go deeper
if (item.content) {
walk(item, styles);
}
}

if(item.hasAttr('style')) {
var itemCss = item.attr('style').value;
if(itemCss.length > 0) {
var itemCssMinified = csso.minifyBlock(itemCss, svgoOptions);
item.attr('style').value = itemCssMinified.css;
}
}

if (item.isElem('style') && !item.isEmpty()) {
styles.push(item);
} else if (item.isElem() && item.hasAttr('style')) {
styles.push(item);
}
}

return styles;
}

return item;
};
return walk(ast, []);
}

function shouldFilter(options, name) {
if ('usage' in options === false) {
return true;
}

if (options.usage && name in options.usage === false) {
return true;
}

return Boolean(options.usage && options.usage[name]);
}

function collectUsageData(ast, options) {

function walk(items, usageData) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];

// go deeper
if (item.content) {
walk(item, usageData);
}

if (item.isElem()) {
usageData.tags[item.elem] = true;

if (item.hasAttr('id')) {
usageData.ids[item.attr('id').value] = true;
}

if (item.hasAttr('class')) {
item.attr('class').value.replace(/^\s+|\s+$/g, '').split(/\s+/).forEach(function(className) {
usageData.classes[className] = true;
});
}
}
}

return usageData;
}

var hasData = false;
var usageData = walk(ast, {
ids: Object.create(null),
classes: Object.create(null),
tags: Object.create(null)
});

for (var key in usageData) {
usageData[key] = shouldFilter(options, key) && Object.keys(usageData[key]);

if (usageData[key]) {
hasData = true;
}
}

return hasData ? usageData : null;
}
121 changes: 0 additions & 121 deletions plugins/removeUnusedStyles.js

This file was deleted.

4 changes: 2 additions & 2 deletions test/plugins/minifyStyles.01.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions test/plugins/minifyStyles.02.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions test/plugins/minifyStyles.03.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit da6a40d

Please sign in to comment.