How do you use browserify in a Gulp task? - javascript

I'm pretty new to Gulp, but by following this tutorial I set up a Gulp task that is meant to browserify javascript files in a particular directory and pipe them to a different directory - pretty simple. I've looked a few other tutorials, but this method seemed to be the most concise. Here is my code:
var gulp = require('gulp');
var browserify = require('browserify');
var transform = require('vinyl-transform');
gulp.task('js', function() {
var browserified = transform(function(filename) {
return browserify(filename).bundle();
});
return gulp.src(['./public/js/src/**/*.js'])
.pipe(browserified)
.pipe(gulp.dest('./public/js/dist'));
});
The above code is very similar to many other implementations of this sort I've seen, but when I try running it with gulp js, it produces the following error:
[15:47:13] Using gulp file
~/development/launchpad/workshop/gulpfile.js
[15:47:13] Starting 'js'...
_stream_readable.js:540
var ret = dest.write(chunk);
^
TypeError: undefined is not a function
at Producer.ondata (_stream_readable.js:540:20)
at Producer.emit (events.js:107:17)
at Producer.Readable.read (_stream_readable.js:373:10)
at flow (_stream_readable.js:750:26)
at resume_ (_stream_readable.js:730:3)
at _stream_readable.js:717:7
at process._tickCallback (node.js:355:11)
Does anyone know what might cause this error?
(As a side note, I'd like to look at the files from the stack trace to try to figure out what is going on here, but searching for _stream_readable.js in Spotlight yields about 20 files of that name, all seemingly Node modules. Is there a way to determine the full path of a file in a stack trace?)

var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
gulp.task('browserify', function() {
return browserify('lib/front/app.js')
.bundle()
//Pass desired output filename to vinyl-source-stream
.pipe(source('bundle.js'))
// Start piping stream to tasks!
.pipe(gulp.dest('public/build/'));
});

If you want browserify to work with gulp. dest and create a file where we specify it via .pipe (gulp.dest ('src/js')),
then you need to download vinyl-source-stream and throw it in .pipe(source('bundle.js')),
but actually in browserify, namely the bundle method accepts callback and neither dest nor source is needed
browserify({
entries: jsFile,
basedir: "src/js/dev",
debug: true,
})
.transform(babelify, {
presets: ['#babel/preset-env'],
})
.bundle((err, buffer) => {
let event = new EventEmitter();
if (err) {
event.emit('error',err)
}
else {
let data = minify(buffer.toString(), {}).code;
fs.createWriteStream('./src/js/bundle.js').write(data)
console.dir(222);
bs.reload()
}
})

Unfortunately, this is an issue with browserify/gulp, and there's nothing that vinyl-transform can do. The solution is to use vinyl-source-stream and vinyl-buffer:
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var glob = require('node-glob');
gulp.task('browserify', function (cb) {
glob('./src/**/*.js', {}, function (err, files) {
var b = browserify();
files.forEach(function (file) {
b.add(file);
});
b.bundle().
.pipe(source('output.js'))
.pipe(gulp.dest('./dist'));
cb();
})
});
More information here.

Related

Trouble with splitting gulpfile.js into multiple files in Gulp 4

I am a beginner to Javascript and Gulp. Am learning this based on a udemy course in which Gulp 3 is being used, and I've been looking at docs to convert the code to Gulp 4. It's been fun so far since I am learning more when I am doing the conversions myself, but am stuck on this one. Wonder if you guys can offer some advice.
Issue: When I split the gulpfile.js into separate files to organise my files better, it starts throwing errors. Code below.
styles.js
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var gulp = require('gulp'),
browserSync = require('browser-sync').create();
function cssInject(cb) {
return gulp.src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
function browserSyncReload(cb) {
browserSync.reload();
cb();
}
function watch(cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', browserSyncReload);
watch('./app/assets/styles/styles.css', gulp.series(cssInject, styles));
cb();
}
exports.browserSyncReload = browserSyncReload;
exports.watch = watch;
gulpfile.js
var stylesTasks = require('./gulp/tasks/styles.js'),
watchTasks = require('./gulp/tasks/watch.js');
exports.watch = watchTasks.watch;
exports.styles = stylesTasks.styles;
exports.browserSyncReload = watchTasks.browserSyncReload;
When I run "gulp watch", this is what I get.
error
$ gulp watch
[21:14:28] Using gulpfile ~/Projects/travel-site/gulpfile.js
[21:14:28] Starting 'watch'...
internal/async_hooks.js:195
function emitInitNative(asyncId, type, triggerAsyncId, resource) { ^
RangeError: Maximum call stack size exceeded
(Use `node --trace-uncaught ...` to show where the exception was thrown)
I found another post with almost identical code, but with a different error - which happened to be one of the errors i was getting earlier as well, and have followed the solution mentioned in that post - and that's when I get this error. Here's the link to the post.
Any help is much appreciated. Thanks for your time.
I have a full article that shows many how to regarding going from gulp3 to gulp4, I think you are going to find everything you need there
But basically, I think you need to take a look at these modules :
gulp-task-loader-recursive
gulp4-run-sequence
require-dir
Then, from a gulp.js perspective, you can end up with something like this :
// gulpfile.js
global.config = require('./gulp/config/config.json');
require('events').EventEmitter.prototype._maxListeners = 1000;
require('require-dir')('./gulp/tasks/styles');
require('require-dir')('./gulp/tasks/watch');
//... etc ...
So you would be able to then create your styles task and export it :
var gulp = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
function styles(cb) {
return gulp.src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(gulp.dest('./app/temp/styles'));
cb();
}
const stylesTask = task('styles', styles);
exports.stylesTask = stylesTask;
You can then validate its recognized by gulp :
gulp --tasks
If you correctly see your styles tasks, you should now be able to run your task by running :
gulp styles
Repeat those steps for the watch task.
Answering my own question feels wierd, but I found the solution after playing with it for couple of days. See below.
I needed to import styles into watch.js, and not gulpfile.js. That was my first mistake. To do this, I added the below line to watch.js
var styles = require('./styles').styles;
Then my gulpfile.js only needed two lines
gulpfile.js
var watchTask = require('./gulp/tasks/watch').watch;
exports.default = watchTask;
I also removed the variable gulp, instead created variables for src and dest. So, the rest of the code looked like below.
styles.js
var {src, dest} = require('gulp'),
postcss = require('gulp-postcss'),
autoprefixer = require('autoprefixer'),
cssvars = require('postcss-simple-vars'),
nested = require('postcss-nested'),
cssImport = require('postcss-import');
const styles = function (cb) {
return src('./app/assets/styles/styles.css')
.pipe(postcss([cssImport, cssvars, nested, autoprefixer]))
.pipe(dest('./app/temp/styles'));
cb();
}
exports.styles = styles;
watch.js
var styles = require('./styles').styles;
var {src, series, watch} = require('gulp'),
browserSync = require('browser-sync').create();
const cssInject = function (cb) {
return src('./app/temp/styles/styles.css')
.pipe(browserSync.stream());
cb();
}
const reload = function (cb) {
browserSync.reload();
cb();
}
const watchTask = function (cb) {
browserSync.init({
notify: false,
server: {
baseDir: "app"
}
});
watch('./app/index.html', reload);
watch('./app/assets/styles/styles.css', series(cssInject, styles));
cb();
}
exports.watch = watchTask;
Hence resolved! hope this helps someone else.

How to make Gulp watch monitoring files?

I have a simple gulpfile.js, that defines only two tasks, buildLess and watchFiles:
var gulp = require('gulp');
var less = require('gulp-less');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
var filter = require('gulp-filter');
function buildLess(done) {
const fileFilter = filter(['**/*', '!**/mixins.less', '!**/variables.less']);
gulp.src('./public/less/*.less')
.pipe(fileFilter)
.pipe(plumber())
.pipe(less())
.pipe(gulp.dest('./public/css/'))
;
done();
};
function watchFiles() {
gulp.watch(['public/less/*.less'], gulp.series('build-less'));
// gulp.watch(['./public/less/*.less'], gulp.series(buildLess));
};
gulp.task('build-less', buildLess);
gulp.task('watch-files', watchFiles);
The first one ($ gulp build-less) is working fine. The watchFiles ($ gulp watch-files) can be started and doesn't cause any errors, but changes on the public/less/style.less are ignored.
What is wrong at this gulpfile.js and how to get the watch-files task working?
The gulp.series API allows you to pass a string of a previously registered task. In your code, you haven't registered build-less yet.
var gulp = require('gulp');
var less = require('gulp-less');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
var filter = require('gulp-filter');
function buildLess(done) {
const fileFilter = filter(['**/*', '!**/mixins.less', '!**/variables.less']);
gulp.src('./public/less/*.less')
.pipe(fileFilter)
.pipe(plumber())
.pipe(less())
.pipe(gulp.dest('./public/css/'))
;
done();
};
gulp.task('build-less', buildLess);
function watchFiles() {
gulp.watch(['public/less/*.less'], gulp.series('build-less'));
// gulp.watch(['./public/less/*.less'], gulp.series(buildLess));
};
gulp.task('watch-files', watchFiles);
I would note that Gulp does not recommend using the gulp.task API anymore to register tasks, but instead to use exports.
Secondly, you don't need gulp-watch, as gulp now comes with its own gulp.watch method (which you are already using).
Lastly, you should make sure to your correctly signaling async completion in your buildLess function. Below, I've changed that function to return a Stream, rather than calling a done() callback since as you have it written, you have a race condition where done() may be called before the Less compilation has finished.
var gulp = require('gulp');
var less = require('gulp-less');
var plumber = require('gulp-plumber');
var filter = require('gulp-filter');
function buildLess() {
const fileFilter = filter(['**/*', '!**/mixins.less', '!**/variables.less']);
return gulp
.src('./public/less/*.less')
.pipe(fileFilter)
.pipe(plumber())
.pipe(less())
.pipe(gulp.dest('./public/css/'));
}
exports['build-less'] = buildLess;
function watchFiles() {
gulp.watch(['public/less/*.less'], buildLess);
}
exports['watch-files'] = watchFiles;
Overall, I'd go through Gulp's documentation. They recently updated their website, and updated their documentation along with it. Going through that might clear up some other questions you may be having.

gulp-load-plugins.sourcemaps.init() TypeError: Cannot read property 'init' of undefined

I'm trying to adapt a gulp file to my purposes and I'm running into issues. I only care about one task:
gulp.task('js:browser', function () {
return mergeStream.apply(null,
Object.keys(jsBundles).map(function(key) {
return bundle(jsBundles[key], key);
})
);
});
It is using browserify to condense my bundle into a usable single file. It uses these two methods and this object:
function createBundle(src) {
//if the source is not an array, make it one
if (!src.push) {
src = [src];
}
var customOpts = {
entries: src,
debug: true
};
var opts = assign({}, watchify.args, customOpts);
var b = watchify(browserify(opts));
b.transform(babelify.configure({
stage: 1
}));
b.transform(hbsfy);
b.on('log', plugins.util.log);
return b;
}
function bundle(b, outputPath) {
var splitPath = outputPath.split('/');
var outputFile = splitPath[splitPath.length - 1];
var outputDir = splitPath.slice(0, -1).join('/');
console.log(outputFile);
console.log(plugins);
return b.bundle()
// log errors if they happen
.on('error', plugins.util.log.bind(plugins.util, 'Browserify Error'))
.pipe(source(outputFile))
// optional, remove if you don't need to buffer file contents
.pipe(buffer())
// optional, remove if you dont want sourcemaps
.pipe(plugins.sourcemaps.init({loadMaps: true})) // loads map from browserify file
// Add transformation tasks to the pipeline here.
.pipe(plugins.sourcemaps.write('./')) // writes .map file
.pipe(gulp.dest('build/public/' + outputDir));
}
var jsBundles = {
'js/polyfills/promise.js': createBundle('./public/js/polyfills/promise.js'),
'js/polyfills/url.js': createBundle('./public/js/polyfills/url.js'),
'js/settings.js': createBundle('./public/js/settings/index.js'),
'js/main.js': createBundle('./public/js/main/index.js'),
'js/remote-executor.js': createBundle('./public/js/remote-executor/index.js'),
'js/idb-test.js': createBundle('./public/js/idb-test/index.js'),
'sw.js': createBundle(['./public/js/sw/index.js', './public/js/sw/preroll/index.js'])
};
When I run the gulp task js:bower I get the following error coming from the the .pipe(plugins.sourcemaps.init({loadMaps: true})) expression:
TypeError: Cannot read property 'init' of undefined
I know that the lines are optional and I can just comment them out, but I do want them. When I run the code in the example file it works properly, when I run it in my gulp file it gives me the error. Any suggestions on what I might be missing? Thanks!
gulp-load-plugins analyzes the contents of your package.json file to find out which Gulp plugins you have installed. Make sure that gulp-sourcemaps is among the "devDependencies" defined there. If not run
npm install --save-dev gulp-sourcemaps
There's a small chance that your problem is related to lazy loading the sourcemaps plugin. If the above doesn't help try requiring gulp-load-plugins like this:
var plugins = require('gulp-load-plugins')({lazy:false});

Using gulp.watch throws "TypeError: Object #<Object> has no method 'watch'"

So I've added a watch task to my gulpfile.js that looks like this:
gulp.task('watch', function(){
gulp.watch('src/style/*.less', ['css']);
});
but when I run it (gulp watch) I get the following error thrown in my face:
PS C:\Projects\web\basic> gulp watch
[21:28:42] Using gulpfile C:\Projects\web\basic\gulpfile.js
[21:28:42] Starting 'watch'...
[21:28:42] 'watch' errored after 226 μs
[21:28:42] TypeError: Object #<Object> has no method 'watch'
at Gulp.watch (C:\Projects\web\basic\node_modules\gulp\index.js:40:14)
at Gulp.<anonymous> (C:\Projects\web\basic\gulpfile.js:37:7)
at module.exports (C:\Projects\web\basic\node_modules\gulp\node_modules\orchestrator\lib\runTask.js:34:7)
at Gulp.Orchestrator._runTask (C:\Projects\web\basic\node_modules\gulp\node_modules\orchestrator\index.js:273:3)
at Gulp.Orchestrator._runStep (C:\Projects\web\basic\node_modules\gulp\node_modules\orchestrator\index.js:214:10)
at Gulp.Orchestrator.start (C:\Projects\web\basic\node_modules\gulp\node_modules\orchestrator\index.js:134:8)
at C:\Users\Magnus\AppData\Roaming\npm\node_modules\gulp\bin\gulp.js:129:20
at process._tickCallback (node.js:415:13)
at Function.Module.runMain (module.js:499:11)
at startup (node.js:119:16)
As I've come to understand watch is a built-in function in gulp so what am I doing wrong here? The only other solutions to this dilemma I've seen is Linux specific (and presumable so is the cause for the problem). It is described in this SO-thread, but I'm using Windows and I can't see how that problem could be showing up in a Windows environment.
Also, I've looked through the Gulp index.js-file for project installation and it does contain a watch prototype, but the problems seems (according to the error message) to come from the final line in the watch function:
Gulp.prototype.watch = function(glob, opt, fn) {
if (typeof opt === 'function' || Array.isArray(opt)) {
fn = opt;
opt = null;
}
// Array of tasks given
if (Array.isArray(fn)) {
return vfs.watch(glob, opt, function() {
this.start.apply(this, fn);
}.bind(this));
}
return vfs.watch(glob, opt, fn);
};
It's the return vfs.watch(glob, opt, fn);-line that causes the crash (it's line 40). vfs in this case is a variable that contains vinyl-fs and looks like this:
var vfs = require('vinyl-fs');
But even after manually installing it both in my project and globally it still doesn't work. Anyone that has any idea what might be causing this crash?
EDIT: The full gulpfile.js:
var gulp = require('gulp'),
less = require('gulp-less'),
concat = require('gulp-concat'),
uglify = require('gulp-uglify');
var cssPath = 'src/style/*.less';
var jsPath = 'src/js/*.js';
var htmlPath = 'src/index.htm';
var assetPath = 'src/assets/*';
gulp.task('css', function() {
return gulp.src(cssPath) //Get all less files from src/style/
.pipe(less()) //Pass them on to less
.pipe(concat('style.css')) //Concat all files to one big style.css-file
.pipe(gulp.dest('dist/style')) //Pass the less result to gulp so it can be moved to dist/css
});
gulp.task('js', function(){
return gulp.src(jsPath) //Get all the javascript files from src/js/
.pipe(uglify()) //Pass them on to uglify
.pipe(concat('all.js')) //Concat all the files into one javascript file
.pipe(gulp.dest('dist/js')) //Pass the result to gulp so it can be moved to dist/js
});
gulp.task('html', function(){
return gulp.src(htmlPath)
.pipe(gulp.dest('dist'))
});
gulp.task('assets', function(){
return gulp.src(assetPath)
.pipe(gulp.dest('dist/assets'))
});
gulp.task('watch', function(){
gulp.watch(cssPath, ['css']);
gulp.watch(jsPath, ['js']);
gulp.watch(htmlPath, ['html']);
gulp.watch(assetPath, ['assets']);
});
gulp.task('default', ['css', 'js', 'html', 'assets']);
Thanks to #ezrepotein and #entre for helping me out.
The solution was simply to reinstall node and then uninstall and reinstall all gulp components in the project.
After that it worked out well so something must've gone wrong during installation of either node or the gulp components.

Chain Gulp glob to browserify transform

I have a project with a few relatively disjoint pages, each including their own entry point script. These scripts require a number of others using commonjs syntax, and need to be transformed by 6to5 and bundled by browserify.
I would like to set up a gulp task that captures all the files matching a pattern and passes them on to the bundler, but I'm not sure how to pass files from gulp.src to browserify(filename).
My gulpfile looks like:
var gulp = require("gulp");
var browserify = require("browserify");
var to5browserify = require("6to5-browserify");
var source = require("vinyl-source-stream");
var BUNDLES = [
"build.js",
"export.js",
"main.js"
];
gulp.task("bundle", function () {
/* Old version, using glob:
return gulp.src("src/** /*.js")
.pipe(sixto5())
.pipe(gulp.dest("dist"));
*/
// New version, using array:
return BUNDLES.map(function (bundle) {
return browserify("./src/" + bundle, {debug: true})
.transform(to5browserify)
.bundle()
.pipe(source(bundle))
.pipe(gulp.dest("./dist"));
});
});
gulp.task("scripts", ["bundle"]);
gulp.task("html", function () {
return gulp.src("src/**/*.html")
.pipe(gulp.dest("dist"));
});
gulp.task("styles", function () {
return gulp.src("src/**/*.css")
.pipe(gulp.dest("dist"));
});
gulp.task("default", ["scripts", "html", "styles"]);
This seems to work, but isn't maintainable: I'll be adding more scripts relatively soon, and don't want to add them to the array every time.
I've tried using gulp.src(glob).pipe within the browserify call and piping after calling (shown here), and gulp.src(glob).map (method doesn't exist).
How can you chain gulp.src with a name-based transformer like browserify?
Use through2 to make a one-off custom plugin stream that does all of the dirty work.
Unfortanately vinyl-transform and vinyl-source-stream and the solutions that go along with those have flaws so we have to go for something custom.
var gulp = require('gulp');
var through = require('through2');
var browserify = require('browserify');
gulp.task('bundle', function() {
var browserified = function() {
return through.obj(function(chunk, enc, callback) {
if(chunk.isBuffer()) {
var b = browserify(chunk.path);
// Any custom browserify stuff should go here
//.transform(to5browserify);
chunk.contents = b.bundle();
this.push(chunk);
}
callback();
});
};
return gulp.src(['./src/**/*.js'])
.pipe(browserified())
.pipe(gulp.dest('dest'));
});
You can specify globs in your BUNDLES array as well as exclude any files:
var BUNDLES = [
"app/**/*.js",
"export.js",
"app/modules/**/*.js",
"!app/modules/excluded/*.js"
];

Categories

Resources