Merge pull request #224 from Snugug/2.x-sync

2.x sync
This commit is contained in:
David Manning 2015-03-30 15:15:42 -07:00
commit d59befea89
5 changed files with 220 additions and 33 deletions

View file

@ -1,6 +1,9 @@
# Gulp Sass Changelog # Gulp Sass Changelog
## v2.0.0-alpha.1 ## v2.0.0-alpha.1
### March 26, 2015
* **New** Added `renderSync` option that can be used through `sass.sync()`
### March 24, 2015 ### March 24, 2015
* **Change** Updated to `node-sass` 3.0.0-alpha.1 * **Change** Updated to `node-sass` 3.0.0-alpha.1
* **New** Added support for `gulp-sourcemaps` including tests * **New** Added support for `gulp-sourcemaps` including tests

View file

@ -10,11 +10,10 @@ npm install gulp-sass --save-dev
# Basic Usage # Basic Usage
Something like this: Something like this will compile your Sass files:
```javascript ```javascript
var gulp = require('gulp'); var gulp = require('gulp');
var gutil = require('gulp-util');
var sass = require('gulp-sass'); var sass = require('gulp-sass');
gulp.task('sass', function () { gulp.task('sass', function () {
@ -24,6 +23,19 @@ gulp.task('sass', function () {
}); });
``` ```
You can also compile synchronously, doing something like this:
```javascript
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('sass', function () {
gulp.src('./scss/*.scss')
.pipe(sass.sync().on('error', sass.logError))
.pipe(gulp.dest('./css'));
});
```
## Options ## Options
Pass in options just like you would for [`node-sass`](https://github.com/sass/node-sass#options); they will be passed along just as if you were using `node-sass`. Pass in options just like you would for [`node-sass`](https://github.com/sass/node-sass#options); they will be passed along just as if you were using `node-sass`.
@ -42,7 +54,7 @@ gulp.src('./scss/*.scss')
.pipe(gulp.dest('./css')); .pipe(gulp.dest('./css'));
``` ```
By default, [gulp-sourcemaps](https://github.com/floridoo/gulp-sourcemaps) writes the source maps inline in the compiled CSS files. To write them to a separate file, specify a relative file path in the `sourcemaps.write()` function. By default, [gulp-sourcemaps](https://github.com/floridoo/gulp-sourcemaps) writes the source maps inline in the compiled CSS files. To write them to a separate file, specify a path relative to the `gulp.dest()` destination in the `sourcemaps.write()` function.
```javascript ```javascript
var sourcemaps = require('gulp-sourcemaps'); var sourcemaps = require('gulp-sourcemaps');

View file

@ -1,3 +1,5 @@
'use strict';
var gutil = require('gulp-util'); var gutil = require('gulp-util');
var through = require('through2'); var through = require('through2');
var assign = require('object-assign'); var assign = require('object-assign');
@ -10,12 +12,13 @@ var PLUGIN_NAME = 'gulp-sass';
////////////////////////////// //////////////////////////////
// Main Gulp Sass function // Main Gulp Sass function
////////////////////////////// //////////////////////////////
var gulpSass = function gulpSass(options) { var gulpSass = function gulpSass(options, sync) {
'use strict';
return through.obj(function(file, enc, cb) { return through.obj(function(file, enc, cb) {
var opts, var opts,
callback; filePush,
errorM,
callback,
result;
if (file.isNull()) { if (file.isNull()) {
return cb(null, file); return cb(null, file);
@ -36,33 +39,77 @@ var gulpSass = function gulpSass(options) {
opts.omitSourceMapUrl = true; opts.omitSourceMapUrl = true;
} }
callback = function(error, obj) { //////////////////////////////
if (error) { // Handles returning the file to the stream
return cb(new gutil.PluginError( //////////////////////////////
PLUGIN_NAME, error.message + ' ' + gutil.colors.cyan('line ' + error.line) + ' in ' + gutil.colors.magenta(error.file) filePush = function filePush(sassObj) {
));
}
// Build Source Maps! // Build Source Maps!
if (obj.map) { if (sassObj.map) {
applySourceMap(file, JSON.parse(obj.map.toString())); applySourceMap(file, JSON.parse(sassObj.map.toString()));
} }
file.contents = obj.css; file.contents = sassObj.css;
file.path = gutil.replaceExtension(file.path, '.css'); file.path = gutil.replaceExtension(file.path, '.css');
cb(null, file); cb(null, file);
}; };
sass.render(opts, callback); //////////////////////////////
// Handles error message
//////////////////////////////
errorM = function errorM(error) {
var relativePath = path.relative(process.cwd(), error.file),
message = '';
message += gutil.colors.underline(relativePath) + '\n';
message += gutil.colors.gray(' ' + error.line + ':' + error.column) + ' ';
message += error.message;
return cb(new gutil.PluginError(
PLUGIN_NAME, message
));
};
if (sync !== true) {
//////////////////////////////
// Async Sass render
//////////////////////////////
callback = function(error, obj) {
if (error) {
return errorM(error);
}
filePush(obj);
};
sass.render(opts, callback);
}
else {
//////////////////////////////
// Sync Sass render
//////////////////////////////
try {
result = sass.renderSync(opts);
filePush(result);
}
catch(error) {
return errorM(error);
}
}
}); });
}; };
//////////////////////////////
// Sync Sass render
//////////////////////////////
gulpSass.sync = function sync(options) {
return gulpSass(options, true);
};
////////////////////////////// //////////////////////////////
// Log errors nicely // Log errors nicely
////////////////////////////// //////////////////////////////
gulpSass.logError = function logError(error) { gulpSass.logError = function logError(error) {
'use strict';
gutil.log(gutil.colors.red('[' + PLUGIN_NAME + '] ') + error.message); gutil.log(gutil.colors.red('[' + PLUGIN_NAME + '] ') + error.message);
}; };

View file

@ -10,11 +10,6 @@ var report;
describe('code style guide', function() { describe('code style guide', function() {
it('index.js should follow our lint style guide', function(done) { it('index.js should follow our lint style guide', function(done) {
cli = new eslint.CLIEngine({
'rules': {
'strict': [ 2, 'function' ]
}
});
report = cli.executeOnFiles(['index.js']); report = cli.executeOnFiles(['index.js']);
if (report.errorCount > 0 || report.warningCount > 0) { if (report.errorCount > 0 || report.warningCount > 0) {
console.log(formatter(report.results)); console.log(formatter(report.results));
@ -26,11 +21,6 @@ describe('code style guide', function() {
}); });
it('test/main.js should follow our lint style guide', function(done) { it('test/main.js should follow our lint style guide', function(done) {
cli = new eslint.CLIEngine({
'rules': {
'strict': [ 2, 'global' ]
}
});
report = cli.executeOnFiles(['test/main.js']); report = cli.executeOnFiles(['test/main.js']);
if (report.errorCount > 0 || report.warningCount > 0) { if (report.errorCount > 0 || report.warningCount > 0) {
console.log(formatter(report.results)); console.log(formatter(report.results));
@ -44,8 +34,7 @@ describe('code style guide', function() {
it('test/lint.js should follow our lint style guide', function(done) { it('test/lint.js should follow our lint style guide', function(done) {
cli = new eslint.CLIEngine({ cli = new eslint.CLIEngine({
'rules': { 'rules': {
'no-console': 0, 'no-console': 0
'strict': [ 2, 'global' ]
} }
}); });
report = cli.executeOnFiles(['test/lint.js']); report = cli.executeOnFiles(['test/lint.js']);

View file

@ -19,7 +19,7 @@ var createVinyl = function createVinyl(filename, contents) {
}); });
}; };
describe('gulp-sass', function() { describe('gulp-sass -- async compile', function() {
it('should pass file when it isNull()', function(done) { it('should pass file when it isNull()', function(done) {
var stream = sass(); var stream = sass();
var emptyFile = { var emptyFile = {
@ -119,7 +119,7 @@ describe('gulp-sass', function() {
var stream = sass(); var stream = sass();
stream.on('error', function(err) { stream.on('error', function(err) {
err.message.indexOf('property "font" must be followed by a \':\'').should.equal(0); err.message.indexOf('property "font" must be followed by a \':\'').should.not.equal(-1);
done(); done();
}); });
stream.write(errorFile); stream.write(errorFile);
@ -154,3 +154,139 @@ describe('gulp-sass', function() {
stream.write(sassFile); stream.write(sassFile);
}); });
}); });
describe('gulp-sass -- sync compile', function() {
it('should pass file when it isNull()', function(done) {
var stream = sass.sync();
var emptyFile = {
'isNull': function () {
return true;
}
};
stream.on('data', function(data) {
data.should.equal(emptyFile);
done();
});
stream.write(emptyFile);
});
it('should emit error when file isStream()', function (done) {
var stream = sass.sync();
var streamFile = {
'isNull': function () {
return false;
},
'isStream': function () {
return true;
}
};
stream.on('error', function(err) {
err.message.should.equal('Streaming not supported');
done();
});
stream.write(streamFile);
});
it('should compile a single sass file', function(done) {
var sassFile = createVinyl('mixins.scss');
var stream = sass.sync();
stream.on('data', function(cssFile) {
should.exist(cssFile);
should.exist(cssFile.path);
should.exist(cssFile.relative);
should.exist(cssFile.contents);
String(cssFile.contents).should.equal(
fs.readFileSync(path.join(__dirname, 'expected/mixins.css'), 'utf8')
);
done();
});
stream.write(sassFile);
});
it('should compile multiple sass files', function(done) {
var files = [
createVinyl('mixins.scss'),
createVinyl('variables.scss')
];
var stream = sass.sync();
var mustSee = files.length;
var expectedPath = 'expected/mixins.css';
stream.on('data', function(cssFile) {
should.exist(cssFile);
should.exist(cssFile.path);
should.exist(cssFile.relative);
should.exist(cssFile.contents);
if (cssFile.path.indexOf('variables') !== -1) {
expectedPath = 'expected/variables.css';
}
String(cssFile.contents).should.equal(
fs.readFileSync(path.join(__dirname, expectedPath), 'utf8')
);
mustSee--;
if (mustSee <= 0) {
done();
}
});
files.forEach(function (file) {
stream.write(file);
});
});
it('should compile files with partials in another folder', function(done) {
var sassFile = createVinyl('inheritance.scss');
var stream = sass.sync();
stream.on('data', function(cssFile) {
should.exist(cssFile);
should.exist(cssFile.path);
should.exist(cssFile.relative);
should.exist(cssFile.contents);
String(cssFile.contents).should.equal(
fs.readFileSync(path.join(__dirname, 'expected/inheritance.css'), 'utf8')
);
done();
});
stream.write(sassFile);
});
it('should handle sass errors', function(done) {
var errorFile = createVinyl('error.scss');
var stream = sass.sync();
stream.on('error', function(err) {
err.message.indexOf('property "font" must be followed by a \':\'').should.not.equal(-1);
done();
});
stream.write(errorFile);
});
it('should work with gulp-sourcemaps', function(done) {
var sassFile = createVinyl('inheritance.scss');
// Expected sources are relative to file.base
var expectedSources = [
'includes/_cats.scss',
'inheritance.scss'
];
var stream;
sassFile.sourceMap = '{' +
'"version": 3,' +
'"file": "scss/subdir/multilevelimport.scss",' +
'"names": [],' +
'"mappings": "",' +
'"sources": [ "scss/subdir/multilevelimport.scss" ],' +
'"sourcesContent": [ "@import ../inheritance;" ]' +
'}';
stream = sass.sync();
stream.on('data', function(cssFile) {
should.exist(cssFile.sourceMap);
assert.deepEqual(cssFile.sourceMap.sources, expectedSources);
done();
});
stream.write(sassFile);
});
});