Build script with Browserify creates an empty file - javascript

I have a simple build script that supposedly should pack all my js modules into a single file using browserify. I have the following code ( inspired from http://www.forbeslindesay.co.uk/post/46324645400/standalone-browserify-builds)
function _browserify(srcPath, distPath) {
var browserify = require('browserify');
var b = new browserify();
b.add(srcPath);
b.bundle().pipe(_fs.createWriteStream(distPath));
console.log(' '+ distPath +' built.');
}
But when I run it, I get a completely empty file. Any idea why?

okay, definitely spent waaaay too much of my evening on this, but this turns out to be an async issue. you're most likely getting an error in there somewhere, but grunt is killing off the process before the error callback has a chance to be called. grunt provides a nifty async method on each task's context that you have to use to let grunt know that this is an async task (and therefore needs to wait for everything to be finito). something like...
grunt.registerTask('build', function () {
var done = this.async();
browserify({ debug: true })
.add('./src/main.js')
.bundle()
.on('error', function (err) {
console.log(err);
})
.pipe(fs.createWriteStream('./target/bundle.js')
.on('end', done);
});

Related

Upgrading to Gulp 4 from Gulp 3

I've attempted to update the gulpfile below to Gulp v4 from v3 but am still getting an error: AssertionError [ERR_ASSERTION]: Task never defined: client
Not sure what I am missing but realise that the functions may not be written correctly. The tasks in series are correct I believe: gulp.task('build', gulp.series('client', 'sass')); for example.
// gulpfile.js
var gulp = require('gulp'),
concat = require('gulp-concat'),
browserify = require('gulp-browserify'),
rename = require('gulp-rename'),
nodemon = require('gulp-nodemon'),
sass = require('gulp-sass');
gulp.task('build', gulp.series('client', 'sass'));
gulp.task('watch', gulp.series('client-watch', 'sass-watch'));
gulp.task('server', function () {
nodemon({
script: 'server/index',
ext: 'js json'
});
});
gulp.task('client', function () {
gulp.src('client/js/main.js')
.pipe(browserify({
transform: ['hbsfy'],
extensions: ['.hbs']
}))
.pipe(rename('hearthclone.js'))
.pipe(gulp.dest('./client/build'));
});
gulp.task('client-watch', function () {
gulp.watch('client/js/**/*.js', ['client']);
});
gulp.task('sass', function () {
gulp.src('client/**/*.scss')
.pipe(sass())
.pipe(concat('style.css'))
.pipe(gulp.dest('client/assets/css'));
});
gulp.task('sass-watch', function () {
gulp.watch('client/**/*.scss', ['sass']);
});
gulp.task('default', gulp.series('build', 'server', 'watch'));
When you use the gulp.task form of defining tasks (rather that as functions) then you cannot refer to those tasknames until after they have been declared. That would be a forward reference (see below). So just put your
gulp.task('build', gulp.series('client', 'sass'));
gulp.task('watch', gulp.series('client-watch', 'sass-watch'));
after all those tasks have been defined. I recommend right before the default task line.
See https://gulpjs.com/docs/en/api/series#forward-references
Forward references
A forward reference is when you compose tasks, using string
references, that haven't been registered yet. This was a common
practice in older versions, but this feature was removed to achieve
faster task runtime and promote the use of named functions.
In newer versions, you'll get an error, with the message "Task never
defined", if you try to use forward references. You may experience
this when trying to use exports for your task registration and
composing tasks by string. In this situation, use named functions
instead of string references.

Execute a JS file (with logs, etc...) inside another NodeJS process

Here is my problem, I want to create a CLI that automatically runs a test. Without the CLI, I'm able to run everything perfectly with the node command:
node test.js
Basically, I want to do the exact same thing as the command before, so I googled for a technique that does this. I found this:
#!/usr/bin/env node
'use strict';
const options = process.argv;
const { execFile } = require('child_process');
const child = execFile('node', ['../dist/test.js'], (error, stdout, stderr) => {
if (error) {
throw error;
}
console.log(stdout);
});
This method doesn't work for me because, in the test.js file, I'm using the ora package. And because this package is making real-time animations, it doesn't come in stdout.
Is there any way of executing in real time (without subprocess) my test.js using Node? I'm open to other methods, but I want to publish the CLI on NPM, so keep in mind that it has to be in JavaScript 😊.
You can find every file that I've talked here on GitHub. Normally, you wouldn't need this link, but I'm giving it to you if you need to have a closer look.
You should simply call your test() function from your CLI code, after requiring the module that defines it. Have a look at mocha and jasmine: you will see that while both tools provide a CLI, they also provide instructions for invoking the test frameworks from arbitrary JS code.
I can't think of a way without a sub-process. but this may help.
The child process exec will not work with the continuous output commands as it buffers the output the process will halt when that buffer is full.
The suitable solution is spwan :
var spwan = require('child_process').spwan
var child = spwan('node', ['../dist/test.js'])
child.stdout.on('data', function(data) {
console.log(data)
})
child.stderr.on('data', function(data) {
console.log(data)
})
Here is my solution, you can use the fs library to get the code of the file, and then, you simply use eval to execute in the same process.
const fs = require("fs");
function run(file) {
fs.readFile(file, (err, data) => {
eval(data.toString('utf8'))
})
}

Stop gulp pipeline from executing when jshint fails

I am using gulp to run a developer web server and I want the following tasks to happen when a change occurs to a javascript file:
Lint javascript
if there are no errors, copy files to .tmp/
reload webpage
I've seen in other examples to use jshint.reporter('fail') as shown in the code below, to stop the rest of the pipeline.
var jshint = require('gulp-jshint'),
watch = require('gulp-watch');
watch('resources/js/src/**/*.js', function() {
util.log('Changes to js source files detected');
}).pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(jshint.reporter('fail'))
.pipe(gulp.dest('.tmp/js/src/'))
.pipe(connect.reload());
However when I do this it appears to always stop regardless of whether or not the lint was a success. So, how can I end the pipeline after a failed linting?
Not sure if this is the best solution, but it works:
var map = require('map-stream');
...
var copyAndReload = map(function (file, cb) {
if (file.jshint.success) {
gulp.src('resources/js/src/**/*.js')
.pipe(gulp.dest('.tmp/js/src/'))
.pipe(connect.reload());
}
});
watch('resources/js/src/**/*.js', function() {
util.log('Changes to js source files detected');
}).pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(copyAndReload);
what you can do is plugin plumber to exit in case of error
so pipe the plumber in the linting process
.pipe(plumber(_doExit))
here is how you defined _doExit
function _doExit() {
process.exit(1);
}

Is it possible to assign a variable in a gulp task before running dependencies?

I'm trying to conditionally pipe a file stream based on the value of a variable, as a way to define two separate build environments (ie. development and production).
Some tasks can be run individually with a command-line flag like so:
gulp scripts --env production
And will then do some production-only pipeline steps:
gulp.task('scripts', function() {
var jsFilter = filter(['*.js']),
appFiles;
return gulp.src(appFiles)
.pipe(jsFilter)
.pipe(concat('application-build.js'))
.pipe(gulpif(env === 'production', uglify()))
.pipe(size())
.pipe(gulpif(env === 'production', gulp.dest('dist/js'), gulp.dest('tmp/js')))
.pipe(browserSync.reload({ stream: true }));
});
I have a build task that calls a number of other tasks as dependencies (including this scripts task for instance). I want this build task to assign a variable (env, in this case) before running task dependencies. Which means that this:
gulp.task('build', ['scripts', 'styles', 'otherstuff'], function() {
env = 'production';
}
doesn't work, because the dependencies are run before the body of the task.
I currently have it implemented with gulp.start:
gulp.task('build', function() {
env = 'production';
gulp.start('scripts');
});
But the .start method isn't actually part of gulp's public API - it comes from Orchestrator - and isn't intended to be used for anything. Plus, the equivalent method gulp.run was deprecated from the API awhile ago.
So I'm wondering - is there another way I could assign a variable in a task before running its dependencies?
(Or maybe there's a better way to to implement something like build environments in gulp?)
THE RIGHT WAY
I disagree with #Justin. Defining an environmental variable with a task is a hackjob of an idea. This is better done with gutil.env this way.
gulp --env prod task
gulp.task( 'myTask', () => { console.log( gutil.env.env ) } )
Now from this point, you have gulp.env.env set.
Or, alternatively you can do like this example in this ticket.. which addresses this from the developers of Gulp which first suggest to use an environmental variable, but provide this idiom..
function js(shouldMinify) {
return gulp.src('./js/*.js')
.pipe(concat('app.js'))
.pipe(gulpif(shouldMinify, uglify()))
.pipe(gulp.dest('js'));
});
gulp.task('develop', function () {
shouldMinify = false;
return js(shouldMinify);
});
gulp.task('build', function () {
shouldMinify = true;
return js(shouldMinify);
});
That same developer (phated) always says to use env...
Not to mention, you should control this type of logic with environment variables or command line flags. - phated
Presumably, he's referring to the use of gutil.noop() in gulp-util's docs:
// gulp should be called like this :
// $ gulp --type production
gulp.task('scripts', function() {
gulp.src('src/**/*.js')
.pipe(concat('script.js'))
// LOOK BELOW: if we don't send to uglify, we push to noop stream.
.pipe(gutil.env.type === 'production' ? uglify() : gutil.noop())
.pipe(gulp.dest('dist/'));
});
You could create a task specifically to set the environment and run it before your other tasks.
gulp.task('set-production', function() {
env = 'production';
});
// Doesn't quite work because tasks are run in parallel
gulp.task('build', ['set-production', 'scripts', 'styles', 'otherstuff']);
The problem here is that your tasks will be run in parallel, meaning the set-production task may be run after the other tasks. You can solve this problem with the run-sequence package.
var runSequence = require('run-sequence');
gulp.task('build', function(callback) {
runSequence('set-production', ['scripts', 'styles', 'otherstuff'], callback);
});
This will run the set-production task first, then run the scripts, styles, and otherstuff tasks in parallel.

gulp error handling for dependent task

Please find the content of the gulpfile.js as below.
The task uglify depends on the task jshint. Currently when I run gulp, both the tasks get executed, irrespective of the outcome of the jshint task. I don't want the uglify task to get executed when there are 'jshint' error(s).
In other words, when ever there are dependent tasks, I don't want the subsequent tasks to get executed, if there are error detected by the preceding task.
Is it possible in gulp?
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var uglify = require('gulp-uglify');
gulp.task('jshint', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('uglify', ['jshint'], function() {
return gulp.src('assets/js/**/*.js')
.pipe(uglify())
.pipe(gulp.dest('assets-min/js/'));
});
gulp.task('default', ['jshint', 'uglify']);
Please refer the below console output - not desired. Though there had been jshint error, the uglify task ran successfully.
I have also created a GitHub repository with the boilerplate code for the above mentioned.
Please find the same at #sarbbottam/gulp-workflow.
Console out of the undesired workflow
Console out of the expected workflow
For JSHint, there is a built-in reporter for this purpose, fail. If an error occurs, it will stop your gulp process.
You just have to redefine your task like :
gulp.task('jshint', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('jshint-stylish'))
.pipe(jshint.reporter('fail'))
})
With other tasks, you can add an error callback on it and exit the process to prevent subsequent tasks to run.
Here is an example with ngmin (cause uglify is hard to break, but it will be the same) :
function handleError (err) {
console.log(err.toString())
process.exit(-1)
}
gulp.task('min', function () {
return gulp.src(['assets/js/**/*.js'])
.pipe(ngmin())
.on('error', handleError)
})
To complement Aperçu's answer, if you don't want gulp to just exit (because you have watcher running) then you can do the following:
gulp.task('min', function(done) {
return gulp.src(['assets/js/**/*.js'])
.pipe(ngmin())
.on('error', done);
});
This will prevent the next task that depends on this one to run but your watchers will still be running.

Categories