How to save Gulp bundle in the source directory? - gulp

I am following the Fast browserify builds with watchify recipe and get it working, but would like my bundles to be written to the original source folder.
For example, I have the following code (taken directly from the recipe, but modified slightly)
// add custom browserify options here
var customOpts = {
entries: glob.sync("./dev/www/**/*-root.js"),
debug: true
};
var opts = _.assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
gulp.task('js', bundle); // so you can run `gulp js` to build the file
b.on('update', bundle); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
function bundle() {
return b.bundle()
// log errors if they happen
.on('error', gutil.log.bind(gutil, 'Browserify Error'))
.pipe(source('bundle.js'))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(sourcemaps.init({ loadMaps: true })) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(sourcemaps.write('./')) // writes .map file
.pipe(gulp.dest((file) => {return file.base;}));
//.pipe(gulp.dest('./dist'));
}
as you can see in the entries: glob.sync("./dev/www/**/*-root.js"), line, I am scanning for multiple files to be bundled.
The problem I am encountering is the .pipe(gulp.dest((_file: any) => {return file.base;})); line, which returns the root project folder's path, not the original source folder's path.
How can I obtain the source folder path for writing to?
Edit
I found http://fettblog.eu/gulp-browserify-multiple-bundles/ which describes how to create multiple bundles, but it doesn't use watchify. it looks like this issue might be a limitation of vinyl-source-stream?

