Processing arrays within Gulp to create bundles in each directory with ordered files

僤鯓⒐⒋嵵緔 提交于 2020-02-25 06:33:05

问题


Like most I have been concatenating my JS/CSS files into one big file within Gulp, however, with HTTP2 becoming the norm nowadays I thought I would change my gulp file instead to make related "bundles" instead, however am wondering how to manage this in a clean fashion within Gulp.

My prior 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'));

Now, to help turn the JS files into bundles I have made a change to the js_scripts array, to:

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']
    ],
];

With the idea being that we will loop through this array and create a separate JS + min.js file for each.

Now, the problem is I'm not sure how to achieve this in Gulp in a clean way.

Take this for example:

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

Ideally it would be good to loop through the array in here; but I'm not sure how to handle doing this multiple times, because once you return the first result then obviously the loop is going to end.

Does Gulp need to return each time? ...if not, then what do you return once you have finished processing the loop?


回答1:


I tried using gulp-order to force ordering of the bootstrap files but it was unreliable. Here I use merge2 instead - it seems to work much better. Assumes you now have a custom folder.

[I didn't incorporate your sourcemaps pipes and browserSync reloads for brevity.]

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


来源:https://stackoverflow.com/questions/60156114/processing-arrays-within-gulp-to-create-bundles-in-each-directory-with-ordered-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!