Skip to content
This repository has been archived by the owner on Feb 9, 2023. It is now read-only.

Commit

Permalink
Eliminate ruby dependency. Closes gh-23.
Browse files Browse the repository at this point in the history
The plugin now uses libsass library for fast node.js compilation.

If compiled file uses compass or it is in .sass format, the plugin
will fallback to ruby compilation.

Ruby compilation can be forced in config.
  • Loading branch information
paulmillr committed Dec 18, 2013
1 parent 2cac26d commit 3458041
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 237 deletions.
147 changes: 147 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
var cp = require('child_process'), spawn = cp.spawn, exec = cp.exec;
var sysPath = require('path');
var progeny = require('progeny');
var libsass = require('node-sass');
var Promise = require('promise');
var os = require('os');

var isWindows = os.platform() === 'win32';
var compassRe = /compass/;
var sassRe = /\.sass$/;

var extend = function(object, source) {
for (var key in source) object[key] = source[key];
return object;
};

function SassCompiler(cfg) {
if (cfg == null) cfg = {};
this.rootPath = cfg.paths.root;
this.optimize = cfg.optimize;
this.config = (cfg.plugins && cfg.plugins.sass) || {};
this.mode = this.config.mode;
this.getDependencies = progeny({
rootPath: this.rootPath
});
this.gem_home = this.config.gem_home;
this.env = {};
if (this.gem_home) {
var env = extend({}, process.env);
env.GEM_HOME = this.gem_home;
this.env = {
env: env
};
this._bin = "" + this.gem_home + "/bin/sass";
this._compass_bin = "" + this.gem_home + "/bin/compass";
}
this.bundler = this.config.useBundler;
this.prefix = this.bundler ? 'bundle exec ' : '';
}

SassCompiler.prototype.brunchPlugin = true;
SassCompiler.prototype.type = 'stylesheet';
SassCompiler.prototype.extension = 'scss';
SassCompiler.prototype.pattern = /\.s[ac]ss$/;
SassCompiler.prototype._bin = isWindows ? 'sass.bat' : 'sass';
SassCompiler.prototype._compass_bin = 'compass';

SassCompiler.prototype._checkRuby = function() {
var prefix = this.prefix;
var env = this.env;
var sassCmd = "" + this.prefix + this._bin + " --version";
var compassCmd = "" + this.prefix + this._compass_bin + " --version";

var sassPromise = new Promise(function(resolve, reject) {
exec(sassCmd, env, function(error) {
if (error) {
console.error("You need to have Sass on your system");
console.error("Execute `gem install sass`");
reject();
} else {
resolve();
}
});
});
var compassPromise = new Promise((function(resolve, reject) {
exec(compassCmd, env, (function(error) {
this.compass = !error;
resolve();
}).bind(this));
}).bind(this));
this.rubyPromise = Promise.all([sassPromise, compassPromise]);
};

SassCompiler.prototype._nativeCompile = function(data, path, callback) {
libsass.render({
data: data,
success: (function(css) {
callback(null, css);
}),
error: (function(error) {
callback(error);
}),
includePaths: [this.rootPath, sysPath.dirname(path)],
outputStyle: 'nested',
sourceComments: !this.optimize
});
};

SassCompiler.prototype._rubyCompile = function(data, path, callback) {
if (this.rubyPromise == null) this._checkRuby();
var result = '';
var error = null;
var cmd = [
'sass',
'--stdin',
'--load-path', this.rootPath,
'--load-path', sysPath.dirname(path),
'--no-cache'
];
if (this.bundler) cmd.unshift('bundle', 'exec');

var debugMode = this.config.debug, hasComments;
if ((debugMode === 'comments' || debugMode === 'debug') && !this.optimize) {
hasComments = this.config.debug === 'comments';
cmd.push(hasComments ? '--line-comments' : '--debug-info');
}

if (!sassRe.test(path)) cmd.push('--scss');
if (this.compass) cmd.push('--compass');
if (this.config.options != null) cmd.push.apply(cmd, this.config.options);

this.rubyPromise.then((function() {
if (isWindows) {
cmd = ['cmd', '/c', '"' + cmd[0] + '"'].concat(cmd.slice(1));
this.env.windowsVerbatimArguments = true;
}
var sass = spawn(cmd[0], cmd.slice(1), this.env);
sass.stdout.on('data', function(buffer) {
result += buffer.toString();
});
sass.stderr.on('data', function(buffer) {
if (error == null) error = '';
error += buffer.toString();
});
sass.on('close', function(code) {
callback(error, result);
});
if (sass.stdin.write(data)) {
sass.stdin.end();
} else {
sass.stdin.on('drain', function() {
sass.stdin.end();
});
}
}).bind(this));
};

SassCompiler.prototype.compile = function(data, path, callback) {
var fileUsesRuby = sassRe.test(path) || compassRe.test(data);

This comment has been minimized.

Copy link
@es128

es128 Dec 18, 2013

Member

What if a dependency includes compass?

This comment has been minimized.

Copy link
@paulmillr

paulmillr Dec 18, 2013

Author Contributor

it won't work, yes

This comment has been minimized.

Copy link
@es128

es128 Dec 18, 2013

Member

I guess it's a simple enough fix for now, just @include "compass"; in the parent. We can add some smarts to make this happen automatically later.

if (this.mode === 'ruby' || (!this.mode && fileUsesRuby)) {
this._rubyCompile(data, path, callback);
} else {
this._nativeCompile(data, path, callback);
}
};

module.exports = SassCompiler;
138 changes: 0 additions & 138 deletions lib/index.js

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
"description": "Adds Sass support to brunch.",
"author": "Paul Miller (http://paulmillr.com/)",
"homepage": "https://github.com/brunch/sass-brunch",
"keywords": ["brunchplugin", "sass"],
"repository": {
"type": "git",
"url": "git@github.com:brunch/sass-brunch.git"
},
"main": "./lib/index",
"scripts": {
"prepublish": "rm -rf lib && coffee --bare --output lib/ src/",
"test": "node_modules/.bin/mocha --require test/common.js"
"test": "node_modules/.bin/mocha"
},
"dependencies": {
"progeny": "~0.1.1"
Expand Down
89 changes: 0 additions & 89 deletions src/index.coffee

This file was deleted.

Loading

3 comments on commit 3458041

@vendethiel
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why swap back to js ?

@paulmillr
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tired of additional coffee work on nodejs

@vendethiel
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's your tools' job

Please sign in to comment.