gulp.watch running only once on Windows - javascript

I'm just started to use Gulp to improve my workflow. I'm currently have a task called styles that compiles .less files, and a task called watch, to watch for changes in any .less file and, then, run styles task. My gulpfile.js contains this code:
var gulp = require( 'gulp' ),
less = require( 'gulp-less' ),
autoprefixer = require( 'gulp-autoprefixer' ),
minifycss = require( 'gulp-minify-css' ),
jshint = require( 'gulp-jshint' ),
uglify = require( 'gulp-uglify' ),
imagemin = require( 'gulp-imagemin' ),
rename = require( 'gulp-rename' ),
clean = require( 'gulp-clean' ),
concat = require( 'gulp-concat' ),
notify = require( 'gulp-notify' ),
cache = require( 'gulp-cache' ),
header = require( 'gulp-header' ),
footer = require( 'gulp-footer' );
// styles task
gulp.task( 'styles', function() {
return gulp.src( 'src/styles/main.less' )
.pipe( less({ paths: ['src/styles/'] }) )
.pipe( autoprefixer( 'last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4' ) )
.pipe( gulp.dest( 'dist/assets/css' ) )
.pipe( rename( 'main.min.css' ) )
.pipe( minifycss() )
.pipe( gulp.dest( 'dist/assets/css' ) )
.pipe( notify({ message: 'Styles task complete' }) );
} )
(...)
// watch task
gulp.task('watch', function() {
// Watch .less files
gulp.watch('src/styles/**/*.less', function(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
gulp.run('styles');
});
});
The problem is, when I run gulp watch, it starts the task and runs the styles task on the first time that I change a .less file. After the first time, I only got the message logged (File X was changed, running tasks...). Am I doing something wrong?
Thanks for any hint or help!
EDIT
Just some information as requested: I'm running Node.js 0.10.24 with Gulp 3.4.0. Here is a screenshot of the prompt output:

After #SteveLacy suggestion to break out my task parts and check if any of them was causing the troubles, I got my really dumb mistake that causes the error: gulp-notify works only on Mac and Linux, and my OS is Windows. From the plugin description:
Send messages to Mac Notification Center or Linux notifications (using
notify-send) using the node-notifier module. Can also specify custom
notifier (e.g. Growl notification).
Shame on me.
I follow a really good tutorial about getting started with Gulp, and gulp-notify was one of the plugins used on it. My mystake was not paying attention at the plugin details.
After I removed gulp-notify from my gulpfile.js, everything works as it should be, I got all the right logs and my gulp watch task works like a charm!
In short: AWAYS check a plugin compatibility with your OS.
Thanks for everybody that spent time trying to help me!

I had the same problem, and mine was a total gulp newbie problem. If anyone is as pathetically new to gulp as I am, ensure your triggered watch functions end with a done():
gulp.task("watch", function() {
gulp.watch("lib/*.js, "foobar");
});
gulp.task("foobar", function(done) {
// This task completion was omitted.
done();
});

If I remember correctly gulp.run is deprecated in Gulp version 3.5. Try to replace gulp.run(); with gulp.start(); and see if that works.

Related

Gulp 4, Tasks don't execute before calling watch

I am using Gulp 4 to compile my code from TypeScript to JavaScript and to build and serve the app.
I've come across one problem that I cannot solve.
I'd like to run the build, copy-html and copy-css tasks before some file gets changed.
According to Gulp documentation I just need to provide a config object with ignoreInitial set to false, but it doesn't work.
I've tried to call the three tasks before I initialize browserSync but for it also didn't work for me.
gulp.task("serve", function() {
// TODO Make a build before first serve
browserSync.init({
server: {
baseDir: "./dist/"
}
});
gulp
.watch(["src/**/*.ts", "src/**/*.html", "src/**/*.css"], {
ignoreInitial: false
})
.on(
"change",
gulp.series(
gulp.parallel("copy-html", "copy-css"),
build,
browserSync.reload
)
);
});
Instead of using calling .on() on the returned chokidar interface, add your tasks to the watch command.
gulp
.watch(
["src/**/*.ts", "src/**/*.html", "src/**/*.css"],
{ ignoreInitial: false },
gulp.series(
gulp.parallel("copy-html", "copy-css"),
build,
browserSync.reload
)
)
);

How do I get Winston to work with Webpack?