It took a lot of effort, but I figured out a solution.
Generally I followed the pattern found at http://fettblog.eu/gulp-browserify-multiple-bundles/ but added caching of each browserify object created (one per page) plus added watchify to it.
Other things added in the following code:
livereload
dev server launch
typescript (tsx) compile (including chained sourcemaps)
full solution (typescript code):
import gulp = require("gulp");
import browserify = require("browserify");
var watchify = require("watchify");
import source = require("vinyl-source-stream");
import buffer = require("vinyl-buffer");
import gutil = require("gulp-util");
import sourcemaps = require("gulp-sourcemaps");
var sourcemapsApply = require("vinyl-sourcemaps-apply");
import _ = require("lodash");
import glob = require("glob");
import vinyl = require("vinyl");
import rename = require("gulp-rename");
var minifyify = require("minifyify");
import path = require("path");
var tsify = require("tsify");
var livereload = require("gulp-livereload");
var notify = require("gulp-notify");
var closureCompiler = require("gulp-closure-compiler");
import uglify = require("gulp-uglify");
import http = require("http");
var st = require("st"); //module for serving static files. used to create dev server. https://www.npmjs.com/package/st
var eventStream = require("event-stream"); //module for merging multiple vinyl streams to return one when finishing task. see http://fettblog.eu/gulp-browserify-multiple-bundles/
var rootPath = __dirname;
gulp.task("default", () => {
gulp.start("tsxDevWatch");
});
gulp.task("devServer", (done) => {
var rootPath = __dirname;
//start server
http.createServer(st({
path: rootPath,
index: true, //"index.html",
cache: false,
})).listen(8080,"localhost", done);
});
gulp.task("tsxDevWatch",["devServer"], () => {
livereload.listen();
//browserify+watchify of *-main.js files and compiles into *-main.bundle.js files IN SAME FOLDER
//created mostly following the pattern described here: http://fettblog.eu/gulp-browserify-multiple-bundles/
//but adds stupid source-filepath workaround for use with "source" (vinyl-source-stream needed for watchify)
/** the files we are going to browserify bundle*/
var entries = glob.sync("./dev/www/**/*-main.tsx", {
realpath: true, //so paths are absolute. This is required so our "bMaps" mappings stay intact, because watchify.on("update") always provides full filepath,
});
/** we create one browserify instance for each file we are bundling. this caches the browserify instance so it can be reused on watchify updates (decreasing compile time by A LOT) */
var bMaps: { [key: string]: BrowserifyObject } = {};
var tasks = entries.map((entry) => {
process.chdir(path.dirname(entry));
var browserifyOptions = {
entries: [entry],
debug: true,
plugin: [
watchify,
//tsify,
],
cache: {}, packageCache: {}, fullPaths: true // Requirement of watchify
};
var b = browserify(browserifyOptions);
b.plugin(tsify, { //options from here: http://json.schemastore.org/tsconfig
jsx: "react",
//inlineSourceMap: false, //sourcemap options don't seem to matter, seems to be set by browserify or something.
//sourceMap:true,
module: "commonjs",
target: "es5",
});
bMaps[entry] = b;
b.on('update', (updatedFiles: string[]) => {
console.log("!!!!!!!!!!!!!! \n!!!!!!!!!!!!!!!!!!!\n UPDATE CALLED FOR", JSON.stringify(updatedFiles));
var rebuildAll = false;
_.forEach(updatedFiles, (updatedFile) => {
if (bMaps[updatedFile] == null) {
//a dependency needs to be rebuilt, skip rebuilding anything that changed and do EVERYTHING
rebuildAll = true;
return false;
}
});
if (rebuildAll === false) {
_.forEach(updatedFiles, (updatedFile) => {
console.log(" ============= update()", updatedFile);
//find the b for this file
var _b = bMaps[updatedFile];
//do a bundle for it
_createTsXBundle(_b, updatedFile);
});
} else {
//this is a dependency, rebuild EVERYTHING!!!
_.forEach(bMaps, (value_b, key_entry) => {
_createTsXBundle(value_b, key_entry);
});
}
}); // on any dep update, runs the bundler
b.on('log', gutil.log); // output build logs to terminal
return _createTsXBundle(b, entry);
});
return eventStream.merge.apply(null, tasks);
});
/** worker to create a tsx bundle. used by a task */
function _createTsXBundle(b: BrowserifyObject, entry: string) {
process.chdir(path.dirname(entry));
console.log("================= doBundle()", entry);
var bundledStream = b.bundle();
bundledStream = <any>bundledStream.on('error', gutil.log.bind(gutil, 'Browserify Error'));
var currentSource: vinyl;
var targetName = path.basename(entry, ".tsx") + ".bundle.js";
bundledStream
.pipe(source(targetName))
.pipe(buffer()) //need this to support chaining our vinyl source file
////////////////////////////////////////
//// optional, remove if you dont want sourcemaps
// .pipe(sourcemaps.init({
// loadMaps: true,
// //debug: true
// })) // loads map from browserify file
///////////////////////// WORKS, BUT NEED TO ENABLE SOURCEMAPS plugin TO GET SOURCEMAPS
//// uglify
//.pipe(uglify({
// //preserveComments: "all",
// output:<any> {
// max_line_len: 300,
// //screw_ie8: false,
// //beautify: true,
// //comments: true,
// //bracketize: true,
// //quote_keys: true,
// //width: 120,
// //semicolons:true,
// },
// compress: {
// unsafe:true,
// },
//}))
//// Add transformation tasks to the pipeline here.
// .pipe(sourcemaps.write())
.pipe(gulp.dest((file: vinyl) => {
//console.log("GULP.DEST(file)\n base=", file.base, "\n cwd=", file.cwd, "\n path=", file.path, "\n relative=", file.relative);
return file.base;
}))
.pipe(livereload())
;
return bundledStream;
}

Related

gulp-inject injects nothing

