Gulp-sass: Watch/recompile only changed sass/scss files

Created on 2 Mar 2016  路  9Comments  路  Source: dlmanning/gulp-sass

Hi,
This question might be already answered, but i couldn't find the answer.
Recently I switch from Compass SASS to Gulp-sass.
So, is it possible with the Watcher to recompile only changed SCSS files?
I have huge amount of SCSS files (~60) so it takes around 7-8sec every time I change ONE file.
Here is my task and watcher

sassSources = ['../sass/**/*.scss'];

gulp.task('sass', function() {
    return gulp.src(sassSources)
        .pipe(plumber())
        .pipe(sourcemaps.init())
        .pipe(sass())
        .pipe(autoprefixer())
        .pipe(sourcemaps.write('./maps'))
        .pipe(gulp.dest('resources/css'));
});

gulp.task('watch', function() {
    gulp.watch(sassSources, ['sass'])
    .on('change', function(event) {
        console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
    });
});

Any help is appreciated !

Thanks !

Most helpful comment

I found a solution. You need to install the following:
gulp-sass-grapher
path
gulp-watch

And this is the working task:

gulp.task('watch-sass', function() {
    var loadPaths = path.resolve('../sass/');
    sassGrapher.init('../sass/', { loadPaths: loadPaths });
    return watch('../sass/**/*.scss', { base: path.resolve('../sass/') })
      .pipe(sassGrapher.ancestors())
      .pipe(sass({
        includePath: loadPaths
      }))
      .pipe(autoprefixer(autoprefix))
      .pipe(gulp.dest('./resources/css'));
  });

Good luck !

All 9 comments

This would be great! node-sass does support sass' selective watch-recompile.

I found a solution. You need to install the following:
gulp-sass-grapher
path
gulp-watch

And this is the working task:

gulp.task('watch-sass', function() {
    var loadPaths = path.resolve('../sass/');
    sassGrapher.init('../sass/', { loadPaths: loadPaths });
    return watch('../sass/**/*.scss', { base: path.resolve('../sass/') })
      .pipe(sassGrapher.ancestors())
      .pipe(sass({
        includePath: loadPaths
      }))
      .pipe(autoprefixer(autoprefix))
      .pipe(gulp.dest('./resources/css'));
  });

Good luck !

Haha wow, that'll do it too, thanks :)

It would be nice to have this as a gulp-sass one-step option!

Might be a bit late but the issue is still open. these references might be worth checking out, as listed on gulps repo page. I have good experiences with gulp-changed in different setups than sass, might try the others soon.

Gulp watcher is owned by gulp. We have no power over it so there is nothing we can do here.

gulp-sass-grapher was something I previously worked on to help with this. I'm not sure if it still works as intended.

I guess we could possibly offer some documentation on how to do this, however I believe gulp-sass-grapher is the only plugin that is aware of the import grapher. At the moment it doesn't with the indented syntax.

It would be great to have some kind of a reliable solution for this.

@venelinn's solution works for me in that it only watches the changed sass files. However it doesn't make the processing time faster. Its slower than the gulp-sass module which i was hoping to get better load times from.

Closing as this is out of scope for gulp-sass.

Translation into English via Google, if something kicks him))

It turned out that only the modified file was compiled!

The output is:
file.scss
聽- file.css
聽- file.min.css
聽- file.min.css.map

It did not work either to beat Watcher, that he would immediately create the file after the "oneSassFileCompile" function was launched, the files were created only after the Watcher stop.

Exit the situation - launch the assistant task.
But again did not find how to transfer parameters.
I had to resort to an external variable, I hope it does not work out that many files changed immediately and this variable did not manage to skip all the files.

Sorry for my english.
And for my script too, the first time I write to NodeJS and the first time I ran into Gulp!

If it turns out to throw a parameter directly into the subtask, or even better to force the files to be created immediately when the function is called in Watcher, I will be very glad to see the solution!

tags: gulp sass watch only one file change and compile css autoprefixer minify and map

gulpfile.js code:

// Variables 
var gulp        = require('gulp'),
    argv        = require('yargs').argv,
    sass        = require('gulp-sass'),
    rename      = require('gulp-rename'),
    //cssmin      = require('gulp-cssnano'), - a very long initialization, because of what is not convenient for a constant launch, but on the watcher will probably rise norms
    cleanCSS    = require('gulp-clean-css'),
    prefix      = require('gulp-autoprefixer'),
    plumber     = require('gulp-plumber'),
    notify      = require('gulp-notify'),
    sassLint    = require('gulp-sass-lint'),
    sourcemaps  = require('gulp-sourcemaps');

// Temporary solution until gulp 4
// https://github.com/gulpjs/gulp/issues/355
var runSequence = require('run-sequence');

// Settings
var sassProjectPath = 'templates/**/*.scss';
var sassOptions     = {
    outputStyle: 'expanded'
};
var prefixerOptions = {
    browsers: ['last 5 versions'],
    cascade: true
};


