Search code examples
javascriptsassgulp

Pass parameter to Gulp task in gulpfile.js (not command-line)


EDIT: As I wrote IN THE TITLE AND FROM THE BEGINNING, this is not about command-line parameters and is thus NOT A DUPLICATE. //EDIT

I have a Sass setup with an indefinite number of uniquely-designed pages (page_1, page_2, etc), each having their own sass/pages/page_1/page_1.scss file.

The pages all belong to the same website, and each page's sass file @imports the same set of files from a sass/includes folder.

With a basic gulp task watching sass/**/*, every page's styles get compiled anytime I make a change to any page's styles. Obviously this doesn't scale well.

I tried using gulp-watch, but it doesn't catch if changes are made to one of the included .scss files. It only catches changes made to the files that actually get compiled into an equivalent .css.

For the purposes of having my gulpfile be as DRY as possible, the best solution I could come up with was to maintain a basic array of folder names in gulpfile.js, and to loop through and watch each of them separately, using the same sass-compiling task for each folder.

var pageFolderNames = [
    'page_1',
    'page_2'
    // etc
];

Then for the gulp task, I have:

gulp.task('watch_pages', function()
{    
  // Get array length
  var numPages = pageFolderNames.length;

  // Add a new watch task for each individual page
  for (var i = 0; i < numPages; i++)
  {
    gulp.watch('sass/pages/' + pageFolderNames[i] + '/**/*.scss', ['sass_page']);
  }
});

The (simplified) task that compiles sass:

// Task: Compile page-specific Sass
gulp.task('sass_page', function()
{
  return gulp.src('sass/pages/' + pageFolderNames[i] +'/**/*.scss')
    .pipe(plumber(plumberErrorHandler))
    .pipe(sass(...))
    .pipe(gulp.dest('css/pages/' + pageFolderNames[i]));
});

This approach (I know my JS-fu is weaksauce) results in an error:

'sass_page' errored after 71 μs
ReferenceError: i is not defined

Is there any way to pass parameters, such as i, to gulp tasks to get this working? Alternately, is there a better way to accomplish what I'm trying to do? I have a sneaking suspicion there is. :-/


Solution

  • I found out there is an on change event for gulp watch. So this might be what you're looking for:

    var pagesDir = 'sass/pages/';
    
    gulp.task('watch_pages', function() {
        gulp.watch(pagesDir + '**/*')
            .on("change", function(file) {
                // absolute path to folder that needs watching
                var changedDest = path.join(__dirname, pagesDir);
                // relative path to changed file
                var changedFile = path.relative(changedDest, file.path);
                // split the relative path, get the specific folder with changes
                var pageFolder  = changedFile.split('\\')[0];
    
                gulp.src(path.join(pagesDir, pageFolder) +'/**/*.scss')
                  .pipe(plumber(plumberErrorHandler))
                  .pipe(sass(...))
                  .pipe(gulp.dest('css/pages/' + pageFolder));
    
                console.log(changedDest);
                console.log(changedFile);
                console.log(pageFolder);
            });
    });
    

    Also, this way you don't need to declare the folder variables. If you add directories within the path being watched, it should pick it up and name the destination folder accordingly.

    Theoretically the gulp task to compile sass should work within the watch task. I played around with the paths, and it seems to spitting them out. Let me know what happens, I can modify if necessary.

    The required packages:

    var gulp = require("gulp"),
        path = require("path"),
        rimraf = require("rimraf");
    

    BTW, since you already have access to the file path, you can perhaps target the specific scss file instead of the whole directory.