I have an electron application which is using node.js. I would like to use Winston for logging in the application. I've added winston to my package.json file, but when I run the build command for webpack I'm getting some warnings from the colors.js dependency in winston.
'...the request of a dependency is an expression...'
It then references winston and colors.js. Ignoring the warnings doesn't work, as the electron application gets an exception trying to load some files from winston.
I did some digging on SO and the github site and they say that colors.js has some dynamic require statements that webpack is having issues with. I've also seen that other sample projects seem to have winston up and running without any issues in their projects. Does anyone know how to correctly include the winston logging package with webpack in an electron app?
There are two sides to this issue:
1) winston directly or indirectly depends on color.js, so that dependency automatically gets included, once winston is there. In some older versions of it, it included a dynamic require statement, which leads to this:
2) a dependency has a dynamic require statement that Webpack cannot handle; you can either configure webpack so it can ignore this specific case, or also upgrade winston to a newer version, so color.js will be picked in a variant without that dynamic require (see https://github.com/winstonjs/winston/issues/984).
To tell Webpack to get along with the dynamic require, you need to tell Webpack that Winston is an external library.
Here's an example from my webpack.config.js:
externals: {
'electron': 'require("electron")',
'net': 'require("net")',
'remote': 'require("remote")',
'shell': 'require("shell")',
'app': 'require("app")',
'ipc': 'require("ipc")',
'fs': 'require("fs")',
'buffer': 'require("buffer")',
'winston': 'require("winston")',
'system': '{}',
'file': '{}'
},
To make the logger available in an angular 2 app using electron, create a logger.js file and then wrap it with a global logging service TypeScript file (i.e. logging.service.ts). The logger.js file creates the logger variable with the desired Winston configuration settings.
logger.js:
var winston = require( 'winston' ),
fs = require( 'fs' ),
logDir = 'log', // Or read from a configuration
env = process.env.NODE_ENV || 'development',
logger;
​
winston.setLevels( winston.config.npm.levels );
winston.addColors( winston.config.npm.colors );
if ( !fs.existsSync( logDir ) ) {
// Create the directory if it does not exist
fs.mkdirSync( logDir );
}
logger = new( winston.Logger )( {
transports: [
new winston.transports.Console( {
level: 'warn', // Only write logs of warn level or higher
colorize: true
} ),
new winston.transports.File( {
level: env === 'development' ? 'debug' : 'info',
filename: logDir + '/logs.log',
maxsize: 1024 * 1024 * 10 // 10MB
} )
],
exceptionHandlers: [
new winston.transports.File( {
filename: 'log/exceptions.log'
} )
]
} );
​
module.exports = logger;
logging.service.ts:
export var LoggerService = require('./logger.js');
Now the logging service is available for use throughout the application.
Example:
import {LoggerService} from '<path>';
...
LoggerService.log('info', 'Login successful for user ' + this.user.email);

Precompile handlebars templates into seperate JST (.js) files with Gulp

I have just recently moved from grunt to gulp and I am wanting to pre-compile my handlebars templates (with .handlebars extension) into separate .js files.
from:
www/templates/login.handlebars
www/templates/home.handlebars
to:
www/templates/login.js
www/templates/home.js
I am trying to use gulp but to no avail. A lot of the npm packages ask you to pass data to the compiler, but the data in my web app is collected mainly from ajax requests and then passed to the handlebars template.
My gulpfile.js:
// cache vars
var gulp = require('gulp'),
rename = require('gulp-rename'),
handlebars = require('gulp-compile-handlebars');
// start task
gulp.task('default', function(){
return gulp.src( 'www/templates/*.handlebars' )
.pipe( handlebars() )
.pipe( rename('*.js') )
.pipe( gulp.dest( 'www/templates' ) );
});
});
The main reason i moved from Grunt to Gulp was because grunt doesnt seem to support the newer handlebars version (link here).
There are lots of examples how to compile handlebars templates but not in the way I want too (Is my way possible?)
Also i don't want to wrap my handlebar js files into a namespace if possible.
When i run my gulp task none of the .js files are generated any ideas?
I have a not so clean solution that works for me. I'm using pump + gulp as it's a good idea to clean the source if something goes wrong while processing the pipe.
in the gulpfile.js:
const pump = require( 'pump' )
const handlebars = require( 'gulp-handlebars' )
gulp.task( 'default', ( done ) => {
const templates = [
'login',
'home'
] // <-- You may want to get the list of files programmatically ;)
let pipe = []
templates.forEach( ( template ) => {
pipe.push( gulp.src( 'www/templates/' + template + '.handlebars' ) )
pipe.push( handlebars() )
pipe.push( gulp.dest( 'www/templates/' ) )
} )
pump( pipe, done )
} )

SASS task in gulp with sourceComments: 'map' produces 'Assertion failed'

