Обработка массивов в Gulp для создания пакетов в каждом каталоге с упорядоченными файлами

Как и большинство, я объединял свои файлы JS/CSS в один большой файл в Gulp, однако, поскольку в настоящее время HTTP2 становится нормой, я подумал, что вместо этого изменю свой файл gulp, чтобы вместо этого создавать связанные «связки», однако мне интересно, как с этим справиться в чистом виде в Gulp.

Мой предыдущий файл gulpfile.js:

var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var concat = require('gulp-concat');
var rename = require('gulp-rename');
var sass = require('gulp-sass');
var postcss = require('gulp-postcss');
var cleanCSS = require('gulp-clean-css');
var uglify = require('gulp-uglify');
var gulpif = require('gulp-if');
var sourcemaps = require('gulp-sourcemaps');
var autoprefixer = require('autoprefixer');

var site_url = 'xxxxxxxxxxxxx.local';

// Set some paths

var js_scripts = [
    'js/dev/lib/**/*.js',
    'js/dev/plugins/**/*.js',
    // We have to set the bootstrap lines separately as some need to go before others
    'js/dev/bootstrap/alert.js',
    'js/dev/bootstrap/collapse.js',
    'js/dev/bootstrap/tooltip.js',
    'js/dev/bootstrap/popover.js',
    'js/dev/bootstrap/tab.js',
    'js/dev/bootstrap/transition.js',
    'js/dev/custom.js'
];

gulp.task('scripts', function() {
    return gulp.src(js_scripts)
        .pipe(sourcemaps.init())
            .pipe(concat('scripts.js'))
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest('./js'));
});

gulp.task('uglify', gulp.series('scripts', function() {
    return gulp.src(js_scripts)
        .pipe(gulpif('!**/*.min.js', uglify({mangle: false})))
        .pipe(concat('scripts.min.js'))
        .pipe(gulp.dest('./js'));
}));

// create a task that ensures the `uglify` task is complete before
// reloading browsers
gulp.task('js-watch', gulp.series('uglify', function (done) {
    browserSync.reload();
    done();
}));

/* Creates the standard version */

gulp.task('styles', function() {
    return gulp.src('scss/**/*.scss')
        .pipe(sourcemaps.init())
        .pipe(sass().on('error', sass.logError))
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest('./css/'))
        .pipe(browserSync.stream());
});

/* Creates the minified version */

gulp.task('css-minify', gulp.series('styles', function() {
    return gulp.src('scss/**/*.scss')
        .pipe(sourcemaps.init())
            .pipe(sass({
                outputStyle: 'compact' // Options: nested, expanded, compact, compressed
            }).on('error', sass.logError))
            .pipe(postcss([
                autoprefixer({
                    cascade: false
                }),
            ]))
            .pipe(cleanCSS({
                advanced: false,
                aggressiveMerging: false
            }))
            .pipe(rename({suffix: '.min'}))
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest('./css/'));
}));

gulp.task('browser-sync', function(done) {
    browserSync.init({
        open: 'external',
        proxy: site_url,
        host: site_url,
        // port: 5000,
        browser: "chrome",
    });
    done();
});

gulp.task('watch', gulp.series('browser-sync', function() {
    gulp.watch('scss/**/*.scss', gulp.series('css-minify'));
    gulp.watch('js/dev/**/*.js', gulp.series('js-watch'));
}));

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

Теперь, чтобы помочь превратить файлы JS в пакеты, я внес изменение в массив js_scripts, чтобы:

var js_scripts = [
    [
        'lib',
        [
            'js/dev/lib/**/*.js'
        ],
        ['lib.js', 'lib.min.js']
    ],
    [
        'plugins',
        [
            'js/dev/plugins/**/*.js'
        ],
        ['plugins.js', 'plugins.min.js']
    ],
    [
        'bootstrap',
        [
            // We have to set the bootstrap lines separately as some need to go before others
            'js/dev/bootstrap/alert.js',
            'js/dev/bootstrap/collapse.js',
            'js/dev/bootstrap/tooltip.js',
            'js/dev/bootstrap/popover.js',
            'js/dev/bootstrap/tab.js',
            'js/dev/bootstrap/transition.js',
        ],
        ['bootstrap.js', 'bootstrap.min.js']
    ],
    [
        'custom',
        [
            'js/dev/custom.js'
        ],
        ['custom.js', 'custom.min.js']
    ],
];

