Node.js Gulp no outputfile created - node.js

I have a Gulp script to concatenate, and minimize javascript.
It seems to be working but doesn't output the combined file.
The script is (complete - including extra debug bits):
// include plug-ins
var fs = require('fs');
var gulp = require('gulp');
var count = require('gulp-count');
var debug = require('gulp-debug');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var config = {
src: 'dist/libraries/',
dest: 'dist/js/',
outputfile: 'libraries.min.js'
}
gulp.task('read', (done) => {
fs.readdir(config.src, (err, items) => {
console.log(items);
});
done();
});
//delete the output file(s)
gulp.task('clean', gulp.series('read'), (done) => {
//del is an async function and not a gulp plugin (just standard nodejs)
//It returns a promise, so make sure you return that from this task function
// so gulp knows when the delete is complete
return del([config.dest + config.outputfile]);
});
// Combine and minify all files from the app folder
// This tasks depends on the clean task which means gulp will ensure that the
// Clean task is completed before running the scripts task.
gulp.task('scripts', gulp.series('clean'), (done) => {
//Include all js files but exclude any min.js files
var files = [config.src + '*.js', '!' + config.src + '*.min.js'];
return gulp.src(files)
.pipe(debug())
.pipe(count('## files selected'))
.pipe(uglify())
.pipe(concat(config.outputfile))
.pipe(gulp.dest(config.dest));
});
//Set a default tasks
gulp.task('default', gulp.series('scripts'), (done) => {
});
Which produces the output - including file list for verification there are src files:
[07:46:25] Using gulpfile <path>\gulpfile.js
[07:46:25] Starting 'default'...
[07:46:25] Starting 'scripts'...
[07:46:25] Starting 'clean'...
[07:46:25] Starting 'read'...
[07:46:25] Finished 'read' after 996 μs
[07:46:25] Finished 'clean' after 2.73 ms
[07:46:25] Finished 'scripts' after 4.26 ms
[07:46:25] Finished 'default' after 6.9 ms
[ 'bootstrap-datetimepicker.js',
'bootstrap.min.js',
'chart.min.js',
'cycle.js',
'farbtastic.js',
'jquery-3.2.1.min.js',
'jquery-sortable-min.js',
'moment.min.js',
'ol.min.js',
'pablo.min.js',
'popper.min.js',
'proj4.js',
'promisedIndexDB.js',
'qunit-2.6.1.js',
'toastr.js' ]
If I create an empty file, at dist/js/libraries.min.js it isn't deleted as part of the gulp tasks, however if i move the call to del() outside the gulp tasks it is deleted, so that leads me to assume that its not as simple as a permissions issue, or path issues.
Any idea what I've done wrong?
PS: its on a windows box, running in an admin cmd window.