I have a web app I'm developing using AngularJS, D3, Pixi.js, and gulp as a build system. It all works great together, except gulp-sass. Here's the relevant code:
gulp.task('sass-dev', ['clean-dev'], function() {
return gulp.src( cfg.appFiles.rootSass )
.pipe( sass({ errLogToConsole: true }))
.pipe( gulp.dest( cfg.buildDir+cfg.destDirs.css ) )
.pipe( livereload( server ) );
});
cfg is just a variable that has predefined globs. If I make the third line
.pipe( sass({ errLogToConsole: true, sourceComments: 'map' }))
by adding the mapping of the source (useful for debugging), I get the following fatal error.
Assertion failed: (val->IsString()), function _NanGetExternalParts, file ../node_modules/nan/nan.h, line 1725.
Abort trap: 6
On my colleague's computer, it works perfectly with or without mapping. On mine, it fails every time with the source comments mapped, and works perfectly without mapping. Both computers are iMacs running the latest version of node (npm), bower, and OS X.
Any idea what could be causing this? Issue in gulp or gulp-sass itself?
These options worked for me.
{ errLogToConsole: true, sourceComments: 'map', sourceMap: 'sass' }.
There's always seems to be something weird going on.
In my case, the cause was an empty scss file. Adding a comment to the file, or removing the scss file, solved this problem

How can Gulp be restarted upon each Gulpfile change?

