skip to Main Content

Function is question is from postcss-discard-duplicates plugin. Here is code in index.js:

'use strict';

var postcss = require('postcss');

function dedupe (node) {
    if (node.nodes) { node.each(dedupe); }

    if (node.type === 'comment') { return; }

    var nodes = node.parent.nodes.filter(function (n) {
        return String(n) === String(node);
    });

    nodes.forEach(function (n, i) {
        if (i !== nodes.length - 1) {
            n.removeSelf();
        }
    });
}

module.exports = postcss.plugin('postcss-discard-duplicates', function () {
    return function (css) {
        css.each(dedupe);
    };
});

Plugin uses PostCSS API which returns CSS node tree. Full API is well documented here.

At the moment I have large CSS file build on top of Twitter Bootstrap with lots of complex selectors. CSS takes ~37 sec. to compile if using this function to find and remove any duplicate rules. Without it, it’s ~3 sec.

I’m looking for help optimizing this function for better performance.

UPDATE: I posted answer that copied improvements made by function author. It reduces compile time for more than 50%.

2

Answers


  1. Chosen as BEST ANSWER

    I reported this issue to repo owner and he made some significant performance improvements. My compile time is now ~13.5 sec. (by adding microoptimizations mentioned in question comment I also managed to shave off aditional second)

    This is improved code:

    'use strict';
    
    var postcss = require('postcss');
    
    function dedupe (node, index) {
        if (node.type === 'comment') { return; }
        if (node.nodes) { node.each(dedupe); }
    
        var toString = node.toString();
        var nodes = node.parent.nodes;
        var result = [node];
        var i = index + 1;
        var max = nodes.length;
    
        for (; i < max; i++) {
            if (nodes[i].toString() === toString) {
                result.push(nodes[i]);
            }
        }
    
        for (var x = 0; x < result.length; x++) {
            if (x !== result.length - 1) {
                result[x].remove();
            }
        }
    
    }
    
    module.exports = postcss.plugin('postcss-discard-duplicates', function () {
        return function (css) {
            css.each(dedupe);
        };
    });
    

  2. I’m not sure that it’s easy to find optimisation directly in this function, seems like it’s task for profession optimisations with building helping structures like binary tree and so on. It’s not easy question, problem in the algorithm, not in the implementation.
    If you just want to optimize code – try to merge filter and forEach. At least, it will help to avoid double iterating.

    var last = null;
    var nodes = node.parent.nodes.forEach(function(n){
        if (String(n) === String(node)) {
            if (last) {
                last.removeSelf();
            }
            last = n;
        }
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search