From 8a14419856c681b687be4d8db60f824d3836be54 Mon Sep 17 00:00:00 2001 From: Natalie Weizenbaum Date: Wed, 13 Jun 2018 12:54:26 -0700 Subject: [PATCH] Continue loading Node Sass by default This documents the option to use Dart Sass, and encourages users to explicitly choose their implementation, but it doesn't change the existing behavior. --- CHANGELOG.md | 4 - CONTRIBUTING.md | 9 +- README.md | 26 +++-- index.js | 283 ++++++++++++++++++++++++------------------------ package.json | 4 +- test/main.js | 2 +- 6 files changed, 160 insertions(+), 168 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce77cce..a71447c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,5 @@ # Gulp Sass Changelog -## v5.0.0 - -https://github.com/dlmanning/gulp-sass/releases/tag/v5.0.0 - ## v3.2.0 **March 11, 2018** diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 65fe483..b4649a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,10 @@ # Contributing to Gulp Sass -`gulp-sass` is a very light-weight wrapper around either [Dart Sass][] or [Node Sass][] (which in turn is a Node binding for [LibSass][]. All of these are implementations of the [Sass][] language. - -[Dart Sass]: http://sass-lang.com/dart-sass -[Node Sass]: https://github.com/sass/node-sass -[LibSass]: https://sass-lang.com/libsass -[Sass]: https://sass-lang.com +Gulp Sass is a very light-weight [Gulp](https://github.com/gulpjs/gulp) wrapper for [`node-sass`](https://github.com/sass/node-sass), which in turn is a Node binding for [`libsass`](https://github.com/sass/libsass), which in turn is a port of [`Sass`](https://github.com/sass/sass). ## Submitting Issues -* Before creating a new issue, perform a [cursory search](https://github.com/issues?utf8=%E2%9C%93&q=repo%3Adlmanning%2Fgulp-sass+repo%3Asass%2Fdart-sass+repo%3Asass%2Fnode-sass+repo%3Asass%2Flibsass+repo%3Asass%2Fsass+repo%3Asass-eyeglass%2Feyeglass) in the Gulp Sass, Dart Sass, Node Sass, Libsass, and main Sass repos to see if a similar issue has already been submitted. Please also refer to our [Common Issues and Their Fixes](https://github.com/dlmanning/gulp-sass/wiki/Common-Issues-and-Their-Fixes) page for some basic troubleshooting. +* Before creating a new issue, perform a [cursory search](https://github.com/issues?utf8=%E2%9C%93&q=repo%3Adlmanning%2Fgulp-sass+repo%3Asass%2Fnode-sass+repo%3Asass%2Flibsass+repo%3Asass%2Fsass+repo%3Asass-eyeglass%2Feyeglass) in the Gulp Sass, Node Sass, Libsass, and main Sass repos to see if a similar issue has already been submitted. Please also refer to our [Common Issues and Their Fixes](https://github.com/dlmanning/gulp-sass/wiki/Common-Issues-and-Their-Fixes) page for some basic troubleshooting. * You can create an issue [here](https://github.com/dlmanning/gulp-sass/issues). Please include as many details as possible in your report. * Issue titles should be descriptive, explaining at the high level what it is about. * Please include the version of `gulp-sass`, Node, and NPM you are using, as well as what operating system you are having a problem on. diff --git a/README.md b/README.md index 09157ac..c3cb8e1 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Only [Active LTS and Current releases][1] are supported. # Install ``` -npm install sass gulp-sass --save-dev +npm install node-sass gulp-sass --save-dev ``` # Basic Usage @@ -24,7 +24,9 @@ Something like this will compile your Sass files: 'use strict'; var gulp = require('gulp'); -var sass = require('gulp-sass')(require('sass')); +var sass = require('gulp-sass'); + +sass.compiler = require(node-sass'); gulp.task('sass', function () { return gulp.src('./sass/**/*.scss') @@ -43,7 +45,9 @@ You can also compile synchronously, doing something like this: 'use strict'; var gulp = require('gulp'); -var sass = require('gulp-sass')(require('sass')); +var sass = require('gulp-sass'); + +sass.compiler = require(node-sass'); gulp.task('sass', function () { return gulp.src('./sass/**/*.scss') @@ -56,6 +60,11 @@ gulp.task('sass:watch', function () { }); ``` +You can choose whether to use [Dart Sass][] or [Node Sass][] by setting the `sass.compiler` property. Node Sass will be used by default, but it's strongly recommended that you set it explicitly for forwards-compatibility in case the default ever changes. + +[Dart Sass]: http://sass-lang.com/dart-sass +[Node Sass]: https://github.com/sass/node-sass + Note that when using Dart Sass, **synchronous compilation is twice as fast as asynchronous compilation** by default, due to the overhead of asynchronous callbacks. To avoid this overhead, you can use the [`fibers`](https://www.npmjs.com/package/fibers) package to call asynchronous importers from the synchronous code path. To enable this, pass the `Fiber` class to the `fiber` option: ```javascript @@ -63,7 +72,9 @@ Note that when using Dart Sass, **synchronous compilation is twice as fast as as var Fiber = require('fibers'); var gulp = require('gulp'); -var sass = require('gulp-sass')(require('sass')); +var sass = require('gulp-sass'); + +sass.compiler = require('sass'); gulp.task('sass', function () { return gulp.src('./sass/**/*.scss') @@ -78,11 +89,6 @@ gulp.task('sass:watch', function () { ## Options -`gulp-sass` supports both [Dart Sass][] and [Node Sass][]. You choose which one to use by writing either `require('gulp-sass')(require('sass'))` for Dart Sass or `require('gulp-sass')(require('node-sass'))` for Node Sass. One or the other must be passed in. - -[Dart Sass]: http://sass-lang.com/dart-sass -[Node Sass]: https://github.com/sass/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. Except for the `data` option which is used by gulp-sass internally. Using the `file` option is also unsupported and results in undefined behaviour that may change without notice. For example: @@ -136,7 +142,7 @@ gulp.task('sass', function () { # Issues -`gulp-sass` is a very light-weight wrapper around either [Dart Sass][] or [Node Sass][] (which in turn is a Node binding for [LibSass][]. Because of this, the issue you're having likely isn't a `gulp-sass` issue, but an issue with one those projects or with [Sass][] as a whole. +`gulp-sass` is a very light-weight wrapper around either [Dart Sass][] or [Node Sass][] (which in turn is a Node binding for [LibSass][]). Because of this, the issue you're having likely isn't a `gulp-sass` issue, but an issue with one those projects or with [Sass][] as a whole. [LibSass]: https://sass-lang.com/libsass [Sass]: https://sass-lang.com diff --git a/index.js b/index.js index 08710dc..3b68d4a 100644 --- a/index.js +++ b/index.js @@ -9,161 +9,156 @@ const applySourceMap = require('vinyl-sourcemaps-apply'); const PLUGIN_NAME = 'gulp-sass'; -module.exports = (compiler) => { - if (!compiler || !compiler.render) { - throw new PluginError( - PLUGIN_NAME, - 'gulp-sass 5 requires you to pass in a Sass implementation. For example:\n\n' + - ' var sass = require(\'gulp-sass\')(require(\'node-sass\'));\n', - ); +////////////////////////////// +// Main Gulp Sass function +////////////////////////////// +const gulpSass = (options, sync) => through.obj((file, enc, cb) => { // eslint-disable-line consistent-return + if (file.isNull()) { + return cb(null, file); + } + + if (file.isStream()) { + return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported')); + } + + if (path.basename(file.path).indexOf('_') === 0) { + return cb(); + } + + if (!file.contents.length) { + file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign + return cb(null, file); + } + + const opts = clonedeep(options || {}); + opts.data = file.contents.toString(); + + // we set the file path here so that libsass can correctly resolve import paths + opts.file = file.path; + + // Ensure `indentedSyntax` is true if a `.sass` file + if (path.extname(file.path) === '.sass') { + opts.indentedSyntax = true; + } + + // Ensure file's parent directory in the include path + if (opts.includePaths) { + if (typeof opts.includePaths === 'string') { + opts.includePaths = [opts.includePaths]; + } + } else { + opts.includePaths = []; + } + + opts.includePaths.unshift(path.dirname(file.path)); + + // Generate Source Maps if plugin source-map present + if (file.sourceMap) { + opts.sourceMap = file.path; + opts.omitSourceMapUrl = true; + opts.sourceMapContents = true; } ////////////////////////////// - // Main Gulp Sass function + // Handles returning the file to the stream ////////////////////////////// - const gulpSass = (options, sync) => through.obj((file, enc, cb) => { // eslint-disable-line consistent-return - if (file.isNull()) { - return cb(null, file); - } + const filePush = (sassObj) => { + let sassMap; + let sassMapFile; + let sassFileSrc; + let sassFileSrcPath; + let sourceFileIndex; - if (file.isStream()) { - return cb(new PluginError(PLUGIN_NAME, 'Streaming not supported')); - } - - if (path.basename(file.path).indexOf('_') === 0) { - return cb(); - } - - if (!file.contents.length) { - file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign - return cb(null, file); - } - - const opts = clonedeep(options || {}); - opts.data = file.contents.toString(); - - // we set the file path here so that libsass can correctly resolve import paths - opts.file = file.path; - - // Ensure `indentedSyntax` is true if a `.sass` file - if (path.extname(file.path) === '.sass') { - opts.indentedSyntax = true; - } - - // Ensure file's parent directory in the include path - if (opts.includePaths) { - if (typeof opts.includePaths === 'string') { - opts.includePaths = [opts.includePaths]; - } - } else { - opts.includePaths = []; - } - - opts.includePaths.unshift(path.dirname(file.path)); - - // Generate Source Maps if plugin source-map present - if (file.sourceMap) { - opts.sourceMap = file.path; - opts.omitSourceMapUrl = true; - opts.sourceMapContents = true; - } - - ////////////////////////////// - // Handles returning the file to the stream - ////////////////////////////// - const filePush = (sassObj) => { - let sassMap; - let sassMapFile; - let sassFileSrc; - let sassFileSrcPath; - let sourceFileIndex; - - // Build Source Maps! - if (sassObj.map) { - // Transform map into JSON - sassMap = JSON.parse(sassObj.map.toString()); - // Grab the stdout and transform it into stdin - sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin'); - // Grab the base file name that's being worked on - sassFileSrc = file.relative; - // Grab the path portion of the file that's being worked on - sassFileSrcPath = path.dirname(sassFileSrc); - if (sassFileSrcPath) { - // Prepend the path to all files in the sources array except the file that's being worked on - sourceFileIndex = sassMap.sources.indexOf(sassMapFile); - sassMap.sources = sassMap.sources.map((source, index) => { // eslint-disable-line arrow-body-style - return index === sourceFileIndex ? source : path.join(sassFileSrcPath, source); - }); - } - - // Remove 'stdin' from souces and replace with filenames! - sassMap.sources = sassMap.sources.filter(src => src !== 'stdin' && src); - - // Replace the map file with the original file name (but new extension) - sassMap.file = replaceExtension(sassFileSrc, '.css'); - // Apply the map - applySourceMap(file, sassMap); + // Build Source Maps! + if (sassObj.map) { + // Transform map into JSON + sassMap = JSON.parse(sassObj.map.toString()); + // Grab the stdout and transform it into stdin + sassMapFile = sassMap.file.replace(/^stdout$/, 'stdin'); + // Grab the base file name that's being worked on + sassFileSrc = file.relative; + // Grab the path portion of the file that's being worked on + sassFileSrcPath = path.dirname(sassFileSrc); + if (sassFileSrcPath) { + // Prepend the path to all files in the sources array except the file that's being worked on + sourceFileIndex = sassMap.sources.indexOf(sassMapFile); + sassMap.sources = sassMap.sources.map((source, index) => { // eslint-disable-line arrow-body-style + return index === sourceFileIndex ? source : path.join(sassFileSrcPath, source); + }); } - file.contents = sassObj.css; // eslint-disable-line no-param-reassign - file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign + // Remove 'stdin' from souces and replace with filenames! + sassMap.sources = sassMap.sources.filter(src => src !== 'stdin' && src); - cb(null, file); - }; - - ////////////////////////////// - // Handles error message - ////////////////////////////// - const errorM = (error) => { - const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path; - const relativePath = path.relative(process.cwd(), filePath); - const message = [chalk.underline(relativePath), error.formatted].join('\n'); - - error.messageFormatted = message; // eslint-disable-line no-param-reassign - error.messageOriginal = error.message; // eslint-disable-line no-param-reassign - error.message = stripAnsi(message); // eslint-disable-line no-param-reassign - error.relativePath = relativePath; // eslint-disable-line no-param-reassign - - return cb(new PluginError(PLUGIN_NAME, error)); - }; - - if (sync !== true) { - ////////////////////////////// - // Async Sass render - ////////////////////////////// - const callback = (error, obj) => { // eslint-disable-line consistent-return - if (error) { - return errorM(error); - } - filePush(obj); - }; - - compiler.render(opts, callback); - } else { - ////////////////////////////// - // Sync Sass render - ////////////////////////////// - try { - filePush(compiler.renderSync(opts)); - } catch (error) { - return errorM(error); - } + // Replace the map file with the original file name (but new extension) + sassMap.file = replaceExtension(sassFileSrc, '.css'); + // Apply the map + applySourceMap(file, sassMap); } - }); - ////////////////////////////// - // Sync Sass render - ////////////////////////////// - gulpSass.sync = options => gulpSass(options, true); + file.contents = sassObj.css; // eslint-disable-line no-param-reassign + file.path = replaceExtension(file.path, '.css'); // eslint-disable-line no-param-reassign - ////////////////////////////// - // Log errors nicely - ////////////////////////////// - gulpSass.logError = function logError(error) { - const message = new PluginError('sass', error.messageFormatted).toString(); - process.stderr.write(`${message}\n`); - this.emit('end'); + cb(null, file); }; - return gulpSass; + ////////////////////////////// + // Handles error message + ////////////////////////////// + const errorM = (error) => { + const filePath = (error.file === 'stdin' ? file.path : error.file) || file.path; + const relativePath = path.relative(process.cwd(), filePath); + const message = [chalk.underline(relativePath), error.formatted].join('\n'); + + error.messageFormatted = message; // eslint-disable-line no-param-reassign + error.messageOriginal = error.message; // eslint-disable-line no-param-reassign + error.message = stripAnsi(message); // eslint-disable-line no-param-reassign + error.relativePath = relativePath; // eslint-disable-line no-param-reassign + + return cb(new PluginError(PLUGIN_NAME, error)); + }; + + if (sync !== true) { + ////////////////////////////// + // Async Sass render + ////////////////////////////// + const callback = (error, obj) => { // eslint-disable-line consistent-return + if (error) { + return errorM(error); + } + filePush(obj); + }; + + gulpSass.compiler.render(opts, callback); + } else { + ////////////////////////////// + // Sync Sass render + ////////////////////////////// + try { + filePush(gulpSass.compiler.renderSync(opts)); + } catch (error) { + return errorM(error); + } + } +}); + +////////////////////////////// +// Sync Sass render +////////////////////////////// +gulpSass.sync = options => gulpSass(options, true); + +////////////////////////////// +// Log errors nicely +////////////////////////////// +gulpSass.logError = function logError(error) { + const message = new PluginError('sass', error.messageFormatted).toString(); + process.stderr.write(`${message}\n`); + this.emit('end'); }; + +////////////////////////////// +// Store compiler in a prop +////////////////////////////// +gulpSass.compiler = require('node-sass'); + +module.exports = gulpSass; diff --git a/package.json b/package.json index ea68d6f..d56d7de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gulp-sass", - "version": "5.0.0", + "version": "4.0.2", "description": "Gulp plugin for sass", "main": "index.js", "engines": { @@ -26,6 +26,7 @@ "dependencies": { "chalk": "^2.3.0", "lodash.clonedeep": "^4.3.2", + "node-sass": "^4.8.3", "plugin-error": "^1.0.1", "replace-ext": "^1.0.0", "strip-ansi": "^4.0.0", @@ -43,7 +44,6 @@ "gulp-sourcemaps": "^2.6.4", "gulp-tap": "^0.1.3", "mocha": "^5.0.4", - "node-sass": "^4.8.3", "rimraf": "^2.4.3", "should": "^13.2.1", "vinyl": "^2.1.0" diff --git a/test/main.js b/test/main.js index 7ec2884..2ae56f0 100644 --- a/test/main.js +++ b/test/main.js @@ -2,7 +2,7 @@ const should = require('should'); const Vinyl = require('vinyl'); const path = require('path'); const fs = require('fs'); -const sass = require('../index')(require('node-sass')); +const sass = require('../index'); const rimraf = require('rimraf'); const gulp = require('gulp'); const sourcemaps = require('gulp-sourcemaps');