javascriptgulpgulp-babel

Gulp Plumber or PrettyError does not work in a loop


I have a problem with gulp watch that breaking after error. Then i found a good reference to use plumber, and the extension of it, gulp-prettyerror.

Then i create this gulpfile.js

const gulp          = require('gulp'),
      babel         = require('gulp-babel')
      changed       = require('gulp-changed'),
      prettyError   = require('gulp-prettyerror');


////////////////////////// START SQUAREBOOK ////////////////////////////////
const reactSquarebookSource   = './common/modules/squarebook/web/jsx/*.{js,jsx}';
const reactSquarebookDest     = './common/modules/squarebook/web/js';

// run babel on squarebook
gulp.task('babel:squarebook', function () {
  return gulp.src(reactSquarebookSource)
    .pipe(prettyError())
    .pipe(changed(reactSquarebookDest)) // make sure only changed source
    .pipe(babel()) // do the babel
    .pipe(gulp.dest(reactSquarebookDest));
});

gulp.task('watch:squarebook', function () {
  gulp.watch(reactSquarebookSource, ['babel:squarebook']);
});
////////////////////////// FINISH SQUAREBOOK ///////////////////////////////


///////////////////////// START FRONTEND ///////////////////////////////////
const reactFrontendSource   = './frontend/web/jsx/*.{js,jsx}';
const reactFrontendDest     = './frontend/web/js';

// run babel on frontend
gulp.task('babel:frontend', function () {
  return gulp.src(reactFrontendSource)
    .pipe(prettyError())
    .pipe(changed(reactFrontendDest)) // make sure only changed source
    .pipe(babel()) // do the babel
    .pipe(gulp.dest(reactFrontendDest));
});

gulp.task('watch:frontend', function () {
  gulp.watch(reactFrontendSource, ['babel:frontend']);
});
///////////////////////// FINISH FRONTEND //////////////////////////////////

// all babel react
gulp.task('babel', [
  'babel:squarebook',
  'babel:frontend'
])

// all watchers
gulp.task('watch', [
  'watch:squarebook',
  'watch:frontend'
]);

gulp.task('default', [
  'babel',
  'watch'
]);

The prettyError works really fine. I like that. But this code is pretty redundant. I still need to create more modules, which will make me copy-paste the task each time i create a module. So i decided to refactor it to:

// require all the libraries
const gulp          = require('gulp'),
      babel         = require('gulp-babel')
      changed       = require('gulp-changed'),
      prettyError   = require('gulp-prettyerror');

// react source map
const moduleSources = {
  squarebook: {
    src   : './common/modules/squarebook/web/jsx/*.{js,jsx}',
    dest   : './common/modules/squarebook/web/js'
  },
  frontend: {
    src   : './frontend/web/jsx/*.{js,jsx}',
    dest  : './frontend/web/js'
  }
}

gulp.task('babel', function () {
  for(var moduleName in moduleSources) {
    var sourceMap = moduleSources[moduleName];
    var taskName = 'babel:' + moduleName;

    // create the task
    gulp.task(taskName, function () {
      return gulp.src(sourceMap.src)
        .pipe(changed(sourceMap.dest)) // make sure only changed source
        .pipe(prettyError())
        .pipe(babel()) // do the babel
        .pipe(gulp.dest(sourceMap.dest));
    });
    // do the watcher
    gulp.watch(sourceMap.src, [taskName]);
  }
});

gulp.task('default', [
  'babel'
]);

Now that i have tried to create an error on the './common/modules/squarebook/web/jsx/*.{js,jsx}', the error is not displayed. It seems that prettyError only shows the error in the last loop. The watcher is not breaking, but the error is not displayed. Any idea why this is happening?

I wonder whether the loop is making the error or not.


Solution

  • The problem is that i use sourceMap inside the anonymous function, that will be updated until the end of the loop. So, my solution is:

    // require all the libraries
    const gulp          = require('gulp'),
          babel         = require('gulp-babel')
          changed       = require('gulp-changed'),
          prettyError   = require('gulp-prettyerror');
    
    // react source map
    const moduleSources = {
      squarebook: {
        src   : './common/modules/squarebook/web/jsx/*.{js,jsx}',
        dest  : './common/modules/squarebook/web/js'
      },
      frontend: {
        src   : './frontend/web/jsx/*.{js,jsx}',
        dest  : './frontend/web/js'
      }
    }
    
    // http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
    // create function to ensure the right closure
    function processBabel(src, dest) {
      console.log(src);
      return gulp.src(src)
        .pipe(changed(dest)) // make sure only changed source
        .pipe(prettyError())
        .pipe(babel()) // do the babel
        .pipe(gulp.dest(dest));
    }
    
    var babelTasks = [];
    gulp.task('babel', function () {
      for(var moduleName in moduleSources) {
        var sourceMap = moduleSources[moduleName];
        var taskName = 'babel:' + moduleName;
    
        // create the task
        gulp.task(taskName, processBabel.bind(this, sourceMap.src, sourceMap.dest));
    
        // do the watcher
        gulp.watch(sourceMap.src, [taskName]);
      }
    });
    
    
    gulp.task('default', [
      'babel'
    ]);
    

    Therefore, i create other function to handle src and dest, so that it will not be updated by reference.