// Secondary functions
var displayError = function(error) {
    // Initial building up of the error
    var errorString = '[' + error.plugin.error.bold + ']';
    errorString += ' ' + error.message.replace("\n",''); // Removes new line at the end

    // If the error contains the filename or line number add it to the string
    if(error.fileName)
        errorString += ' in ' + error.fileName;

    if(error.lineNumber)
        errorString += ' on line ' + error.lineNumber.bold;

    // This will output an error like the following:
    // [gulp-sass] error message in file_name on line 1
    console.error(errorString);
};
var onError      = function(err) {
    notify.onError({
        title:    "Gulp",
        subtitle: "Failure!",
        message:  "Error: <%= error.message %>",
        sound:    "Basso"
    })(err);
    this.emit('end');
};


// BUILD SUB-TASKS
// ---------------


// Compiling a single single SASS file
var oneSassFileCompile = function(filePath, destinationDir){
    var fullFileName, fileName, baseDir;

    // Checking the parameters
    if(!filePath) {
        console.log('param filePath miss');
        return false;
    }

    // Find file paths
    fullFileName    = filePath.replace(/\\/g,'/').replace(/.*\//, '');
    fileName        = fullFileName.replace('.'+ fullFileName.split('.').pop(), '');
    baseDir         = filePath.replace(fullFileName, '');

    // If you do not specify a folder to save, use the current
    destinationDir         = destinationDir || baseDir;

    // Compile
    return gulp.src(filePath)
        // Error Handler
        .pipe(plumber({errorHandler: onError}))
        // For generic style.css.map
        .pipe(sourcemaps.init())
        // The actual compilation
        .pipe(sass(sassOptions))
        // Adding Manufacturer Prefixes
        .pipe(prefix(prefixerOptions))
        // Call the file
        .pipe(rename(fileName +'.css'))
        // Save the compiled version
        .pipe(gulp.dest(destinationDir))

        // Compress CSS
        //.pipe(cssmin())
        .pipe(cleanCSS())
        // Rename the suffix
        .pipe(rename({suffix: '.min'}))
        // Save the .map
        .pipe(sourcemaps.write('./'))
        // Save the compressed file
        .pipe(gulp.dest(destinationDir));
};

// Task to start compiling a specific file
// For PHPStorm File Watcher
gulp.task('sass-file', function() {
    var filePath        = argv.filePath,
        destinationDir  = argv.destDir;

    // Checking the parameters
    if(!filePath) {
        console.log('argv --filePath miss');
        return false;
    }
    return oneSassFileCompile(filePath, destinationDir)
});


// Compiling all SASS project files
// TODO - customize the paths and check
gulp.task('sass-project', function() {
    return gulp.src(sassProjectPath)
        .pipe(plumber({errorHandler: onError}))
        .pipe(sourcemaps.init())
        .pipe(sass(sassOptions))
        .pipe(prefix(prefixerOptions))
        .pipe(rename(fileName +'.css'))
        .pipe(gulp.dest('./'))

        // Compress CSS
        //.pipe(cssmin())
        .pipe(cleanCSS())
        .pipe(rename({suffix: '.min'}))
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest('./'));
});


// Task checks the SASS project files
// TODO - customize the paths and check
gulp.task('sass-lint', function() {
    gulp.src(sassProjectPath)
        .pipe(sassLint())
        .pipe(sassLint.format())
        .pipe(sassLint.failOnError());
});


// Watcher for all SASS project files
// An auxiliary variable to transfer the file path from the watcher to the task
var sassWatchFilePath = '';
gulp.task('sass-watch', function() {
    gulp.watch(sassProjectPath, function(watchEvent){
        console.log('Watcher catch: '+ watchEvent.type +' :: '+ watchEvent.path);

        // Skip deleting
        if(watchEvent.type === 'deleted')
            return;

        // We set the variable with the path and start the helper
        sassWatchFilePath = watchEvent.path;
        gulp.start('sass-watch-helper');
    });
});
//Taks helper, if you immediately call "oneSassFileCompile" in sass-watch,
// then the files are not created until the process ends. watcher = (
gulp.task('sass-watch-helper', function() {
    var tmpPath = sassWatchFilePath;
    sassWatchFilePath = null;
    // Compilation
    return oneSassFileCompile(tmpPath);
});


// BUILD TASKS
// ------------


// Default task
gulp.task('default', function(done) {
    runSequence('sass-project', 'sass-watch', done);
});

// Project Collector
gulp.task('build', function(done) {
    runSequence('sass-project', done);
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

JamesVanWaza picture JamesVanWaza  路  4Comments

cmegown picture cmegown  路  6Comments

seeliang picture seeliang  路  4Comments

mrgnou picture mrgnou  路  6Comments

EpicOkapi picture EpicOkapi  路  5Comments