gulp with nodemon, watch for file changes, "app crashed - waiting for file changes before starting" - node.js

I'm trying to automate a simple gulp task to run/debug node, watch for file changes, and restart node if any files change. Most popular recipes I've seen for this use gulp-nodemon, but when a file change event occurs, (gulp-) nodemon crashes:
[nodemon] app crashed - waiting for file changes before starting...
The crashing happens inconsistently, so sometimes I have to manually send a SIGINT to stop the node process (which kind of defeats the purpose of nodemon).
I want to be able to run a gulp task that can watch files, run or debug node. How can this be accomplished without nodemon crashing?

It's not fancy, but the following should accomplish what you want.
'use strict'
const gulp = require('gulp');
const spawn = require('child_process').spawn;
gulp.task('debug', function() {
let child = spawn("node", ["debug", "./server.js"], { stdio: 'inherit' });
gulp.watch([__dirname + "/*.js", '!gulpfile.js'], function(event) {
console.log(`File %s was %s.`, event.path, event.type);
if (child) {
child.kill();
child = spawn("node", ["debug", "./server.js"], { stdio: 'inherit' });
}
});
});
This assumes you're watching for changes to any js files in __dirname except for your gulpfile.

Related

Unable to read a continuous data stream from a node child process in Node.js

First things first. The goal I want to achieve:
I have two processes:
the first one is webpack that just watches for file changes and pushes the bundled files into the dist/ directory
the second process (Shopify CLI) watches for any file changes in the dist/ directory and pushes them to a remote destination
My goal is to have only one command (like npm run start) which simultaneously runs both processes without printing anything to the terminal so I can print custom messages. And that's where the problem starts:
How can I continuously read child process terminal output?
Printing custom messages for webpack events at the right time is pretty easy, since webpack has a Node API for that. But the Shopify CLI only gives me the ability to capture their output and process it.
Normally, the Shopify CLI prints something like "Finished Upload" as soon as the changed file has been pushed. It works perfectly fine for the first time but after that, nothing is printed to the terminal anymore.
Here is a minimal representation of what my current setup looks like:
const spawn = require('spawn');
const childProcess = spawn('shopify', ['theme', 'serve'], {
stdio: 'pipe',
});
childProcess.stdout.on('data', (data) => {
console.log(data);
});
childProcess.stderr.on('data', (data) => {
// Just to make sure there are no errors
console.log(data);
});

process.exit() not exiting process from within express .close callback, only with nodemon

I am trying to create some setup and teardown logic for an expressjs server. Here's my entry code:
import fs from "fs";
import express from "express";
import { setRoutes } from "./routes";
let app = express();
const server = app.listen(8080, function () {
console.log(`šŸŽ§ Mock Server is now running on port : ${8080}`);
});
app = setRoutes(app);
function stop() {
fs.rmdirSync("./uploads", { recursive: true });
fs.mkdirSync("uploads");
console.log("\nšŸ§¹ Uploads folder purged");
server.on("close", function () {
console.log("ā¬‡ Shutting down server");
process.exit();
});
server.close();
}
process.on("SIGINT", stop);
// Purge sw images on restart
process.once("SIGUSR2", function () {
fs.rmdirSync("./uploads/swimages", { recursive: true });
console.log("šŸ§¹ Software Images folder purged");
process.kill(process.pid, "SIGUSR2");
});
The npm script to start this up is "start": "FORCE_COLOR=3 nodemon index.js --exec babel-node".
The setup and restart logic works as expected. I get šŸŽ§ Mock Server is now running on port : 8080 logged to console on startup. When I save a file, nodemon restarts the server, and the code in process.once is executed. When I want to shut it all down, I ctrl + c in the terminal. The cleanup logic from within the stop function is run. However, the process bever fully exits. In the terminal, am still stuck in the process, and I have to hit ctrl + c again to fully exit the process. It looks like this:
As far as I know there are no open connections (other questions mentioned that if there is a keep-alive connection still open, the server will not close properly, but as far as I can tell, that is not the case). I have tried different variations of server.close(callback), server.on('close', callback), process.exit(), process.kill(process.pid), etc, but nothing seems to fully exit the process.
Note that if I simply run node index.js, I do not have this issue. The cleanup logic runs, and the process exits to completion without issue. It seems to be an issue when using nodemon only.
I don't want other developers to have to wait for cleanup logic to run and then hit ctrl + c again. What am I missing to run my cleanup logic and fully exit the process in the terminal?
There is an open connection for sure. Check this package that can tell you which one: https://www.npmjs.com/package/wtfnode

Nodemon crashed when bound with gulp watch and restarted more than twice