Had to rewrite my gulpfile to gulp 4 but I'm facing problems of gulp-inject injecting nothing.
var gulp = require('gulp');
var svgstore = require('gulp-svgstore');
var svgmin = require('gulp-svgmin');
var rename = require('gulp-rename');
var cheerio = require('gulp-cheerio');
var inject = require('gulp-inject');
var path = require('path');
gulp.task('svgstore', function () {
var svgs = gulp
.src('static/svg/icons/src/*.svg')
.pipe(svgmin(function (file) {
var prefix = path.basename(file.relative, path.extname(file.relative));
return {
plugins: [{
convertPathData: false
}, {
cleanupIDs: {
prefix: prefix + '-',
minify: true
}
}]
}
}))
.pipe(cheerio(function ($, file) {
$('[fill]').attr('fill', 'currentColor');
}))
.pipe(svgstore({ inlineSvg: true }))
.pipe(gulp.dest('dest'));
function fileContents(filePath, file) {
return file.contents.toString();
}
return gulp
.src('layouts/partials/src/inline-svg.html')
.pipe(inject(svgs, { transform: fileContents }))
.pipe(gulp.dest('layouts/partials'));
});
// Watch asset folder for changes
gulp.task("watch", function () {
var watcher = gulp.watch("static/svg/icons/src/**/*")
watcher.on('all', gulp.series('svgstore'))
})
// Set watch as default task
gulp.task("default", gulp.series("watch"))
I can't figure out why. I tried logging fileContents and it just says [Function: fileContents].
I faced the same issue. When I debugged the gulp-inject package, I figured out that the gulp-inject plugin look up for the startTag and the endTag in the source file/s (in your case, the source file/s is gulp.src('layouts/partials/src/inline-svg.html')) to inject the content, and when I printed out the tags to the console, the result is:
startTag: /<!\-\-\s*inject\b:svg\b\s*\-\->/gi
endTag: /<!\-\-\s*endinject\s*\-\->/gi
Conclusion:
In the src file(i.e., inline-svg.html), insert the comments like below:
<div class="sr-only">
<!-- inject:svg --><!-- endinject -->
</div>
Then, try to run the gulp task and it should work.
Reference: https://github.com/w0rm/gulp-svgstore#inlining-svgstore-result-into-html-body
Gulp Version Used: ^5.0.4

Gulp default task unable to compress after copy

At first I thought this was related to dependency of tasks so I went with run-sequence and even tried defining dependencies within tasks themselves. But I cannot get the compress task to run after copy. Or, even if it says it did finish the compress task, the compression only works if I run compress in the task runner inside visual studio by itself. What else can I try to get it to compress after copy?
/// <binding BeforeBuild='default' />
/*
This file is the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. https://go.microsoft.com/fwlink/?LinkId=518007
*/
var gulp = require("gulp");
var debug = require("gulp-debug");
var del = require("del");
var uglify = require("gulp-uglify");
var pump = require("pump");
var runSequence = require("run-sequence");
var paths = {
bower: "./bower_components/",
lib: "./Lib/"
};
var modules = {
"store-js": ["store-js/dist/store.legacy.js"],
"bootstrap-select": [
"bootstrap-select/dist/css/bootstrap-select.css",
"bootstrap-select/dist/js/bootstrap-select.js",
"bootstrap-select/dist/js/i18n/*.min.js"
]
}
gulp.task("default", function (cb) {
runSequence("clean", ["copy", "compress"], cb);
});
gulp.task("clean",
function () {
return del.sync(["Lib/**", "!Lib", "!Lib/ReadMe.md"]);
});
gulp.task("compress",
function (cb) {
pump([
gulp.src(paths.lib + "**/*.js"),
uglify(),
gulp.dest(paths.lib)
], cb);
});
gulp.task("copy",
function (cb) {
prefixPathToModules();
copyModules();
cb();
});
function prefixPathToModules() {
for (var moduleIndex in modules) {
for (var fileIndex in modules[moduleIndex]) {
modules[moduleIndex][fileIndex] = paths.bower + modules[moduleIndex][fileIndex];
}
}
}
function copyModules() {
for (var files in modules) {
gulp.src(modules[files], { base: paths.bower })
.pipe(gulp.dest(paths.lib));
}
}
You use run-sequence and your code
runSequence("clean", ["copy", "compress"], cb);
run in such order
clean
copy and compress in parallel // that's why your code compresses nothing, because you have not copied files yet
cb
Write like this and compress will be after copy
runSequence("clean", "copy", "compress", cb);
I am not familiar with runSequence. But why don't you try the following. By this way your default task depends on compress and compress depends on copy. So, 'copy' will run first and then 'compress'
gulp.task('default', ['copy','compress'], function(cb){});
gulp.task('compress',['copy'], function(cb){});
Gulp returns a steam , since you are calling it in a for loop the stream is returned during the first iteration itself.
Update your copyModule to the following and you can try either runSequence like posted by Kirill or follow my approach
function copyModules() {
var inputFileArr = [];
for (var files in modules) {
inputFileArr = inputFileArr.concat(modules[files]);
};
return gulp.src(inputFileArr, { base: paths.bower })
.pipe(gulp.dest(paths.lib));
}

