问题
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