Gulp browserify order/sort files - javascript

I've got a Gulp task using browserify and watchify. As you can see I've got four files. modules.js uses the class from overlay-model.js.
But browserify doens't keep the order I'm passing. Instead of that browserify puts the files in alphabetical order so it first uses modules.js.
I'll tried looking for a solution gulp sort doens't seem to work and I can't find a browserify-ish solution.
Anyone knows something about this?
var gulp = require('gulp');
var gutil = require('gulp-util');
var c = gutil.colors;
var sort = require('gulp-sort');
var sourcemaps = require('gulp-sourcemaps');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var browserify = require('browserify');
var watchify = require('watchify');
var babel = require('babelify');
function compile(watch) {
var bundler = watchify(browserify([
'./assets/js/overlay-model.js',
'./assets/js/slider.js',
'./assets/js/words.js',
'./assets/js/modules.js'
], {
debug: true
})
.transform(babel.configure({
presets: ['es2015']
})));
function rebundle() {
bundler.bundle()
.on('error', function(err) { console.error(err); this.emit('end'); })
.pipe(source('build.js'))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./public'));
}
if (watch) {
gutil.log(`${c.cyan('scripts')}: watching`);
bundler.on('update', function() {
gutil.log(`${c.cyan('scripts')}: processing`);
rebundle();
});
}
rebundle();
}
function watch() {
return compile(true);
};
gulp.task('build', function() { return compile(); });
gulp.task('watch', function() { return watch(); });
gulp.task('scripts', ['watch']);

I think typically you'll have just one entry point (modules.js in your case) that'll use require(...) to load other modules in order you want.
// modules.js
require('./overlay-model');
require('./slider');
require('./modules');
Then use browserify like:
browserify('./assets/js/modules.js', ...);

Related

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

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?
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

Combine two gulp tasks into one JS file

I have the following two tasks:
gulp.task('compress', () => {
return gulp.src('app/static/angular/**/*.js')
.pipe(concat('build.js'))
.pipe(gulp.dest('./app/static'));
});
gulp.task('templates', () => {
return gulp.src('app/static/angular/**/*.html')
.pipe(htmlmin())
.pipe(angularTemplateCache('templates.js', {
module: 'myApp',
root: '/static/angular'
}))
.pipe(gulp.dest('./app/static'))
});
And it works fine, but I want them both concatenated into build.js -- how can I combine these two?
In the end I used merge-stream to merge the two streams into one output file:
var gulp = require('gulp');
var concat = require('gulp-concat');
var htmlmin = require('gulp-htmlmin');
var angularTemplateCache = require('gulp-angular-templatecache');
var merge = require('merge-stream');
gulp.task('build', () => {
var code = gulp.src('app/static/angular/**/*.js');
var templates = gulp.src('app/static/angular/**/*.html')
.pipe(htmlmin())
.pipe(angularTemplateCache({
module: 'myApp',
root: '/static/angular'
}));
return merge(code, templates)
.pipe(concat('build.js'))
.pipe(gulp.dest('./app/static'));
});
gulp.task('default', ['build']);
I assume the above task mentioned is in separate file say compress.js inside tasks folder
In gulpfile.js you can use below code :
//Include require-dir to include files available in tasks directory
var requireDir = require('require-dir');
// And Take the tasks directory
requireDir('./tasks');
Then you can create a build task as below in gulpfile.js:
gulp.task('build', ['compress', 'templates']);

Optimizing gulp watch task