Идея заключалась в том, что мы будем перебирать этот массив и создавать для каждого отдельный файл JS + min.js.

Теперь проблема в том, что я не уверен, как добиться этого в Gulp чистым способом.

Возьмите это, например:

gulp.task('scripts', function() {
    return gulp.src(js_scripts)
        .pipe(sourcemaps.init())
            .pipe(concat('scripts.js'))
        .pipe(sourcemaps.write('../maps'))
        .pipe(gulp.dest('./js'));
});

В идеале было бы хорошо прокрутить массив здесь; но я не уверен, как справиться с этим несколько раз, потому что как только вы return получите первый результат, очевидно, что цикл закончится.

Нужно ли возвращать Gulp каждый раз? ... если нет, то что вы возвращаете после завершения обработки цикла?


person Brett    schedule 10.02.2020    source источник


Ответы (1)


Я попытался использовать gulp-order, чтобы принудительно упорядочить файлы начальной загрузки, но это было ненадежно. Здесь я вместо этого использую merge2 - кажется, он работает намного лучше. Предполагается, что теперь у вас есть папка custom.

[Для краткости я не включил ваши sourcemaps каналы и перезагрузку browserSync.]

const gulp = require('gulp');
const concat = require('gulp-concat');

// const rename = require('gulp-rename');  // not needed
// var gulpif = require('gulp-if');        // not needed

var terser = require('gulp-terser');      // better than uglify, works with es6
const merge2 = require('merge2')          // does the ordering of source files
const glob = require('glob');
const path = require('path');

// glob.sync will build your array for you, so you don't need your 'js_scripts' array

const bundleFolders = glob.sync('js/dev/*/'); // returns an array of folders
console.log(bundleFolders);

gulp.task('scripts', () => {

  let stream;

  for (const bundle of bundleFolders) {

    // get just the last directory of 'js/dev/bootstrap', 'js/dev/lib`, etc.
    let thisBundle = path.basename(bundle);
    console.log('thisBundle = ' + thisBundle);

    if (thisBundle === 'bootstrap') {

      stream = merge2(

        gulp.src([
          'js/dev/bootstrap/alert.js',
          'js/dev/bootstrap/collapse.js',
          'js/dev/bootstrap/tooltip.js',
          'js/dev/bootstrap/popover.js',
          'js/dev/bootstrap/tab.js',
          'js/dev/bootstrap/transition.js',
        ])
          // your other stuff - sourcemaps, etc.
          .pipe(concat(thisBundle + '.js'))
          // your other stuff - sourcemaps, etc.
        .pipe(gulp.dest('./js')));
    }

    else {  // not 'bootstrap' directory

      stream = gulp.src(bundle + "**/*.js")
        // your other stuff - sourcemaps, etc.
        .pipe(concat(thisBundle + '.js'))
        // your other stuff - sourcemaps, etc.
        .pipe(gulp.dest('./js'));
    }
  }

  return stream;
});

// gulp.task('uglify', gulp.series('scripts', function () {  // not needed

gulp.task('terser', () => {

  let bundles= [];

  for (const bundle of bundleFolders) {

    // get `js/dev/custom/custom.js`,'js/dev/bootstrap/bootstrap.js' etc.
    bundles.push(bundle + path.basename(bundle) + '.js');
  }

  console.log(bundles);


  return gulp.src(bundles)

      // .pipe(gulpif('!**/*.min.js', uglify({mangle: false})))

      //  assumes what you want to uglify and concat are the 'lib.js', bootstrap.js', etc. files 

    .pipe(terser({ mangle: false }))    
    .pipe(concat('scripts.min.js'))    
    .pipe(gulp.dest('./js'));
});

// create a task that ensures the `terser` task is complete before
// reloading browsers
// gulp.task('js-watch', gulp.series('terser', function (done) {
//   browserSync.reload();
//   done();
// }));

