Как насчет этой комбинации gulp -concat и lazypipe вызывает ошибку при использовании gulp 4?

Я обновляюсь от Gulp от 3 до 4, и у меня возникает ошибка:

The following tasks did not complete: build
Did you forget to signal async completion?

Я понимаю, что он говорит, но не может понять, почему этот код запускает его.

Ошибка или нет, задача завершена (файлы объединены и записаны в dest). Выполнение одного и того же кода без lazypipe не приводит к ошибке, и удаление конкатенации внутри lazypipe также устраняет ошибку.

Обертка всей вещи в том, что создает поток (например, поток слияния), устраняет проблему. Я предполагаю, что что-то о взаимодействии между gulp -concat и lazypipe препятствует правильному возврату потока.

Здесь (упрощенная) задача:

gulp.task('build', function() {
    var dest = 'build';

    var buildFiles = lazypipe()
        .pipe(plugins.concat, 'cat.js') // Task will complete if I remove this
        .pipe(gulp.dest, dest);

    // This works
    // return gulp.src(src('js/**/*.js'))
    //     .pipe(plugins.concat('cat.js'))
    //     .pipe(gulp.dest(dest));

    // This doesn't (unless you wrap it in a stream-making function)
    return gulp.src(src('js/**/*.js'))
        .pipe(buildFiles());
});

Любые советы оценены!

Ответ 1

Это известная проблема при использовании lazypipe с gulp 4, и это не будет исправлено в ближайшем будущем. Цитата из этой проблемы:

OverZealous прокомментировал 20 декабря 2015 г.
На данный момент я не собираюсь делать лазиппип на gulp 4.

Насколько я могу судить, эта проблема вызвана тем фактом, что gulp 4 использует async-done, который имеет это сказать о его поддержка потока:

Примечание. Поддерживаются только фактические потоки, а не потоки faux; Поэтому модули типа event-stream не поддерживаются.

Когда вы используете lazypipe() как последний канал, вы получаете поток, который не имеет большого количества свойств, которые вы обычно используете при работе с потоками в gulp. Вы можете сами это увидеть, зарегистрировав потоки:

// console output shows lots of properties
console.log(gulp.src(src('js/**/*.js'))
  .pipe(plugins.concat('cat.js'))
  .pipe(gulp.dest(dest))); 

// console output shows much fewer properties
console.log(gulp.src(src('js/**/*.js'))
  .pipe(buildFiles())); 

Вероятно, это причина, по которой gulp считает, что второй поток является "фальшивым потоком" и не обнаруживает, когда поток завершен.

Ваш единственный вариант на данный момент - это своего рода обходное решение. Самый простой способ обхода (который не требует дополнительных пакетов) - просто добавить функцию обратного вызова cb к вашей задаче и прослушать событие 'end':

gulp.task('build', function(cb) {
  var dest = 'build';

  var buildFiles = lazypipe()
   .pipe(plugins.concat, 'cat.js') 
   .pipe(gulp.dest, dest);

  gulp.src(src('js/**/*.js'))
   .pipe(buildFiles())
   .on('end', cb);
});

В качестве альтернативы добавление любого .pipe() после buildFiles() должно исправить это, даже тот, который на самом деле ничего не делает gutil.noop()

var gutil = require('gulp-util');

gulp.task('build', function() {
  var dest = 'build';

  var buildFiles = lazypipe()
    .pipe(plugins.concat, 'cat.js') 
    .pipe(gulp.dest, dest);

  return gulp.src(src('js/**/*.js'))
    .pipe(buildFiles())
    .pipe(gutil.noop());
});

Ответ 2

Так что ошибка понятна. Мне пришлось провести некоторый рефакторинг, чтобы все снова заработало для gulp 4. Я закончил тем, что сделал несколько дополнительных методов, которые берут источник и назначение и выполняют задачи, ранее выполненные моей реализацией lazypipe.

Я должен сказать, что я не скучаю по Lazypipe сейчас. Это просто другой подход. Я закончил с некоторыми дополнительными задачами, но они используют стандартный метод, как в примере ниже:

// previously a lazypipe, now just a method to return from a gulp4 task 
const _processJS = (sources, destination) => {

  return src(sources)
    .pipe(minify(...))
    .pipe(uglify(...))
    .pipe(obfuscate(...))
    .pipe(whatever())
    .pipe(dest(destination));

};

const jsTaskXStep1 = ()=>{
  return src(...).pipe(...).pipe(...).pipe(dest(...));
};

const jsTaskXStep2 = ()=>{
  return _processJS(['./src/js/x/**/*.js'], './dist/js');
};

const jsTaskYStep1 = ()=>{
  return src(...).pipe(...).pipe(...).pipe(dest(...));
};

const jsTaskYStep2 = ()=>{
  return _processJS(['./src/js/y/**/*.js'], './dist/js');
};

const jsTaskX = series(jsTaskXStep1, jsTaskXStep2);
const jsTaskY = series(jsTaskYStep1, jsTaskYStep2);

module.exports = {
  js: parallel(jsTaskX, jsTaskY),
  css: ...,
  widgets: ...,
  ...
  default: parallel(js, css, widgets, series(...), ...); 
}

Таким образом, вы можете поместить свои ленипайпы в методы, подобные _processJS в этом примере. И затем создайте задачи, которые используют это и объедините все с сериями глотка и параллелью. Надеюсь, это поможет некоторым из вас, кто борется с этим.