Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Run eslint before watchify runs

I'm adding watchify to our build process but I want to put a precondition to watchify running, and that is that the file(s) that changed pass our linting step (which is using ESLint).

I was thinking of doing this:

function runBrowserify(watch){
  var babel = babelify.configure({
      optional: ['es7.objectRestSpread']
  });
  var b = browserify({
    entries: './app/main.js',
    debug: true,
    extensions: ['.jsx', '.js'],
    cache: {},
    packageCache: {},
    fullPaths: true
  })
  .transform(babel);

  if(watch) {
    // if watch is enable, wrap this bundle inside watchify
    b = watchify(b);
    b.on('update', function(ids) {
      //run the linting step
      lint(ids);

      //run the watchify bundle step
      gutil.log(gutil.colors.blue('watchify'), 'Started');
      bundleShare(b);
    });
    b.on('time', function (time) {
      gutil.log(gutil.colors.blue('watchify'), 'Finished', 'after', gutil.colors.magenta(time), gutil.colors.magenta('ms'));
    });
  }

  bundleShare(b);
}

function bundleShare(b) {
  b.bundle()
    .pipe(source('main.min.js'))
    .pipe(gulp.dest('./dist'));
}

function lint(glob) {
  return gulp.src(glob)
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failOnError());
}

The problem is that the linting step is async so it doesn't finish before the bundling would be done (it also throws so I probably need to use plumber to stop it from terminating the watch step).

So how would I make a precondition before I call bundleShared?

like image 872
Aaron Powell Avatar asked May 20 '15 23:05

Aaron Powell


1 Answers

I was able to do this using the closure method I mentioned above. I also moved my Browserify and Watchify code into helper functions that each build could take advantage of.

gulpfile.js (partial)

gulp.task('build:dev', buildDev); 
gulp.task('lint:js', lintJS);

function lintJS(callback) {
  return gulp.src(['src/**/*.js', 'src/**/*.jsx', '!src/js/vendor/**/*.*',])
      .pipe(eslint())
      .pipe(eslint.format())
      .pipe(eslint.failAfterError());
}

function buildDev(callback) {
  var bundler = getBundler('src/js/app.jsx', { debug: true }, callback);
  var watcher = getWatcher(bundler, rebundle);

  function rebundle() {
    lintJS(callback);

    return watcher.bundle()
      .pipe(source('bundle.min.js'))
      .pipe(buffer())
      .pipe(gulp.dest('dist/js'));
  }

  rebundle();
  // Call watch methods here, i.e.: watchHTML()
  return callback();
}

/****************************** Helper functions ******************************/

/**
 * Gets the default Browserify bundler used by all builds.
 *
 *
 * @param path A string representing where Browserify should start from
 * @param options An Object containing options for the bundler
 * @param callback The Gulp callback function from the calling task
 * @return A basically configured Browserify bundler
 */
function getBundler(path, options, callback) {
  var bundler = browserify(path, { debug: options.debug, cache: {}, packageCache: {} });
  bundler.transform(babelify);
  bundler.on('log', gutil.log);
  bundler.on('error', gutil.log.bind(gutil.colors.red, 'Browserify Error'));

  return bundler;
}

/**
 * Gets the default Watchify watcher used by dev builds. By default, the watcher
 * will rebundle the Browserify package when an update occurs.
 *
 * @param bundle The Browserify bundler object
 * @param rebundle A function to perform when Watchify detects a code update
 * @return A basically configured Watchify watcher
 */
function getWatcher(bundle, rebundle) {
  var watcher = watchify(bundle);
  watcher.on('update', rebundle);

  return watcher;
}

For my test and prod builds, I don't use Watchify (and thus have no rebundle() method) so I keep the 'lint:js' task as a dependency:

gulp.task('build:test', ['lint:js'], buildTest);
gulp.task('build:prod', ['lint:js'], buildProd);
like image 171
Matthew Herbst Avatar answered Nov 14 '22 03:11

Matthew Herbst