I'm new to gulp and I've got a couple of gulp questions that I hope are pretty easy (meaning I'll probably have one of those forehead smacking moments when I hear the answer)...
My gulpfile has a number of repetitive one-way copy tasks, and then I'm watching these separate tasks in the watch command, however I'm almost certain that the way I'm doing it is totally inefficient.
Also, I'm noticing some interesting behavior, the copy command for syncHtmlRootDir task works exactly as I hoped (it will delete files as necessary), but none of my other one way copy tasks will remove deleted files, and I'm guessing it's a pathing issue, but I'm stumped on it.
gulpfile.js
var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css')
var uglify = require('gulp-uglify');
var newer = require('gulp-newer');
var path = require('path');
var del = require('del');
function handleError (error) {
console.log(error.toString())
this.emit('end')
}
//setup browerSync to serve from both src and dist directories.
gulp.task('browserSync', function() {
browserSync.init({
server: {
baseDir: ["./", "src"] // ./ signifies root of folder, allows to load files from dist and src folders.
},
})
});
//one way sync of root folder
gulp.task('syncHtmlRootDir', function(done) {
return gulp.src(['src/*.html'])
.pipe(newer('dist/'))
.pipe(gulp.dest('dist/'))
.pipe(browserSync.reload({
stream: true
}))
});
//one way sync of app folder
gulp.task('syncHtmlAppDir', function(done) {
return gulp.src(['src/app/**/*'])
.pipe(newer('dist/app/'))
.pipe(gulp.dest('dist/app/'))
.pipe(browserSync.reload({
stream: true
}))
});
//one way sync of image folder
gulp.task('syncImgDir', function(done) {
return gulp.src(['src/assets/img/**/*'])
.pipe(newer('dist/assets/img/'))
.pipe(gulp.dest('dist/assets/img/'))
.pipe(browserSync.reload({
stream: true
}))
});
//copy and compile SCSS code
gulp.task('compileSass', function() {
return gulp.src('src/assets/css/**/*.scss')
.pipe(sass())
.on('error', handleError)
.pipe(minifyCss())
.pipe(gulp.dest('dist/assets/css'))
.pipe(browserSync.reload({
stream: true
}))
});
//minify JS
gulp.task('uglifyJS', function() {
gulp.src('src/assets/js/**/*.js')
.pipe(uglify())
.on('error', handleError)
.pipe(gulp.dest('dist/assets/js'))
.pipe(browserSync.reload({
stream: true
}))
});
//watch tasks
gulp.task('watch', ['browserSync'], function() {
var rootDir = gulp.watch('src/*.html', ['syncHtmlRootDir']);
rootDir.on('change', function(ev) {
if(ev.type === 'deleted') {
del(path.relative('./', ev.path).replace('src','dist'));
}
});
var appDir = gulp.watch('src/app/**/*', ['syncHtmlAppDir']);
appDir.on('change', function(ev) {
if(ev.type === 'deleted') {
del(path.relative('./', ev.path).replace('src/app/','dist/app/'));
}
});
var imgDir = gulp.watch('src/assets/img/**/*', ['syncImgDir']);
imgDir.on('change', function(ev) {
if(ev.type === 'deleted') {
del(path.relative('./', ev.path).replace('src/assets/img/','dist/assets/img/'));
}
});
var jsDir = gulp.watch('src/assets/js/**/*', ['uglifyJS']);
jsDir.on('change', function(ev) {
if(ev.type === 'deleted') {
del(path.relative('./', ev.path).replace('src/assets/js/','dist/assets/js/'));
}
});
var cssDir = gulp.watch('src/assets/css/**/*', ['compileSass']);
cssDir.on('change', function(ev) {
if(ev.type === 'deleted') {
del(path.relative('./', ev.path).replace('src/assets/css/','dist/assets/css/'));
}
});
});
So I'm 1) looking to combine my repetitive copy tasks into fewer tasks 2)have the delete file function work on all copy tasks and 3) optimize my watch task function to reduce repetition.
p.s., I've also noticed that if I add new files to the watch folders, it won't "recognize" them until I restart the watch command, so my method of syncing isn't exactly bulletproof. =/
Your thoughts are most appreciated.
Thanks!

gulp.watch doesn't catch a new files

I have the following gulpfile
var gulp = require('gulp');
var clean = require('gulp-clean');
var rename = require('gulp-rename');
var coffee = require('gulp-coffee');
var cache = require('gulp-cached');
var path = require('path');
var dist = './Test/public/';
var assets = './Test/assets/';
var paths = {
coffee: ['./**/*.coffee']
};
var coffeeTask = function () {
console.log('coffeeTask');
return gulp.src(paths.coffee, { cwd: assets + '**' })
.pipe(cache('coffee'))
.pipe(coffee({ bare: true }))
.pipe(rename({
extname: ".coffee.js"
}))
.pipe(gulp.dest(dist));
};
gulp.task('clean', function() {
return gulp.src(dist)
.pipe(clean());
});
gulp.task('coffee', ['clean'], coffeeTask);
gulp.task('coffee-watch', coffeeTask);
gulp.task('build', ['clean', 'coffee']);
gulp.task('watch', ['build'], function() {
var w = gulp.watch(paths.coffee, ['coffee-watch']);
w.on('change', function(evt) {
console.log(evt);
});
});
gulp.task('default', ['build']);
The key point of this configuration is use the same tasks for deploy and watch processes (read "build" and "watch" tasks).
The problem is that watch task doesn't catche any new coffee files. Edited or removed coffee files are processed well. According the following issue it should works. What the reason is?
Solved by using gulp-watch module:
watch(paths.coffee, function(evt) {
gulp.start('coffee-watch');
});
The question no is how to remove in dist folder deleted file in assets folder?

Laravel 5 extend Elixir to include browserify

My browserify workflow (from coffee to js, with browserify-shim and coffeeify) is like this:
I have 2 main files, app.coffee and _app.coffee, respectively for frontend and backend. Both files located in resources/coffee/front and resources/coffee/back (respectively). I'm trying to include browserify task in laravel elixir so the result file will be on public/js/app.js and public/js/_app.js and can be revision to the build folder later.
So far, I have tried to extend the elixir by creating a browserify.js file in elixir's node_modules ingredients folder. The content is:
var gulp = require('gulp');
var browserify = require('browserify');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
var logger = require('../../../gulp/util/bundleLogger');
var errors = require('../../../gulp/util/handleErrors');
var config = require('../../../gulp/config').browserify;
elixir.extend('browserify', function(callback) {
var bundleQueue = config.bundleConfigs.length;
var browserifyThis = function(bundleConfig) {
var bundler = browserify({
cache: {},
packageCache: {},
fullPaths: true,
entries: bundleConfig.entries,
extensions: config.extensions,
debug: config.debug
});
var bundle = function() {
logger.start(bundleConfig.outputName);
return bundler
.bundle()
.on('error', errors)
.pipe(source(bundleConfig.outputName))
.pipe(gulp.dest(bundleConfig.dest))
.on('end', finished);
}
if (global.isWatching) {
bundler = watchify(bundler);
bundler.on('update', bundle);
}
var finished = function() {
logger.end(bundleConfig.outputName);
if (bundleQueue) {
bundleQueue--;
if (bundleQueue === 0) {
callback();
}
}
}
return bundle();
};
config.bundleConfigs.forEach(browserifyThis);
});
Config for browserify is:
browserify: {
debug: true,
extensions: ['.coffee'],
watch: './resources/assets/coffee/{front,back}/**/*.coffee',
bundleConfigs: [
{
entries: './resources/assets/coffee/front/app.coffee',
dest: './public/js',
outputName: 'app.js'
},
{
entries: './resources/assets/coffee/back/app.coffee',
dest: './public/js',
outputName: '_app.js'
}]
}
Then in my gulp elixir task, I do this:
var gulp = require('gulp');
var elixir = require('laravel-elixir');
gulp.task('elixir', function() {
return elixir(function(mix) {
mix.sass('app.scss').browserify().version(['.public/css/app.css', './public/js/app.js', '.public/js/_app.js']);
});
});
This does not work because the callback function is not included in elixir (originally it is gulp's). Even if it is, the elixir watch will not listen to my original .coffee files (I'm trying to watch the entire coffee file located in resources/coffee/**/*.coffee).
So what I have thought as a solution is to re-run the entire elixir procedure if the file changed, like:
gulp.task('default', function() {
runSequence('coffeelint', 'browserify', 'elixir', 'images', 'watch');
});
and my watch task:
gulp.task('watch', function() {
gulp.watch(config.browserify.watch, ['coffeelint', 'default']);
gulp.watch(config.images.src, ['images']);
});
But the error is that, it says that sass() function in elixir cannot be linked to browserify(). Any idea how to do this?
Laravel elixir comes bundle with browserify so no need to do a require of browserify what you can do is
elixir(function(mix) {
mix.browserify(['main.js'],
'output directory',
'base-directory-if-different-from-public-folder');
});
You can't combine them, but you can run both.
//gulp.js in the root folder
var elixir = require('laravel-elixir');
var browserify = require('browserify');
elixir(function(mix) {
mix.sass(['app.scss'], 'public/css');
});
elixir(function(mix) {
mix.browserify(['app.js'], 'public/js');
});

Categories