twolfson / gulp.spritesmith

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

Generated by intermittently cutting sprite image generation. #154

Closed Dailyscat closed 3 years ago

Dailyscat commented 3 years ago

Hello. I am using gulp spritesmith gratefully. When executing a build based on the gulp.js file below, the sprite file is sometimes cut and executed.

Attach the photo below. Could you please give us an opinion on what to doubt?

Thank you.

normal image

abnormal image

gulp.js

gulp.task('makeSprite', () => {
  var folders = getFolders(paths.sprite_png_src);
  let options = {
    spritesmith: (options) => {
      const { folder, paths } = options;
      return {
        imgPath: path.posix.relative(paths.css_src, path.posix.join(paths.img_src, 'sp_' + folder + '.png')),
        imgName: 'sp_' + folder + '.png',
        cssName: path.posix.relative(paths.img_src, path.posix.join(paths.scss_src, 'sprites', folder + '.scss')),
        cssFormat: 'scss',
        padding: 4,
        cssTemplate: path.join(paths.gulpconfig, './sprite_template.hbs'),
        cssSpritesheetName: folder,
        algorithm: 'binary-tree'
      }
    },
  }

  return folders.map((folder) => {
    return new Promise((resolve) => {
      gulp.src(path.join(paths.sprite_png_src, folder, '*@2x.png'))
          .pipe(gulpSort())
          .pipe(spritesmith(options.spritesmith({folder, paths})))
          .pipe(gulp.dest(paths.img_src))
          .on('end',resolve);
    });
  })
})

gulp.task('makeSpriteMaps', () => {
  const folders = getFolders(paths.sprite_png_src);
  var options = {
        maps: {
            handlebars: {
                path: path.join('.', path.posix.relative(path.join(paths.scss_src, 'sprites'), path.join(paths.scss_src, 'sprites'))),
                import: folders,
            }
        },
  };

    return new Promise((resolve) => {
        gulp.src('./sprite_maps_template.hbs')
            .pipe(handlebars(options.maps.handlebars))
            .pipe(rename('_sprite-mixins.scss'))
            .pipe(gulp.dest(path.join(paths.scss_src, 'sprites')))
            .on('end', resolve);
  });
});

gulp.task('sprite', (cb) => {
  return config.sprite.png ? runSequence('makeSprite', 'makeSpriteMaps', cb) : cb();
});
twolfson commented 3 years ago

This is a very long gulpfile.js to read through so I only focused on the tasks makeSprite and makeSpriteMap

These both seem to be returning a promise which waits for the end event

gulp.task('makeSprite', () => {
  // ...
  return folders.map((folder) => {
    return new Promise((resolve) => {
      gulp.src(path.join(paths.sprite_png_src, folder, '*@2x.png'))
          .pipe(gulpSort())
          .pipe(spritesmith(options.spritesmith({folder, paths})))
          .pipe(gulp.dest(paths.img_src))
          .on('end',resolve);
    });
  })
})

I can't recall if end is the appropriate event to wait for (I believe it might be close)

https://nodejs.org/docs/latest-v12.x/api/fs.html#fs_event_close_2

Additionally, Gulp has no insight into when the .map items are done writing to disk so it can stop before that completes (maybe why the file is incomplete)

One quick fix might be using Promise.all

But even better than changing the event would be to return the stream directly to gulp

https://gulpjs.com/docs/en/getting-started/async-completion#returning-a-stream

And then using a utility like merge-stream:

https://www.npmjs.com/package/merge-stream

const mergeStream = require('merge-stream');

gulp.task('makeSprite', () => {
  // ...
  return mergeStream(folders.map((folder) => {
    return gulp.src(path.join(paths.sprite_png_src, folder, '*@2x.png'))
          .pipe(gulpSort())
          .pipe(spritesmith(options.spritesmith({folder, paths})))
          .pipe(gulp.dest(paths.img_src));
    });
  }))
})
Dailyscat commented 3 years ago

@twolfson Thank you so much, I will support you