gulp.task('watch', gulp.series('browser-sync', function () {

  gulp.watch('scss/**/*.scss', gulp.series('css-minify'));

  // gulp.watch('js/dev/**/*.js', gulp.series('js-watch'));    // replaced by below
  gulp.watch('js/dev/**/*.js', gulp.series('scripts', 'terser', browserSync.reload));
}));


exports.terser = gulp.series('terser');    // useful for testing
exports.scripts = gulp.series('scripts');  // useful for testing

exports.default = gulp.series('scripts');  // just for testing
person Mark    schedule 11.02.2020
comment
Потрясающе - спасибо. Нет проблем с размещением custom.js в отдельной папке; мой единственный вопрос: как мне обрабатывать файлы начальной загрузки, где я упомянул в комментариях, что мне нужно, чтобы они обрабатывались в определенном порядке? - person Brett; 11.02.2020
comment
Спасибо за это. Я начал тестировать это, но столкнулся с некоторыми проблемами..... кажется, были некоторые синтаксические ошибки, но думаю, что я их исправил. Протестировал только на задаче скриптов, но получил эту ошибку: Следующие задачи не выполнены: по умолчанию, js-watch, uglify, скрипты. Вы забыли сигнализировать о завершении асинхронного выполнения? - наконец, нет ли необходимости включать вызов concat сейчас или вы оставили его для краткости? - person Brett; 12.02.2020
comment
Я просто пропустил ваши трубы для краткости. Раньше я использовал эту форму возврата потока без асинхронного предупреждения. Вы получаете это предупреждение, если запускаете только задачу scripts. - person Mark; 12.02.2020
comment
О, хорошо... причина, по которой я спрашивал, нужно ли мне все еще включать вызов concat, заключалась в том, что я не был уверен, как теперь установить имя файла; как вы можете видеть, я ранее установил его на scripts.js, но теперь имя файла будет динамическим, что я должен поставить вместо этого? Представляет ли bundle папку? Это строка и будет ли работать contact(bundle + '.js')? Что касается вашего другого вопроса, да, просто запуск задачи scripts вызывает ошибки того же типа. - person Brett; 12.02.2020
comment
Я сильно пересмотрел код, я не мог заставить работать сортировку залпом. Я тестировал код. Попробуйте это по частям, чтобы начать. Сначала запустите gulp scripts, а затем gulp terser, чтобы увидеть, получаете ли вы ожидаемые файлы в своих каталогах. - person Mark; 14.02.2020
comment
Извините, у меня еще не было возможности проверить это, но просто просматриваю - интересно, почему вы больше не используете gulp-if? В задаче terser кажется, что вы работаете с файлами, сгенерированными задачей scripts, а не просматриваете отдельные файлы - проблема в том, что в этих связанных файлах могут быть уже сжатые файлы, поэтому я думаю, что было бы чище запускать каждый файл снова создать соответствующие файлы пакета *.min.js, чтобы избежать двойного сжатия уже минифицированных файлов? - person Brett; 18.02.2020
comment
У краткого канала есть этот источник: return gulp.src(bundles), который является ``js/dev/custom/custom.js,'js/dev/bootstrap/bootstrap.js, js/dev/lib/lib.js и т. д.' только файлы - пакеты. Они не будут содержать уже минифицированных файлов (если вы по какой-то причине не включили эту функциональность в свои scripts задачи). Я не вижу необходимости предварительно минифицировать какие-либо файлы до тех пор, пока вы не сделаете пакеты, а затем не уменьшите их. - person Mark; 19.02.2020
comment
О, иногда я буду включать предварительно минифицированные файлы; например, jQuery может быть включен; Я предпочитаю использовать их уже уменьшенную версию, чем создавать свою собственную; поэтому в этом случае мы должны избегать их повторного сжатия и, следовательно, снова запускать исходные файлы. Я уверен, что смогу понять, как это сделать, основываясь на вашем примере в задаче scripts, но подумал, что вы можете обновить свой ответ :) - person Brett; 19.02.2020
comment
Тестировал это и работал хорошо; хотя он создавал файлы не в том месте; необходимо изменить gulp.dest() обратно на gulp.dest('./js'). - person Brett; 21.02.2020
comment
Рад принять этот ответ с внесенными изменениями... :) - person Brett; 22.02.2020