You were using the wrong signature for the task. The correct one is :
task([taskName], taskFunction)
see task signature
But your tasks look like this:
gulp.task('scripts', gulp.series('clean'), (done) => { // 3 parameters
Merely changing that to:
gulp.task('scripts', gulp.series('clean', (done) => {
...
}));
makes it work - I tested it. So now that task has only two parameters: a task name and a function. Yours had a task name plus two functions.
You would also need to change your default and clean tasks to this proper signature. Also you should call done() at the end of the task as you did with your cb().
Your new code uses task functions, which are better than named tasks for a number of reasons - but now you know what was wrong with your original code. The main body of your scripts task was never being run.

I never worked out what was wrong, but went direct to the doc's and started again (previous version was from a example)..
Works with the below (much simpler) script.
// // include plug-ins
var gulp = require('gulp');
var count = require('gulp-count');
var debug = require('gulp-debug');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
var config = {
src: 'jspa-scada/dist/libraries/',
dest: 'jspa-scada/dist/js/',
outputfile: 'libraries.min.js'
}
function defaultTask(cb) {
del([config.dest + config.outputfile]);
// Include all js files but exclude any min.js files
var globs = [
config.src + '*.js',
'!' + config.src + '*.min.js'
];
return gulp.src(globs)
.pipe(debug())
.pipe(count('## files selected'))
.pipe(uglify())
.pipe(concat(config.outputfile))
.pipe(gulp.dest(config.dest));
cb();
}
exports.default = defaultTask

Related

Svgmin infinite loop when running inside a task

I'm trying to get svgmin to work in my gulpfile. This is my current config:
var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var sass = require('gulp-sass');
var minify = require('gulp-minify');
var uglify = require('gulp-uglify');
var pump = require('pump');
var concat = require('gulp-concat');
var connect = require('gulp-connect-php');
var svgmin = require('gulp-svgmin');
// Static Server + watching scss/html files
gulp.task('serve', function() {
connect.server({}, function (){
browserSync.init({
proxy: '127.0.0.1:8000'
});
});
gulp.watch("assets/scss/*.scss", ['sass']);
gulp.watch("assets/js/*.js", ['javascripts']);
gulp.watch("assets/img/**/*.svg", ['svg']);
gulp.watch('**/*.php').on('change', function () {
browserSync.reload();
});
});
// Optimize SVG
gulp.task('svg', function() {
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'));
browserSync.reload();
});
// Compile sass into CSS & auto-inject into browsers
gulp.task('sass', function() {
return gulp.src([
"node_modules/normalize.css/normalize.css",
'node_modules/animate.css/animate.min.css',
"assets/scss/main.scss"
])
.pipe(sass().on('error', sass.logError))
.pipe(minify())
.pipe(concat('main.css'))
.pipe(gulp.dest("assets/build"))
.pipe(browserSync.stream());
});
// Compile javascripts & refresh browser
gulp.task('javascripts', function (cb) {
pump([
gulp.src([
// Javascript files we need
'assets/js/modernizr.js', // Modernizr
'node_modules/jquery/dist/jquery.min.js', // jQuery
'node_modules/gsap/src/minified/TweenMax.min.js', // GSAP Aninmations
'node_modules/scrollmagic/scrollmagic/uncompressed/ScrollMagic.js', // ScrollMagic Main
'node_modules/scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js', // GASP ScrollMagic plugin
'assets/js/main.js' // Main JS file
]),
concat('main.js'),
uglify(),
gulp.dest('assets/build'),
],
cb
);
browserSync.reload();
});
gulp.task('default', ['sass', 'svg', 'javascripts', 'serve']);
When I run gulp svg it runs correctly without any errors. But when I run gulp (and thus the serve task) the svg task ends in a infinite loop. What am I doing wrong here? I want my gulp to minify my SVG files whenever theres a new file or a change, and then update the browser with browerSync.
[15:46:09] Starting 'svg'...
[15:46:10] Finished 'svg' after 823 ms
[15:46:10] Starting 'svg'...
[15:46:11] Finished 'svg' after 609 ms
[15:46:11] Starting 'svg'...
[15:46:11] Finished 'svg' after 618 ms
[15:46:11] Starting 'svg'...
[15:46:12] Finished 'svg' after 630 ms
[15:46:12] Starting 'svg'...
Your problem originates with this watch:
gulp.watch("assets/img/**/*.svg", ['svg']);
This runs the svg task whenever an SVG file is touched. In your svg task you do the following:
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'));
This minifies all your SVG files and replaces each file with its minified version. So what happens is:
svg task is run
all SVG files are replaced with their minified version
watch is triggered, because SVG files have been touched
svg task is run
all SVG files are replaced with their minified version
watch is triggered, because SVG files have been touched
etc ...
You need to break that cycle.
One way of doing that is to just place the minified SVG files into the assets/build directory as you do with files in your other tasks:
return gulp.src('assets/img/**/*.svg')
.pipe(svgmin())
.pipe(gulp.dest('assets/build/'));
If you really want to replace the SVG files your can use the gulp-cached plugin. It prevents the SVG files from being overwritten if there are no actual content changes:
var cache = require('gulp-cached');
gulp.task('svg', function() {
return gulp.src('assets/img/**/*.svg')
.pipe(cache('svgmin'))
.pipe(svgmin())
.pipe(gulp.dest('assets/img/'))
.pipe(browserSync.stream());
});
This has the added benefit that your svg task will run faster, since only modified files will need to be processed now.

gulp - command-line to run a task on a specific file

I have a task scripts that do all that normal stuff with scripts on watch:
var folderScripts = "assets/scripts";
gulp.task('scripts', function(){
gulp.src([
folderScripts+'/**/*.js',
'!'+folderScripts+'/**/_*.js',
'!'+folderScripts+'/**/*.min.js'
])
// uglify, rename, etc etc...
.pipe(gulp.dest( function(file) { return file.base; } ));
});
Sometimes, I may need to run that task scripts only for a specific file outside that folder, ex: assets/plugins/flexsider/flexslider.js I'm wondering if it would be possible to do something like this on terminal:
gulp scripts assets/plugins/flexsider/flexslider.js
and then the task scripts would replace gulp.src() content for a dynamic content, this case assets/plugins/flexsider/flexslider.js, and would be like this:
var folderScripts = "assets/scripts";
gulp.task('scripts', function(){
gulp.src('assets/plugins/flexsider/flexslider.js') //this would be the "flag" I passed on terminal line
// uglify, rename, etc etc...
.pipe(gulp.dest( function(file) { return file.base; } ));
});
I searched for gulp-exec and similares but I think it is not what i'm looking for.
Thanks
Install yargs
npm install yargs --save-dev
Your task:
gulp.task('scripts', function(){
// require yargs
var args = require('yargs').argv;
var arraySources = [
folderScripts+'/**/*.js',
'!'+folderScripts+'/**/_*.js',
'!'+folderScripts+'/**/*.min.js'];
// check for an argument called file (or whatever you want)
// and set the source to the file if the argument exists. Otherwise set it to the array
var source = args.file? args.file : arraySources;
gulp.src(source)
// uglify, rename, etc etc...
.pipe(gulp.dest( function(file) { return file.base; } ));
});
Call your task from the prompt:
gulp scripts --file=assets/plugins/flexsider/flexslider.js
which will run scripts on that file only.
or
gulp scripts
which will run scripts as before

Restarting gulp after changes to gulpfile.js

I am attempting to re-run my gulp build when gulpfile.js changes, but I am having issues with the method all of my research has lead me to.
I have one watcher for all my less and javascript files and a configuration object that has the list of files to watch, how they are output, etc. This is a stripped-down example of what it looks like:
var $ = require('gulp-load-plugins')();
var config = {
root: rootPath,
output: {
app: 'app',
vendor: 'vendor'
}, // ...
};
gulp.task('default', ['build', 'watch']);
gulp.task('build', ['clean', 'less:app', 'less:theme', 'css:vendor', 'js:app', 'js:vendor', 'rev', 'css:copyfonts']);
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
$.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
gulp.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
// .. other build tasks ..
The above code shows how I tried the accepted answer to this:
How can Gulp be restarted upon each Gulpfile change?
However, it has a major issue. When I run watch:gulp, it runs the build just fine, and everything is great. The config.output.app variable is how the app specific css and js files are named, so my test case has been:
run gulp:watch, check that the css output is named according to config.output.app
change config.output.app, and perform step #1 again
save any random javascript file that it is watching, and see if it builds correctly
Step 3 is riddled with permission errors because of multiple watchers on the files, and this only gets worse the more I repeat steps 1 and 2. Visual Studio will even freeze.
I have not found a way to clean up the old watchers. I tried to manually kill them like this:
var appFileWatcher;
gulp.task('watch', function () {
var allFiles = config.styles.appSrc
.concat(config.styles.vendorSrc)
.concat(config.scripts.appSrc)
.concat(config.scripts.vendorSrc);
appFileWatcher = $.watch(allFiles, function () {
gulp.start('default');
});
});
gulp.task('watch:gulp', function () {
var p;
var gulpWatcher = $.watch('gulpfile.js', spawnUpdatedGulp);
spawnUpdatedGulp();
function spawnUpdatedGulp() {
if (p) {
p.kill();
}
if (appFileWatcher) {
appFileWatcher.unwatch();
}
gulpWatcher.unwatch();
p = spawn('gulp', ['default', '--color'], { stdio: 'inherit' });
}
});
This also does not work. I still get multiple watchers trying to perform the build when I perform my same test case.
How do I kill those watchers that stay around after the new gulp process is spawned?

Looking to use Gulp to create individual distributions of standalone HTML files

Basically I'm looking for a Gulp plugin to turn a directory like this:
/app
- htmlfile1.html
- htmlfile2.html
- htmlfile3.html
- /css
-cssmain.css
-/js
-global.js
And turn that into this:
/dist
-/htmlfile1
- htmlfile1.html
- /css
-cssmain.css
-/js
-global.js
- /htmlfile2
- htmlfile2.html
- /css
-cssmain.css
-/js
-global.js
- /htmlfile3
- htmlfile3.html
- /css
-cssmain.css
-/js
-global.js
Any thoughts on how to do accomplish a build system like this?
The code allows common files to be added to every page distribution as well as unique dependencies defined as an array in the pages object.
The following Gulp file relies on gulp-foreach, parse-filepath, and event-stream: npm install gulp gulp-foreach parse-filepath event-stream --save-dev
gulpfile.js:
// Command:
// npm install gulp gulp-foreach parse-filepath event-stream --save-dev
// Include gulp
var gulp = require('gulp');
var foreach = require('gulp-foreach'); // https://www.npmjs.org/package/gulp-foreach
var parsePath = require('parse-filepath'); // https://www.npmjs.org/package/parse-filepath
var es = require('event-stream'); // https://www.npmjs.org/package/event-stream
// The pages that each make a distribution
// Unique dependencies are defined as an array value for each page.
var pages = {
'./app/htmlfile1.html': [
'./app/images/1.png',
'./app/images/1-another.png',
],
'./app/htmlfile2.html': [],
'./app/htmlfile3.html': []
};
// Files added to each page distribution
var common = [
'./app/css/cssmain.css',
'./app/js/global.js',
];
function makeDistributionStream(page)
{
var gulpStream = gulp.src(page)
.pipe(foreach(function(stream, file) {
var pathParts = parsePath(file.path);
// Assemble the distribution path
var destinationPath = './dist/' + pathParts.name + '/';
// Pipe the html into the distribution folder
stream.pipe(gulp.dest(destinationPath));
// Move all of the unique and common files into the distibution
var uniqueDependencies = pages[page];
// Merge the common files to the unique ones
var distFiles = uniqueDependencies.concat(common);
gulp.src(distFiles, {base: './app/'})
.pipe(gulp.dest(destinationPath));
}));
return gulpStream;
}
// Assemble the distribution directories for each page
gulp.task('make-distributions', function() {
var mergedStream = null;
for(var page in pages)
{
var stream = makeDistributionStream(page);
// Merge the streams, if there is already one
if(mergedStream)
{
mergedStream = es.merge(mergedStream, stream);
}
// Otherwise, just make it this one
else
{
mergedStream = stream;
}
}
return mergedStream;
});
// Rerun the task when a file changes
gulp.task('watch', function() {
// If the html pages change, re-make the distributions
gulp.watch(Object.keys(pages), ['make-distributions']);
});
// Default Task
gulp.task('default', ['make-distributions', 'watch']);

Send parameters to jshint reporter in Gulp

I have Gulpfile with jshint configured to use jshint-stylish reporter. I need to pass option verbose to reporter in order to display warning codes. Is it possible to do it using Gulp?
Current my gulpfile.js looks like below:
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var compass = require('gulp-compass');
var path = require('path');
require('shelljs/global');
var jsFiles = ['www/js/**/*.js', '!www/js/libraries/**/*.js', 'www/spec/**/*.js', '!www/spec/lib/**/*.js'];
var sassFiles = 'www/sass/*.scss';
gulp.task('lint', function () {
return gulp
.src(jsFiles)
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
gulp.task('compass', function () {
gulp.src(sassFiles)
.pipe(compass({
project: path.join(__dirname, 'www'),
css: 'css',
sass: 'sass',
image: 'img',
font: 'fonts'
})).on('error', function() {});
});
var phonegapBuild = function (platform) {
if (!which('phonegap')) {
console.log('phonegap command not found')
return 1;
}
exec('phonegap local build ' + platform);
};
gulp.task('build:android', ['lint', 'compass'], function () {
phonegapBuild('android');
});
gulp.task('build:ios', ['lint', 'compass'], function () {
phonegapBuild('ios');
});
gulp.task('watch', function() {
gulp.watch(jsFiles, ['lint']);
gulp.watch(sassFiles, ['compass']);
});
gulp.task('default', ['lint', 'compass']);
Well, this, plus the fact that the output of the stylish reporter is hardly readable on Windows due to the darkness of the blue text, so I have to keep going in an manually changing the colour after installing it, has made me do something about it. So you should hopefully have more luck with this reporter I've just written:
https://github.com/spiralx/jshint-summary
You basically use it like this;
var summary = require('jshint-summary');
// ...
.pipe(jshint.reporter(summary({
verbose: true,
reasonCol: 'cyan,bold',
codeCol: 'green'
})
and the summary function will initialise the function passed to JSHint with those settings - see the page on Github for a bit more documentation.
It's got some very basic tests, and the library's gulpfile.js uses it to show its own JSHint output :)
How about using similar technique, as you already did with phonegap?
var jshint = function (parameter) {
// todo: define paths with js files, or pass them as parameter too
exec('jshint ' + paths + ' ' + parameter);
};
Based on https://github.com/wearefractal/gulp-jshint/blob/master/index.js#L99 it appears that gulp-jshint doesn't facilitate passing more than the name to the reporter if you load it with a string. It seems a simple thing to extend though. I'll race you to a pull request. :D
Alternatively, try something like this:
var stylish = require('jshint-stylish');
// ...
.pipe(jshint.reporter(stylish(opt)));
I'm pretty sure I have the syntax wrong, but this may get you unstuck.
It's annoying, and makes any decent reporter somewhat tricky to use within the existing framework. I've come up with this hack for the Stylish reporter, it's just currently in my gulpfile.js:
function wrapStylishReporter(reporterOptions) {
var reporter = require(stylish).reporter,
reporterOptions = reporterOptions || {};
var wrapped = function(results, data, config) {
var opts = [config, reporterOptions].reduce(function(dest, src) {
if (src) {
for (var k in src) {
dest[k] = src[k];
}
}
return dest;
}, {});
reporter(results, data, opts);
};
return jshint.reporter(wrapped);
}
And then for the task definition itself:
gulp.task('lint', function() {
return gulp.src('+(bin|lib)/**/*.js')
.pipe(jshint())
.pipe(wrapStylishReporter({ verbose: true }))
.pipe(jshint.reporter('fail'));
});
Ideally reporters would either be a function that takes an options parameter and returns the reporter function, or a fairly basic class so you could have options as well as state.

Resources