twolfson / gulp.spritesmith

Convert a set of images into a spritesheet and CSS variables via gulp
The Unlicense
1.07k stars 81 forks source link

Run task synchronously - wait on .img & .css to be processed. #48

Closed wembernard closed 9 years ago

wembernard commented 9 years ago

I'm trying to make a watch or build feature using spritesmith. My gulp watch works fine updating my sprite whenever I add/remove/change some *.png in my icon directory.

However, my gulp build fails on the first attempt because my gulp sprite-dist starts before my gulp sprite has complete its job.

Here is my sprite task:

  gulp.task('sprite', function () {
    var sprite = gulp.src(options.src + '/assets/images/icon/*.png')
      .pipe(spritesmith({
          imgName: 'sprite.png',
          cssName: 'sprite.css',
          imgPath: '../assets/images/sprite.png'
        }));

    sprite.img
      .pipe(imagemin())
      .pipe(gulp.dest(options.tmp + '/serve/assets/images'))
      .pipe(browserSync.reload({ stream: true }))
      .pipe($.size());

    sprite.css
      .pipe(gulp.dest(options.tmp + '/serve/app/'))
      .pipe(browserSync.reload({ stream: true }))
      .pipe($.size());

    return sprite;
  });

Here is my sprite-dist task

  gulp.task('sprite-dist', ['sprite'], function() {
    return gulp.src([
      options.tmp + '/serve/assets/images/sprite.png'
    ])
      .pipe(gulp.dest(options.dist + '/assets/images/'))
      .pipe($.size({ title: options.dist + '/assets/images/', showFiles: true }));
  });

After investigation, I realized my problem comes from:

    sprite.img...
    sprite.css...

    return sprite;

which makes my sprite task considered as complete while .img and .css are still running.

Do you have any idea on how to solve this problem?

twolfson commented 9 years ago

gulp identifies a task is done via a few different mechanisms:

https://github.com/orchestrator/orchestrator/blob/v0.3.7/lib/runTask.js#L32-L65

For our purposes, we need to wait for the end events on both of the piped results of the img and css streams.

https://nodejs.org/api/stream.html#stream_event_end

gulp has a recipe for this which utilizes merge-stream.

https://github.com/gulpjs/gulp/blob/v3.8.11/docs/recipes/using-multiple-sources-in-one-task.md

For your purposes, the script would look like:

  gulp.task('sprite', function () {
    var sprite = gulp.src(options.src + '/assets/images/icon/*.png')
      .pipe(spritesmith({
          imgName: 'sprite.png',
          cssName: 'sprite.css',
          imgPath: '../assets/images/sprite.png'
        }));

    var imgStream = sprite.img
      .pipe(imagemin())
      .pipe(gulp.dest(options.tmp + '/serve/assets/images'))
      .pipe(browserSync.reload({ stream: true }))
      .pipe($.size());

    var cssStream = sprite.css
      .pipe(gulp.dest(options.tmp + '/serve/app/'))
      .pipe(browserSync.reload({ stream: true }))
      .pipe($.size());

    return merge(imgStream, cssStream);
  });

In the past, we have also listed out a callback based solution in #9.

https://github.com/twolfson/gulp.spritesmith/issues/9

twolfson commented 9 years ago

Reopening task because we seem to lack this example in our documentation x_x

Thanks for the bug report by the way =)

twolfson commented 9 years ago

We have updated the documentation to now include merge-stream. Thanks again for the bug report =)

wembernard commented 9 years ago

Thanks for your help @twolfson :)

merge-stream was the solution I was looking for.