В Gulp 3 происходит зацикливание при сборке когда одновременно выполняется проверка SCSS и CSS файлов?

В версии 3.x Gulp.js действительно может возникнуть проблема зацикливания при одновременной сборке SCSS и CSS файлов.

Это происходит из-за особенностей последовательности выполнения задач в Gulp. При запуске Gulp.js вам может понадобиться создать несколько задач, например, для компиляции SCSS в CSS и для минификации CSS файлов. Вы можете определить эти задачи следующим образом:

const gulp = require('gulp');
const sass = require('gulp-sass');
const minifyCSS = require('gulp-clean-css');

gulp.task('sass', function() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('dist/css'));
});

gulp.task('minify-css', function() {
  return gulp.src('dist/css/*.css')
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist/css-min'));
});

gulp.task('default', gulp.series('sass', 'minify-css'));

При запуске задач Gulp в режиме наблюдения за изменениями файлов (например, командой gulp или gulp watch), Gulp будет следить за изменениями SCSS файлов и автоматически компилировать их в CSS. Затем Gulp будет следить за изменениями CSS файлов, минифицировать их и сохранять в отдельной папке.

Проблема возникает, когда компиляция SCSS файла вызывает перезапись CSS файла, и Gulp снова замечает изменение в CSS файле, вызывая задачу minify-css, которая в свою очередь изменяет и перезаписывает CSS файл, и так далее. Это создает зацикливание задач и бесконечный цикл сборки.

Чтобы предотвратить это, можно воспользоваться одним из следующих решений:

1. Используйте условие, чтобы проверить, если SCSS файл изменился, прежде чем запустить компиляцию и сохранение CSS файла:

const gulp = require('gulp');
const sass = require('gulp-sass');
const minifyCSS = require('gulp-clean-css');

let isCompilingSCSS = false;

gulp.task('sass', function() {
  if (isCompilingSCSS) return;
  isCompilingSCSS = true;
  
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('dist/css'))
    .on('end', function() {
      isCompilingSCSS = false;
    });
});

gulp.task('minify-css', function() {
  return gulp.src('dist/css/*.css')
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist/css-min'));
});

gulp.task('default', gulp.series('sass', 'minify-css'));

В этом случае мы добавляем флаг isCompilingSCSS, который показывает, что в данный момент выполняется задача компиляции SCSS. Если флаг уже установлен (т.е. предыдущая задача еще не завершена), задача sass будет прервана. Флаг будет установлен в значение true в момент начала выполнения задачи, и будет сброшен в значение false по завершении.

2. Используйте плагин gulp-newer, чтобы отслеживать только измененные файлы и минимизировать количество повторных задач:

const gulp = require('gulp');
const sass = require('gulp-sass');
const minifyCSS = require('gulp-clean-css');
const newer = require('gulp-newer');

gulp.task('sass', function() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(newer('dist/css'))
    .pipe(sass())
    .pipe(gulp.dest('dist/css'));
});

gulp.task('minify-css', function() {
  return gulp.src('dist/css/*.css')
    .pipe(newer('dist/css-min'))
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist/css-min'));
});

gulp.task('default', gulp.series('sass', 'minify-css'));

Здесь мы используем плагин gulp-newer, который отслеживает изменения только для уже существующих файлов в указанной папке. Это позволяет избежать повторной обработки файлов, что приводит к зацикливанию задач. Плагин будет сохранять временную метку изменения файла и сравнивать ее с рабочими файлами, пропуская только новые или измененные файлы.

3. Используйте Gulp 4.x, который предлагает более гибкую систему тасков и позволяет использовать gulp.series и gulp.parallel для управления последовательностью выполнения задач:

const gulp = require('gulp');
const sass = require('gulp-sass');
const minifyCSS = require('gulp-clean-css');

gulp.task('sass', function() {
  return gulp.src('src/scss/**/*.scss')
    .pipe(sass())
    .pipe(gulp.dest('dist/css'));
});

gulp.task('minify-css', function() {
  return gulp.src('dist/css/*.css')
    .pipe(minifyCSS())
    .pipe(gulp.dest('dist/css-min'));
});

gulp.task('default', gulp.series('sass', 'minify-css'));

В Gulp 4.x можно явно указать последовательность выполнения задач с помощью gulp.series. Это позволяет установить желаемую последовательность, чтобы избежать зацикливания. В данном случае задача minify-css не будет выполняться до завершения задачи sass, что исключает возможность зацикливания.

Выбор определенного решения зависит от ваших потребностей и предпочтений. Каждое из этих решений имеет свои особенности и подходит для различных сценариев использования.