How to append the main.css file through Roots's Sage gulpfile?

I'm very new to gulp and seeing as how complex the Roots's Sage gulpfile is, I'm so lost as to which block of code I should put in my code in.
The usage examples for both packages is as follows:
CSS Shrink
var gulp = require('gulp');
var cssshrink = require('gulp-cssshrink');
gulp.task('default', function() {
gulp.src('css/**/*.css')
.pipe(cssshrink())
.pipe(gulp.dest('dist/css/'));
});
Combine Media Queries
var cmq = require('gulp-combine-media-queries');
gulp.task('cmq', function () {
gulp.src('src/**/*.css')
.pipe(cmq({
log: true
}))
.pipe(gulp.dest('dist'));
});
Manifest.json file:
{
"dependencies": {
"main.js": {
"files": [
"scripts/main.js"
],
"main": true
},
"main.css": {
"files": [
"styles/main.scss"
],
"main": true
},
"customizer.js": {
"files": [
"scripts/customizer.js"
]
},
"jquery.js": {
"bower": [
"jquery"
]
}
},
"config": {
"devUrl": "http://yaharga/"
}
}
I tried to put it in the Styles task at the gulpfile.js, but nothing happened:
// ## Globals
var argv = require('minimist')(process.argv.slice(2));
var autoprefixer = require('gulp-autoprefixer');
var browserSync = require('browser-sync').create();
var changed = require('gulp-changed');
var concat = require('gulp-concat');
var flatten = require('gulp-flatten');
var gulp = require('gulp');
var gulpif = require('gulp-if');
var imagemin = require('gulp-imagemin');
var jshint = require('gulp-jshint');
var lazypipe = require('lazypipe');
var less = require('gulp-less');
var merge = require('merge-stream');
var cssNano = require('gulp-cssnano');
var plumber = require('gulp-plumber');
var rev = require('gulp-rev');
var runSequence = require('run-sequence');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require('gulp-uglify');
var cmq = require('gulp-combine-media-queries');
var cssshrink = require('gulp-cssshrink');
// See https://github.com/austinpray/asset-builder
var manifest = require('asset-builder')('./assets/manifest.json');
// `path` - Paths to base asset directories. With trailing slashes.
// - `path.source` - Path to the source files. Default: `assets/`
// - `path.dist` - Path to the build directory. Default: `dist/`
var path = manifest.paths;
// `config` - Store arbitrary configuration values here.
var config = manifest.config || {};
// `globs` - These ultimately end up in their respective `gulp.src`.
// - `globs.js` - Array of asset-builder JS dependency objects. Example:
// ```
// {type: 'js', name: 'main.js', globs: []}
// ```
// - `globs.css` - Array of asset-builder CSS dependency objects. Example:
// ```
// {type: 'css', name: 'main.css', globs: []}
// ```
// - `globs.fonts` - Array of font path globs.
// - `globs.images` - Array of image path globs.
// - `globs.bower` - Array of all the main Bower files.
var globs = manifest.globs;
// `project` - paths to first-party assets.
// - `project.js` - Array of first-party JS assets.
// - `project.css` - Array of first-party CSS assets.
var project = manifest.getProjectGlobs();
// CLI options
var enabled = {
// Enable static asset revisioning when `--production`
rev: argv.production,
// Disable source maps when `--production`
maps: !argv.production,
// Fail styles task on error when `--production`
failStyleTask: argv.production,
// Fail due to JSHint warnings only when `--production`
failJSHint: argv.production,
// Strip debug statments from javascript when `--production`
stripJSDebug: argv.production
};
// Path to the compiled assets manifest in the dist directory
var revManifest = path.dist + 'assets.json';
// ## Reusable Pipelines
// See https://github.com/OverZealous/lazypipe
// ### CSS processing pipeline
// Example
// ```
// gulp.src(cssFiles)
// .pipe(cssTasks('main.css')
// .pipe(gulp.dest(path.dist + 'styles'))
// ```
var cssTasks = function(filename) {
return lazypipe()
.pipe(function() {
return gulpif(!enabled.failStyleTask, plumber());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.init());
})
.pipe(function() {
return gulpif('*.less', less());
})
.pipe(function() {
return gulpif('*.scss', sass({
outputStyle: 'nested', // libsass doesn't support expanded yet
precision: 10,
includePaths: ['.'],
errLogToConsole: !enabled.failStyleTask
}));
})
.pipe(concat, filename)
.pipe(autoprefixer, {
browsers: [
'last 2 versions',
'android 4',
'opera 12'
]
})
.pipe(cssNano, {
safe: true
})
.pipe(function() {
return gulpif(enabled.rev, rev());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.write('.', {
sourceRoot: 'assets/styles/'
}));
})();
};
// ### JS processing pipeline
// Example
// ```
// gulp.src(jsFiles)
// .pipe(jsTasks('main.js')
// .pipe(gulp.dest(path.dist + 'scripts'))
// ```
var jsTasks = function(filename) {
return lazypipe()
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.init());
})
.pipe(concat, filename)
.pipe(uglify, {
compress: {
'drop_debugger': enabled.stripJSDebug
}
})
.pipe(function() {
return gulpif(enabled.rev, rev());
})
.pipe(function() {
return gulpif(enabled.maps, sourcemaps.write('.', {
sourceRoot: 'assets/scripts/'
}));
})();
};
// ### Write to rev manifest
// If there are any revved files then write them to the rev manifest.
// See https://github.com/sindresorhus/gulp-rev
var writeToManifest = function(directory) {
return lazypipe()
.pipe(gulp.dest, path.dist + directory)
.pipe(browserSync.stream, {match: '**/*.{js,css}'})
.pipe(rev.manifest, revManifest, {
base: path.dist,
merge: true
})
.pipe(gulp.dest, path.dist)();
};
// ## Gulp tasks
// Run `gulp -T` for a task summary
// ### Styles
// `gulp styles` - Compiles, combines, and optimizes Bower CSS and project CSS.
// By default this task will only log a warning if a precompiler error is
// raised. If the `--production` flag is set: this task will fail outright.
gulp.task('styles', ['wiredep'], function() {
var merged = merge();
manifest.forEachDependency('css', function(dep) {
var cssTasksInstance = cssTasks(dep.name);
if (!enabled.failStyleTask) {
cssTasksInstance.on('error', function(err) {
console.error(err.message);
this.emit('end');
});
}
merged.add(gulp.src(dep.globs, {base: 'styles'})
.pipe(cssTasksInstance));
});
/************************* This is where I added it! *************************/
gulp.src(path.dist + 'styles/main.css')
.pipe(cssshrink())
.pipe(cmq())
.pipe(gulp.dest(path.dist + 'styles/main.css'));
return merged
.pipe(writeToManifest('styles'));
});
// ### Scripts
// `gulp scripts` - Runs JSHint then compiles, combines, and optimizes Bower JS
// and project JS.
gulp.task('scripts', ['jshint'], function() {
var merged = merge();
manifest.forEachDependency('js', function(dep) {
merged.add(
gulp.src(dep.globs, {base: 'scripts'})
.pipe(jsTasks(dep.name))
);
});
return merged
.pipe(writeToManifest('scripts'));
});
// ### Fonts
// `gulp fonts` - Grabs all the fonts and outputs them in a flattened directory
// structure. See: https://github.com/armed/gulp-flatten
gulp.task('fonts', function() {
return gulp.src(globs.fonts)
.pipe(flatten())
.pipe(gulp.dest(path.dist + 'fonts'))
.pipe(browserSync.stream());
});
// ### Images
// `gulp images` - Run lossless compression on all the images.
gulp.task('images', function() {
return gulp.src(globs.images)
.pipe(imagemin({
progressive: true,
interlaced: true,
svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}]
}))
.pipe(gulp.dest(path.dist + 'images'))
.pipe(browserSync.stream());
});
// ### JSHint
// `gulp jshint` - Lints configuration JSON and project JS.
gulp.task('jshint', function() {
return gulp.src([
'bower.json', 'gulpfile.js'
].concat(project.js))
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'))
.pipe(gulpif(enabled.failJSHint, jshint.reporter('fail')));
});
// ### Clean
// `gulp clean` - Deletes the build folder entirely.
gulp.task('clean', require('del').bind(null, [path.dist]));
// ### Watch
// `gulp watch` - Use BrowserSync to proxy your dev server and synchronize code
// changes across devices. Specify the hostname of your dev server at
// `manifest.config.devUrl`. When a modification is made to an asset, run the
// build step for that asset and inject the changes into the page.
// See: http://www.browsersync.io
gulp.task('watch', function() {
browserSync.init({
files: ['{lib,templates}/**/*.php', '*.php'],
proxy: config.devUrl,
snippetOptions: {
whitelist: ['/wp-admin/admin-ajax.php'],
blacklist: ['/wp-admin/**']
}
});
gulp.watch([path.source + 'styles/**/*'], ['styles']);
gulp.watch([path.source + 'scripts/**/*'], ['jshint', 'scripts']);
gulp.watch([path.source + 'fonts/**/*'], ['fonts']);
gulp.watch([path.source + 'images/**/*'], ['images']);
gulp.watch(['bower.json', 'assets/manifest.json'], ['build']);
});
// ### Build
// `gulp build` - Run all the build tasks but don't clean up beforehand.
// Generally you should be running `gulp` instead of `gulp build`.
gulp.task('build', function(callback) {
runSequence('styles',
'scripts',
['fonts', 'images'],
callback);
});
// ### Wiredep
// `gulp wiredep` - Automatically inject Less and Sass Bower dependencies. See
// https://github.com/taptapship/wiredep
gulp.task('wiredep', function() {
var wiredep = require('wiredep').stream;
return gulp.src(project.css)
.pipe(wiredep())
.pipe(changed(path.source + 'styles', {
hasChanged: changed.compareSha1Digest
}))
.pipe(gulp.dest(path.source + 'styles'));
});
// ### Gulp
// `gulp` - Run a complete build. To compile for production run `gulp --production`.
gulp.task('default', ['clean'], function() {
gulp.start('build');
});
Ideally, I would need to capture the main.css code and implement the cmq and cssshrink to it just before it is finally exported into the distribution folder.
I followed the post on Roots Discourse to help me do it; will update with full answer once done.

