chris
chris

Reputation: 4351

Gulp has 2 tasks conflicting with each other

I have both javascript and css files that I am using a forked repo of gulp-rev lib[1] that both renames the files and updates the file references within the html file.

Unfortunately, there is a race condition between the two tasks resulting in either the stylesheet reference to the md5-named file OR the js files winning out.

I have tried to use promises as well as callbacks (see below) to allow for syncing of the tasks, but never are both of the css and js md5 references made.

sindresorhus's lib only renames the files and does not fix the links, so is there a better way to fix the html links, or is using the forked plugin they way to go (with some fixes that I am missing)?

gulp.task('rev', ['rev-js'] );
gulp.task('rev-js', ['rev-css'], function(cb) {
  var context = rev.Context();
  gulp.src(['./build/public/js/woddy.js', './build/public/js/angular.js', './build/public/js/components.js'])
    .pipe(rev(context))
    .pipe(gulp.dest('./build/public/js'));
  gulp.src('./build/public/app.html')
    .pipe(context.replace(/src="js\/(\w+\.js)"/g, 'src="js/{{$1}}"'))
    .pipe(gulp.dest('./build/public'));
});
gulp.task('rev-css', function() {
  var context = rev.Context();
  gulp.src('./build/public/styles/woddy.css')
    .pipe(rev(context))
    .pipe(gulp.dest('./build/public/styles'));
  gulp.src('./build/public/app.html')
    .pipe(context.replace(/href="styles\/(\w+\.css)"/g, 'href="styles/{{$1}}"'))
    .pipe(gulp.dest('./build/public'));
});
  1. https://github.com/dtinth/gulp-rev

Upvotes: 3

Views: 2398

Answers (1)

OverZealous
OverZealous

Reputation: 39560

Pretty much all operations within gulp are asynchronous, which means you need to use one of the 3 supported methods for notifying when a task is complete. (If a task is truly synchronous, you don't need to do anything.)

  1. Return a stream from a method (usually the easiest)
  2. Return a promise (rare in gulp)
  3. Use the callback method supplied to the task function.

First, you've got the callback argument in your rev-js method. By including the variable (cb), but never using it, that task will never "complete", so rev will hang around waiting for it.

Second, you've got two sets of streams in each task, which are being run simultaneously — not one-after-the-other as you might think. For example, in rev-js, the js task is started, then the html task is started, then either may process and complete in any order. Most likely, the HTML task will complete before all the JS files have been processed.

Personally, I'd split out the HTML task and use one of the existing plugins (such as gulp-inject, which is easy), and then handle that separately.

So, for that case, your file would look like this

gulp.task('rev', ['rev-html'] );

gulp.task('rev-html', ['rev-js', 'rev-css'], function() {
  // change to reference specific JS and CSS files as necessary
  return gulp.src(['./build/public/**/*.*', '!./build/public/index.html'])
    .pipe(inject('index.html'))
    .pipe(gulp.dest('./build/public'));
});

gulp.task('rev-js', function() { // NOTE: no `cb` here
  var context = rev.Context();
  return gulp.src(['./build/public/js/woddy.js', './build/public/js/angular.js', './build/public/js/components.js'])
    .pipe(rev(context))
    .pipe(gulp.dest('./build/public/js'));
});
gulp.task('rev-css', function() {
  var context = rev.Context();
  return gulp.src('./build/public/styles/woddy.css')
    .pipe(rev(context))
    .pipe(gulp.dest('./build/public/styles'));
});

Now, if you really want to handle the injection manually, then you should use a stream combiner and return the result of that stream. But you still need to have the JS step complete before the HTML step.

Upvotes: 5

Related Questions