I am developing a Gulpfile. Can it be made to restart as soon as it changes? I am developing it in CoffeeScript. Can Gulp watch Gulpfile.coffee in order to restart when changes are saved?
You can create a task that will gulp.watch for gulpfile.js and simply spawn another gulp child_process.
var gulp = require('gulp'),
argv = require('yargs').argv, // for args parsing
spawn = require('child_process').spawn;
gulp.task('log', function() {
console.log('CSSs has been changed');
});
gulp.task('watching-task', function() {
gulp.watch('*.css', ['log']);
});
gulp.task('auto-reload', function() {
var p;
gulp.watch('gulpfile.js', spawnChildren);
spawnChildren();
function spawnChildren(e) {
// kill previous spawned process
if(p) { p.kill(); }
// `spawn` a child `gulp` process linked to the parent `stdio`
p = spawn('gulp', [argv.task], {stdio: 'inherit'});
}
});
I used yargs in order to accept the 'main task' to run once we need to restart. So in order to run this, you would call:
gulp auto-reload --task watching-task
And to test, call either touch gulpfile.js or touch a.css to see the logs.
I created gulper that is gulp.js cli wrapper to restart gulp on gulpfile change.
You can simply replace gulp with gulper.
$ gulper <task-name>
I use a small shell script for this purpose. This works on Windows as well.
Press Ctrl+C to stop the script.
// gulpfile.js
gulp.task('watch', function() {
gulp.watch('gulpfile.js', process.exit);
});
Bash shell script:
# watch.sh
while true; do
gulp watch;
done;
Windows version: watch.bat
#echo off
:label
cmd /c gulp watch
goto label
I was getting a bunch of EADDRINUSE errors with the solution in Caio Cunha's answer. My gulpfile opens a local webserver with connect and LiveReload. It appears the new gulp process briefly coexists with the old one before the older process is killed, so the ports are still in use by the soon-to-die process.
Here's a similar solution which gets around the coexistence problem, (based largely on this):
var gulp = require('gulp');
var spawn = require('child_process').spawn;
gulp.task('gulp-reload', function() {
spawn('gulp', ['watch'], {stdio: 'inherit'});
process.exit();
});
gulp.task('watch', function() {
gulp.watch('gulpfile.js', ['gulp-reload']);
});
That works fairly well, but has one rather serious side-effect: The last gulp process is disconnected from the terminal. So when gulp watch exits, an orphaned gulp process is still running. I haven't been able to work around that problem, the extra gulp process can be killed manually, or just save a syntax error to gulpfile.js.
I've been dealing with the same problem and the solution in my case was actually very simple. Two things.
npm install nodemon -g (or locally if you prefer)
run with cmd or create a script in packages like this:
"dev": "nodemon --watch gulpfile.js --exec gulp"
The just type npm run dev
--watch specifies the file to keep an eye on. --exec says execute next in line and gulp is your default task. Just pass in argument if you want non default task.
Hope it helps.
EDIT : Making it fancy ;)
Now while the first part should achieve what you were after, in my setup I've needed to add a bit more to make it really user friend. What I wanted was
First open the page.
Look for changes in gulpfile.js and restart gulp if there are any
Gulp it up so keep an eye on files, rebuild and hot reload
If you only do what I've said in the first part, it will open the page every time. To fix it, create a gulp task that will open the page. Like this :
gulp.task('open', function(){
return gulp
.src(config.buildDest + '/index.html')
.pipe(plugins.open({
uri: config.url
}));
Then in my main tasks I have :
gulp.task('default', ['dev-open']);
gulp.task('dev-open', function(done){
plugins.sequence('build', 'connect', 'open', 'watch', done);
});
gulp.task('dev', function(done){
plugins.sequence('build', 'connect', 'watch', done);
});
Then modifying your npm scripts to
"dev": "gulp open & nodemon --watch gulpfile.js --watch webpack.config.js --exec gulp dev"
Will give you exactly what you want. First open the page and then just keep live reloading. Btw for livereload I use the one that comes with connect which always uses the same port. Hope it works for you, enjoy!
Another solution for this is to refresh the require.cache.
var gulp = require('gulp');
var __filenameTasks = ['lint', 'css', 'jade'];
var watcher = gulp.watch(__filename).once('change', function(){
watcher.end(); // we haven't re-required the file yet
// so is the old watcher
delete require.cache[__filename];
require(__filename);
process.nextTick(function(){
gulp.start(__filenameTasks);
});
});
I know this is a very old question, but it's a top comment on Google, so still very relevant.
Here is an easier way, if your source gulpfile.js is in a different directory than the one in use. (That's important!) It uses the gulp modules gulp-newer and gulp-data.
var gulp = require('gulp' )
, data = require('gulp-data' )
, newer = require('gulp-newer' )
, child_process = require('child_process')
;
gulp.task( 'gulpfile.js' , function() {
return gulp.src( 'sources/gulpfile.js' ) // source
.pipe( newer( '.' ) ) // check
.pipe( gulp.dest( '.' ) ) // write
.pipe( data( function(file) { // reboot
console.log('gulpfile.js changed! Restarting gulp...') ;
var t , args = process.argv ;
while ( args.shift().substr(-4) !== 'gulp' ) { t=args; }
child_process.spawn( 'gulp' , args , { stdio: 'inherit' } ) ;
return process.exit() ;
} ) )
;
} ) ;
It works like this:
Trick 1: gulp-newer only executes the following pipes, if the source file is newer than the current one. This way we make sure, there's no reboot-loop.
The while loop removes everything before and including the gulp command from the command string, so we can pass through any arguments.
child_process.spawn spawns a new gulp process, piping input output and error to the parent.
Trick 2: process.exit kills the current process. However, the process will wait to die until the child process is finished.
There are many other ways of inserting the restart function into the pipes.
I just happen to use gulp-data in every of my gulpfiles anyway. Feel free to comment your own solution. :)
Here's another version of #CaioToOn's reload code that is more in line with normal Gulp task procedure. It also does not depend on yargs.
Require spawn and initilaize the process variable (yargs is not needed):
var spawn = require('child_process').spawn;
var p;
The default gulp task will be the spawner:
gulp.task('default', function() {
if(p) { p.kill(); }
// Note: The 'watch' is the new name of your normally-default gulp task. Substitute if needed.
p = spawn('gulp', ['watch'], {stdio: 'inherit'});
});
Your watch task was probably your default gulp task. Rename it to watch and add a gulp.watch()for watching your gulpfile and run the default task on changes:
gulp.task('watch', ['sass'], function () {
gulp.watch("scss/*.scss", ['sass']);
gulp.watch('gulpfile.js', ['default']);
});
Now, just run gulp and it will automatically reload if you change your gulpfile!
try this code (only win32 platform)
gulp.task('default', ['less', 'scripts', 'watch'], function(){
gulp.watch('./gulpfile.js').once('change' ,function(){
var p;
var childProcess = require('child_process');
if(process.platform === 'win32'){
if(p){
childProcess.exec('taskkill /PID' + p.id + ' /T /F', function(){});
p.kill();
}else{
p = childProcess.spawn(process.argv[0],[process.argv[1]],{stdio: 'inherit'});
}
}
});
});
A good solution for Windows, which also works well with Visual Studio task runner.
/// <binding ProjectOpened='auto-watchdog' />
const spawn = require('child-proc').spawn,
configPaths = ['Gulpconfig.js', 'bundleconfig.js'];
gulp.task('watchdog', function () {
// TODO: add other watches here
gulp.watch(configPaths, function () {
process.exit(0);
});
});
gulp.task('auto-watchdog', function () {
let p = null;
gulp.watch(configPaths, spawnChildren);
spawnChildren();
function spawnChildren() {
const args = ['watchdog', '--color'];
// kill previous spawned process
if (p) {
// You might want to trigger a build as well
args.unshift('build');
setTimeout(function () {
p.kill();
}, 1000);
}
// `spawn` a child `gulp` process linked to the parent `stdio`
p = spawn('gulp', args, { stdio: 'inherit' });
}
});
Main changes compared to other answers:
Uses child-proc because child_process fails on Windows.
The watchdog exits itself on changes of files because in Windows the gulp call is wrapped in a batch script. Killing the batch script wouldn't kill gulp itself causing multiple watches to be spawned over time.
Build on change: Usually a gulpfile change also warrants rebuilding the project.
Install nodemon globally: npm i -g nodemon
And add in your .bashrc (or .bash_profile or .profile) an alias:
alias gulp='nodemon --watch gulpfile.js --watch gulpfile.babel.js --quiet --exitcrash --exec gulp'
This will watch for file gulpfile.js and gulpfile.babel.js changes. (see Google)
P.S. This can be helpful for endless tasks (like watch) but not for single run tasks. I mean it uses watch so it will continue process even after gulp task is done. ;)
Here's a short version that's easy to understand that you can set as a default task so you just need to type "gulp":
gulp.task('watch', function() {
const restartingGulpProcessCmd = 'while true; do gulp watch2 --colors; done;';
const restartingGulpProcess = require('child_process').exec(restartingGulpProcessCmd);
restartingGulpProcess.stdout.pipe(process.stdout);
restartingGulpProcess.stderr.pipe(process.stderr);
});
gulp.task('watch2', function() {
gulp.watch(['config/**.js', 'webpack.config.js', './gulpfile.js'],
() => {
console.log('Config file changed. Quitting so gulp can be restarted.');
process.exit();
});
// Add your other watch and build commands here
}
gulp.task('default', ['watch']);
I spent a whole day trying to make this work on Windows / Gulp 4.0.2, and I (finally) made it...
I used some solutions from people on this page and from one other page. It's all there in the comments...
Any change in any function inside "allTasks" will take effect on gulpfile.js (or other watched files) save...
There are some useless comments and console.logs left, feel free to remove them... ;)
const { gulp, watch, src, dest, series, parallel } = require("gulp");
const spawn = require('child_process').spawn;
// This function contains all that is necessary: start server, watch files...
const allTasks = function (callback) {
console.log('==========');
console.log('========== STARTING THE GULP DEFAULT TASK...');
console.log('========== USE CTRL+C TO STOP THE TASK');
console.log('==========');
startServer();
// other functions (watchers) here
// *** Thanks to Sebazzz ***
// Stop all on gulpfile.js change
watch('gulpfile.js', function (callback) {
callback(); // avoid "task didn't complete" error
process.exit();
});
callback(); // avoid "task didn't complete" error
}
// Restart allTasks
// ********************************************
// CALL GULPDEFAULT WITH THE GULP DEFAULT TASK:
// export.default = gulpDefault
// ********************************************
const gulpDefault = function (callback) {
let p = null;
watch('gulpfile.js', spawnChildren);
// *** Thanks to Sphinxxx: ***
// New behavior in gulp v4: The watcher function (spawnChildren()) is passed a callback argument
// which must be called after spawnChildren() is done, or else the auto-reload task
// never goes back to watching for further changes (i.e.the reload only works once).
spawnChildren(callback);
function spawnChildren(callback) {
/*
// This didn't do anything for me, with or without the delay,
// so I left it there, but commented it out, together with the console.logs...
// kill previous spawned process
if (p) {
// You might want to trigger a build as well
//args.unshift('build');
setTimeout(function () {
console.log('========== p.pid before kill: ' + p.pid); // a random number
console.log('========== p before kill: ' + p); // [object Object]
p.kill();
console.log('========== p.pid after kill: ' + p.pid); // the same random number
console.log('========== p after kill: ' + p); // still [object Object]
}, 1000);
}
*/
// `spawn` a child `gulp` process linked to the parent `stdio`
// ['watch'] is the task that calls the main function (allTasks):
// exports.watch = allTasks;
p = spawn('gulp', ['watch'], { stdio: 'inherit', shell: true });
// *** Thanks to people from: ***
// https://stackoverflow.com/questions/27688804/how-do-i-debug-error-spawn-enoent-on-node-js
// Prevent Error: spawn ENOENT
// by passing "shell: true" to the spawn options
callback(); // callback called - thanks to Sphinxxx
}
}
exports.default = gulpDefault;
exports.watch = allTasks;
Install gulp-restart
npm install gulp-restart
This code will work for you.
var gulp = require('gulp');
var restart = require('gulp-restart');
gulp.task('watch', function() {
gulp.watch(['gulpfile.js'], restart);
})
it will restart gulp where you do changes on the gulpfile.js

Categories

Resources