Pass parameter to Gulp task in gulpfile.js (not co

2019-09-04 06:24发布

问题:

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. :-/

回答1:

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.



回答2:

As Brian answered, the best approach is to have one watcher. In the same way as the principle of delegation with dom event listeners. it's better, even in our case it can not really matter. We need our thing done. if the consumed resources and performance doesn't bother us. It's ok. But stay as Brian answered. one watcher is the best approach. then you've got to get the file that was changed. and from there you get your page folder. So for that i will not add a thing. Except that you don't necessarily need to use the .on("change". You can directly set the same parameter for your function as this example show:

  watch('./app/tempGulp/json/**/*.json', function (evt) {
    jsonCommentWatchEvt = evt
    gulp.start('jsonComment')
})

evt here is what Brian set as file.

What i want to add, is about how to pass a parameter from your watcher to your task. For example about the i in your initial work. A way of doing that, that i see and use, is to set a global variable that hold the data wanted to be passed. So it's accessible in both blocks. You set the value in watcher just before starting the task. And then you use it in the task. A good practice, is to save it in a task local variable just at start. That way you avoid the problem that it can change by another watch handling triggering.

For a lively example. check my answer out here : https://stackoverflow.com/a/49733123/7668448