peter-vilja / gulp-clean

A gulp plugin for removing files and folders from given paths.
177 stars 21 forks source link

Subsequent tasks fail sometimes #4

Closed thasmo closed 10 years ago

thasmo commented 10 years ago

Hello!

I'm experiencing some errors when using gulp-clean:

[gulp] Plumber found unhandled error: Error: EPERM, open 'S:\Project\gulpjs.dummy\public\static\image\cat.gif'
[gulp] Plumber found unhandled error: Error: EEXIST, mkdir 'S:\Project\gulpjs.dummy\public\static\image'
[gulp] Plumber found unhandled error: Error: EEXIST, mkdir 'S:\Project\gulpjs.dummy\public\static\image'
[gulp] Plumber found unhandled error: Error: EEXIST, mkdir 'S:\Project\gulpjs.dummy\public\static\image'
[gulp] Plumber found unhandled error: Error: EEXIST, mkdir 'S:\Project\gulpjs.dummy\public\static\image'

I'm not sure why this happens. My gulpfile can be found here: https://github.com/thasmo/gulpjs.dummy/blob/master/gulpfile.js

I'm trying to deleted a directory before running other tasks, but somehow the subsequent tasks do not create the desired directories/files after running gulp-clean. It seems like gulp-clean somehow interferes with the other tasks.

Any idea what that could be?

thasmo commented 10 years ago

I was able to get rid of the error messages, but still - the subsequent tasks do not create files in the directory, which should have been cleaned before. It seems like the cleaning happens after the new files got created.

thasmo commented 10 years ago

If I configure the task to only delete the files inside the directories, all works well. But if I configure to delete the parent directory, new files won't get created correctly.

peter-vilja commented 10 years ago

Hi,

I cloned your repository and it seems like there is an issue with if plugin.

Does it work if you change:

gulp.task('clean', function() {
    return gulp.src('public/static/', {read: false})
        .pipe(plugins.if(plugins.util.env.production, plugins.clean({force: true})));
});

to:

gulp.task('clean', function() {
    return gulp.src('public/static/', {read: false})
        .pipe(plugins.clean({force: true}));
});

and run it with gulp build

Of course this is not a great solution, but it helps to track down the problem.

thasmo commented 10 years ago

@peter-vilja thanks for your fast reply. You're right - seems to be related to the gulp-if plugin. Do you think it's related to https://github.com/robrich/gulp-if/pull/12?

peter-vilja commented 10 years ago

@thasmo No problem. Kind of. I am not sure, maybe the issue might be that gulp-if registers a child listener even when the file passed to stream gulp.src('public/static/'...) doesn't exist.

peter-vilja commented 10 years ago

Or maybe it's not issue with gulp-if, because this seems to cause the same problem.

gulp.task('clean', function() {
    var stream = gulp.src('public/static/', {read: false})
    if (gulp.env.production) {
        stream.pipe(plugins.clean({force: true}));
    }
    return stream;
});
thasmo commented 10 years ago

Weird. As a workaround this is what I do for now: https://github.com/thasmo/gulpjs.dummy/blob/master/gulpfile.js#L56

And it seems to work.

peter-vilja commented 10 years ago

@thasmo Now it seems like the issue is with gulp-load-plugins because this seems to work:

var gulp    = require('gulp'),
    plugins = require('gulp-load-plugins')(),
    server  = require('tiny-lr')();
    clean = require('gulp-clean');
gulp.task('clean', function() {
    var stream = gulp.src('public/static/', {read: false})
    if (plugins.util.env.production) {
        stream.pipe(clean({force: true}));
    }
    return stream;
});
peter-vilja commented 10 years ago

@thasmo I think it's because the gulp-load-plugins emit's 'end' before gulp-clean. Now the dependency system thinks that task is done, but only the gulp-load-plugins is done and the clean finishes later asynchronously.

thasmo commented 10 years ago

@peter-vilja, this again fails sometimes:

var gulp    = require('gulp'),
    plugins = require('gulp-load-plugins')(),
    clean   = require('gulp-clean'),
    server  = require('tiny-lr')();
gulp.task('build', ['clean'], function() {
    return gulp.start('styles', 'scripts', 'images');
});
gulp.task('clean', function() {
    return gulp.src('public/static/', {read: false})
        .pipe(plugins.if(plugins.util.env.production, clean({force: true})));
});