Gulp Browserify with glob and uglify/factor-bundle

I'm currently getting into browserify. I like it so far but before I start using it I want to automate it. Gulp is the build system of my choice.
So what I actually want to do is:
Get js/app/**.js, bundle it to js/bundle/ and extract common dependencies into js/bundle/common.js. In addition uglify everything and add source maps.
Well. The gulp support for browserify kinda seems poor, at least my google researches were pretty disappointing.
Anyway. What I've got so far.
var gulp = require('gulp'),
browserify = require('browserify'),
factor = require('factor-bundle');
// ...
// gulp task
return browserify({
entries: ['js/app/page1.js', 'js/app/page2.js'],
debug: true
})
.plugin(factor, {
o: ['js/bundle/page1.js', 'js/bundle/page2.js']
})
.bundle()
.pipe(source('common.js'))
.pipe(gulp.dest('js/bundle/'));
Well this is neither uglifying nor adding sourcemaps and much less using a glob pattern. I can find an official recipe which shows me how to use the pipe to add additional transformations like uglify. But it's only for a single file.
as an outputs parameter to factor-bundle, use streams instead of file paths. You can do whatever you want with the streams then.
var indexStream = source("index.js");
var testStream = source("tests.js");
var commonStream = bundler.plugin('factor-bundle', { outputs: [indexStream, testStream] })
.bundle()
.pipe(source('common.js'));
return merge(indexStream, commonStream, testStream)
.pipe(buffer())
.pipe(sourcemaps.init({ debug: true, loadMaps: true }))
.pipe(uglify())
.pipe(gulp.dest('js/bundle/'))
Thanks to Liero's answer, I got something very similar working. Here's the complete gulpfile:
const gulp = require('gulp');
const browserify = require('browserify');
const factor = require('factor-bundle');
const source = require('vinyl-source-stream');
const sourcemaps = require('gulp-sourcemaps');
const buffer = require('gulp-buffer');
const merge = require('gulp-merge');
gulp.task('bfb', function () {
const fejs = 'public/javascripts/' // location of source JS
const fejsb = fejs + 'b/'; // location of bundles
const modules = [ // aka entry points
'accounts',
'invoice',
'invoices',
// etc...
];
const inputs = [];
const streams = [];
modules.forEach(function (module) {
inputs.push(fejs + module + '.js');
streams.push(source(module + '.js'));
});
const bundler = browserify(inputs, {});
const commonStream = bundler.plugin(factor, { outputs: streams })
.bundle()
.pipe(source('common.js'));
streams.push(commonStream);
return merge(streams)
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
//.pipe(uglify()) // haven't tested this bit
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest(fejsb));
});

Prepend custom strings to JS files while concatenating

I am trying to migrate our build process to gulp from existing custom bash build script. We concatenate several unminified opensource JS files like bootstrap, lazyload, ... and our own JS files. We uglify each JS file (removing their licenses as well) in an order, prepend custom license text to some of them as required and concatenate to create the output JS file. The custom license text are currently kept as strings in the bash script.
How to achieve this in gulp without creating intermediate files?
Will it also be possible to selectively avoid uglifying some JS scripts?
Ok, I spent some time learning up gulp and it's plugins and here is a working version. The points here are using the foreach on each JS retrieved from the JSON config file, pushing the streams to an array and finally using merge on the array streams.
Here are the plugins used and the JSON structure defined:
var gulp = require('gulp');
var each = require('foreach');
var debug = require('gulp-debug');
var gulpif = require('gulp-if');
var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat-util');
var es = require('event-stream');
var cache = require('gulp-cached');
var remember = require('gulp-remember');
// Structure that holds the various JS files and their handling
var Config = {
js: {
output_dir: 'path/to/output/file/',
output_file: 'outputfile.js',
src: [{
name: 'bootstrap',
src: ['path/to/bootstrap.js'],
run_lint: false,
run_uglify: true,
license: '/* bootstrap license */'
}, {
name: 'lazyload',
src: ['path/to/lazyload.js'],
run_lint: false,
run_uglify: true,
license: '/* lazyload license */'
}, {
name: 'inhouse-js',
src: ['path/to/inhouse/ih-1.js', 'path/to/inhouse/ot/*.js'],
run_lint: true,
run_uglify: true,
license: ''
}]
}
}
The build task, with caching as we will be using it in development also:
gulp.task('build', ['build:js']);
gulp.task('build:js', function() {
var streams = [];
each(Config.js.src, function(val, key, array) {
var stream = gulp.src(val.src)
.pipe(cache('scripts'))
.pipe(gulpif(val.run_lint, jshint('.jshintrc')))
.pipe(gulpif(val.run_lint, jshint.reporter('jshint-stylish')))
.pipe(gulpif(val.run_uglify, uglify({
compress: {
drop_console: true
}
})))
.pipe(concat.header(val.license + '\n'));
streams.push(stream);
});
es.merge.apply(this, streams)
.pipe(remember('scripts')) // add back all files to the stream
.pipe(concat(Config.js.output_file))
.pipe(gulp.dest(Config.js.output_dir));
});
If you would like to debug, a good option will be to insert debug plugin like this example around the 'gulp-remember' plugin call above:
.pipe(debug({title: 'before remember:'}))
.pipe(remember('scripts')) // add back all files to the stream
.pipe(debug({title: 'after remember:'}))
And here's the watch task:
gulp.task('watch', function() {
var watch_list = [];
each(Config.js.src, function(val, key, array) {
watch_list.push.apply(watch_list, val.src);
});
// Watch .js files
var watcher = gulp.watch(watch_list, ['build']);
watcher.on('change', function(event) {
console.log('File '+ event.path +' was '+ event.type +', running tasks..');
if (event.type === 'deleted') { // if a file is deleted, forget it
delete cache.caches['scripts'][event.path];
remember.forget('scripts', event.path);
}
})
});
You can use lazypipe() to reuse parts of the build:js task with normal build.