I am trying to make my processes (webpack, nodemon-restart) work with a single gulp command. This works well enough. However, webpack builds only once if its task is tied to gulp's default task (together with nodemon), or embedded withing nodemon's gulp task.
Then I decided to tie both webpack build task and nodemon restart task to gulp's watch command and this works just the way I wanted, except that if you make changes and save them more than twice, the app nodemon crashed and prints this error in the console
"/home/nnanyielugo/Workspace/activity-calendar/node_modules/nodemon/lib/monitor/match.js:132
var rules = monitor.sort(function (a, b) {
^
TypeError: Cannot read property 'sort' of undefined"
As a solution, i tried to tie the webpack build task to the nodemon restart using the .on() method, and instead got an infinite loop of restarting an rebuilding (nodemon restarts first, webpack builds, nodemon restarts again, webpack rebuilds, and on and on).
Does anyone have a solution please?`
Here is a sample of my code `
var gulp = require('gulp'),
nodemon = require('gulp-nodemon'),
webpack = require('webpack-stream');
gulp.task('default', ['watch']);
gulp.task('webpack', function() {
return gulp.src('src/entry.js')
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('./public'));
});
gulp.task('nodemon', function () {
return nodemon({
script: 'app.js'
, ext: 'js html'
, env: { 'NODE_ENV': 'development' }
})
})
gulp.task('watch', function(){
gulp.watch(['./api/**/*.js', './server/**/*.js', './*.js'], ['webpack', 'nodemon']);
})`
I guess, your nodemon and gulp's watch task collides with each other. Either you should get ride of using nodemon and to rely upon gulp to start your application.
Or else, you can get rid of your gulp's watch task and add the relevant script in your nodemon's restart method like this,
nodemon({
// script goes here.
}).on('restart', your_reload_logic)
Hope this helps!

NodeJS: Can't kill spawn of gulp process

I'd like to restart gulp on certain changes. That can be easily done by placing the following within the gulpfile
spawn('gulp', [], { stdio: 'inherit'});
However, once gulp restarts in this way, the process is no longer killed properly with Ctrl+C via the terminal. If I start gulp via terminal, I can capture a Ctrl+C signal, but can't if gulp was started via the spawn in gulpfile. How can I capture 'SIGINT' for the spawn?
Okay here's the full story to anyone who might encounter the issue. From what I have been reading, whenever you want to restart gulp from within gulp you simply use:
spawn('gulp', [], { stdio: 'inherit'});
process.exit();
I didn't mention process.exit() in my question as I didn't expect it to affect the usage of Ctrl+C. Indeed it was, as my server was an ExpressJS one, whenever I'd use Ctrl+C after gulp restarted from within itself, I would get the port still in use error (Error: listen EADDRINUSE). Obviously, all node processes wasn't being closed. Once I removed the line process.exit() from my code, I was able to use Ctrl+C and successfully close all processes. Below is the useful bit of code in the gulpfile and output in terminal that is related to this issue.
// gulpfile.js
gulp.task('restart', function() {
server.close();
spawn('gulp', [], { stdio: 'inherit'});
process.exit(); // this line needs to be removed
});
process.on('SIGINT', function() {
setTimeout(function() {
gutil.log(gutil.colors.red('Successfully closed ' + process.pid));
process.exit(1);
}, 500);
});
// Console results:
^C[20:12:12] Successfully closed 67160
[20:12:12] Successfully closed 67151

Starting node.js app as a background process

I have a node.js app which runs until user quits the process. I'm trying to run this app as a background process with forever, however, my app originally outputs something to stdout:
process.stdout.clearLine();
process.stdout.cursorTo(0);
process.stdout.write('...');
and if I run this app with forever
forever start -l forever.log -o out.log -e err.log app.js
it does run in the background but there's nothing in out.log file. If I look at err.log I see that problem is in printing something to stdout:
$ cat err.log
/Users/err/Sites/js/test/app.js:105
process.stdout.clearLine();
^
TypeError: Object #<Socket> has no method 'clearLine'
at null.<anonymous> (/Users/err/Sites/js/test/app.js:105:20)
at wrapper [as _onTimeout] (timers.js:252:14)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
I also tried to use forever-monitor and wrote a small script:
var config = require('./config');
if (config.runInBackground) {
var forever = require('forever-monitor');
var child = new (forever.Monitor)('app.js', {
max: 1,
silent: true,
outFile: 'monitor.out.log',
errFile: 'monitor.err.log'
});
child.on('stdout', function(e) {
console.log(e);
});
child.on('exit', function () {
console.log('exited.');
});
child.start();
} else {
// do the regular process.stdout.write('...');
}
But my script exists without writing any file or starting a background process.
How can I run my node app in the background and write the original stdout to some log file? Or even better, is it possible to have an option (let's say in config.js file) to run this app as a background process or not, and if so, all stdout stuff should be written to a file?
You may need to specify an absolute path for your files.
That said, there are alternatives to forever that might work depending on your operating system. node-windows and node-mac both offer what you're looking for. node-linux isn't ready yet, but the project has some init.d scripts that could be configured to run processes with logging.
Disclosure: I am the author of all three of these.

Resources