If there're already files in the directory public/static/, it gets removed, but stays empty (no files are generated). If I again execute gulp build --production the directory gets populated correctly.

peter-vilja commented 10 years ago

@thasmo Same thing here the if plugin 'emit's end before clean plugin and the clean is run asynchronously later. Use this one:

gulp.task('clean', function() {
    var stream = gulp.src('public/static/', {read: false})
    if (plugins.util.env.production) {
        stream.pipe(clean({force: true}));
    }
    return stream;
});
thasmo commented 10 years ago

So, are those bugs in if and load-plugins?

peter-vilja commented 10 years ago

@thasmo No. Just the dependency system believes that the task 'clean' is done because 'end' was emitted inside the task. But this 'end' wasn't gulp-clean's 'end' emit it was other plugins ('end') finishing first before gulp-clean. After this the dependency system started to run tasks 'scripts', 'styles' and 'images' and the actual process of clean finishes some where after running the other tasks.

thasmo commented 10 years ago

@peter-vilja, I see. Which would be weird for the if plugin at least, because it makes it useless, no?

peter-vilja commented 10 years ago

@thasmo Well only inside the task which is as a dependency to other task and last pipe is using it I think. For example here it would not be useless:

// Clean
gulp.task('stuff', function() {
    return gulp.src('public/static/*.js', {read: false})
                   .pipe(plugins.concat('app.js'))
               .pipe(gulp.dest('dist'));
});

// Build
gulp.task('build', ['stuff'], function() {
    gulp.run('styles', 'scripts', 'images');
});

I think this should work because now the last pipe .pipe(gulp.dest('dist')); Will emit correctly that the stream ended.

Or maybe this could be fixed in gulp-if by emitting 'end' only after the child process emit's end. I am not 100% sure that this is the issue, but it seems to be.

thasmo commented 10 years ago

@peter-vilja Thanks for your help and feedback. I've opened an issue on the gulp-if issue tracker requesting review on this - which would be helpful I think.

markgoodyear commented 10 years ago

I get a similar issue as above, although without using gulp-if. Perhaps not quite the same issue as above, but get the same outcome.

gulp.task('clean', function() {
    return gulp.src(['.src/assets/'], {read: false})
        .pipe(clean({force: true}));
});

gulp.task('default', ['clean', 'styles', 'scripts', 'imagemin', 'svgmin'])

As the dependancy array all run at the same time, clean doesn't have time to finish before moving on. I could do this:

gulp.task('default', ['clean'], function() {
    gulp.run(['clean', 'styles', 'scripts', 'imagemin', 'svgmin'])
});

However gulp.run() is depreciated so this won't be able to work in future versions. I'm not sure a way to ensure the clean task is fully complete / block all other tasks before finishing?

Cheers

peter-vilja commented 10 years ago

@markgoodyear You could do this.

var gulp = require('gulp');
var clean = require('gulp-clean');
var concat = require('gulp-concat');

gulp.task('styles', ['clean-styles'], function () {...});

gulp.task('scripts', ['clean-scripts'], function () {...});

gulp.task('clean-styles', function () {
  return gulp.src('.src/assets/styles', {read: false})
          .pipe(clean({force: true}));
});

gulp.task('clean-scripts', function () {
  return gulp.src('.src/assets/scripts', {read: false})
          .pipe(clean({force: true}));
});

gulp.task('default', ['styles', 'scripts']);

But this creates quite a lot boilerplate.

Other option is to use gulp.start

gulp.task('clean', function () {
  return gulp.src('.src/assets/', {read: false})
          .pipe(clean({force: true}));
});

gulp.task('default', ['clean'], function () {
  gulp.start('styles', 'scripts');
});

For more information: https://github.com/gulpjs/gulp/issues/193#issuecomment-33296003 https://github.com/robrich/orchestrator

I'll provide an example which shows how to use clean task as a dependency to the README.md

markgoodyear commented 10 years ago

@peter-vilja Yeah that's what I had thought about, though I didn't want to clean the files each time the task is run. I tried to avoid the gulp.start too, as it seems discouraged to use, but it does seem the better (and cleanest, excuse the pun!) method.

nmccready commented 10 years ago

OMG, gulp.start has solved my madness, thank you. They better not deprecate this. I also agree that chaining so many dependencies seems like super overkill. Especially when some tasks do not really need cleaning in front of it!