Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Synchronous less compiling in NodeJS

I'm trying to write a transform script for Browserify that allows me to require() .less files. The transformation will compile them to CSS and then wrap that minified CSS in a little Javascript function that appends the CSS to the page.

My trouble is that the main LESS module is asynchronous, which doesn't appear to work alongside a transformation script:

lessify/index.js (Modeled directly from node-underscorify)

var less = require('less');
var cleanCSS = require('clean-css');
var through = require('through');

module.exports = function(file) {
    if (!/\.css|\.less/.test(file)) {
        return through();
    }
    var buffer = "";

    return through(function(chunk) {
        return buffer += chunk.toString();
    }, function() {
        compiled = buffer;
        if (/\.less/.test(file)) {
            compiled = less.render(compiled, function(e, r) { return r; });
        }
        // rv comments
        compiled = compiled.replace(/\/\*.*?\*\//g, "");

        // minify. TO DO: Get less.js to do this for us
        var compiled = cleanCSS.process(buffer);

        compiled = "(function($) { $('head').append('<style type=\"text/css\">" + compiled.replace(/'/g, "\\'") + "</style>');}(window.jQuery));";
        this.queue(compiled);
        return this.queue(null);
    });
};

This works just fine for .css file, but breaks on .less files since compiled is undefined.

There are several completed pull requests in the less.js source related to this, but none seem to work for me.

I'm not terribly familiar with the through library, so perhaps its behavior can easily be adjusted to asynchronous functions? I realize it makes sense for less.render() to be async by default to handle @import, and don't mind forgoing imports in order to be able to directly require() LESS on my pages.

like image 878
Chris Wilson Avatar asked Nov 13 '13 14:11

Chris Wilson


1 Answers

This actually works if slightly modified. I was being stupid above with running cleanCSS on buffer, not compiled

var less = require('less');
var cleanCSS = require('clean-css');
var through = require('through');

var parser = new(less.Parser)({
    processImports: false
});

module.exports = function(file) {
    if (!/\.css|\.less/.test(file)) {
        return through();
    }
    var buffer = "";

    return through(function(chunk) {
        return buffer += chunk.toString();
    }, function() {
        var compiled;
        // CSS is LESS so no need to check extension
        parser.parse(buffer, function(e, r) { 
            compiled = r.toCSS();
        });

        // rv comments
        compiled = compiled.replace(/\/\*.*?\*\//g, "");

        var compiled = cleanCSS.process(compiled);

        compiled = "(function($) { $('head').append('<style type=\"text/css\">" + compiled.replace(/'/g, "\\'") + "</style>');}(window.jQuery));";
        this.queue(compiled);
        return this.queue(null);
    });
};
like image 163
Chris Wilson Avatar answered Oct 16 '22 05:10

Chris Wilson