Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nodemon

Package Overview
Dependencies
Maintainers
1
Versions
256
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nodemon - npm Package Compare versions

Comparing version 0.5.7 to 0.6.0

options.js

398

nodemon.js
#!/usr/bin/env node
var fs = require('fs'),
sys = require('util'),
util = require('util'),
childProcess = require('child_process'),
dirs = [],
path = require('path'),

@@ -10,5 +11,4 @@ spawn = childProcess.spawn,

flag = './.monitor',
nodeArgs = process.argv.splice(2), // removes 'node' and this script
app = nodeArgs[0],
node = null,
program = getNodemonArgs(),
child = null,
monitor = null,

@@ -22,2 +22,3 @@ ignoreFilePath = './.nodemonignore',

restartTimer = null,
lastStarted = +new Date,
// create once, reuse as needed

@@ -32,26 +33,18 @@ reEscComments = /\\#/g,

function startNode() {
sys.log('\x1B[32m[nodemon] starting node\x1B[0m');
util.log('\x1B[32m[nodemon] starting ' + program.options.exec + '\x1B[0m');
var ext = path.extname(app);
// console.log('running: ' + program.options.exec + ' ' + program.args.join(' '))
child = spawn(program.options.exec, program.args);
lastStarted = +new Date;
if (ext === '.coffee') {
//coffeescript requires --nodejs --debug
var debugIndex = nodeArgs.indexOf('--debug');
if (debugIndex >= 0) {
nodeArgs.splice(debugIndex, 0, '--nodejs');
}
node = spawn('coffee', nodeArgs);
} else {
node = spawn('node', nodeArgs);
}
node.stdout.on('data', function (data) {
sys.print(data);
child.stdout.on('data', function (data) {
util.print(data);
});
node.stderr.on('data', function (data) {
sys.error(data);
child.stderr.on('data', function (data) {
util.error(data);
});
node.on('exit', function (code, signal) {
child.on('exit', function (code, signal) {
// exit the monitor, but do it gracefully

@@ -61,16 +54,65 @@ if (signal == 'SIGUSR2') {

startNode();
} else if (code === 0) { // clean exit - wait until file change to restart
util.log('\x1B[32m[nodemon] clean exit - waiting for changes before restart\x1B[0m');
child = null;
} else {
sys.log('\x1B[1;31m[nodemon] app crashed - waiting for file change before starting...\x1B[0m');
node = null;
util.log('\x1B[1;31m[nodemon] app crashed - waiting for file changes before starting...\x1B[0m');
child = null;
}
});
// pinched from https://github.com/DTrejo/run.js - pipes stdin to the child process - cheers DTrejo ;-)
process.stdin.resume();
process.stdin.setEncoding('utf8');
process.stdin.pipe(child.stdin);
setTimeout(startMonitor, timeout);
}
function startMonitor() {
var cmd = 'find -L . -type f -newer ' + flag + ' -print';
function changedSince(time, dir, callback) {
callback || (callback = dir);
var changed = [],
i = 0,
j = 0,
dir = dir && typeof dir !== 'function' ? [dir] : dirs,
dlen = dir.length,
todo = 0, // how fucking lame is this? promises anyone?
flen = 0,
done = function () {
todo--;
if (todo === 0) callback(changed);
};
dir.forEach(function (dir) {
todo++;
fs.readdir(dir, function (err, files) {
if (err) return;
exec(cmd, function (error, stdout, stderr) {
var files = stdout.split(/\n/);
files.forEach(function (file) {
if (program.includeHidden == true || !program.includeHidden && file.indexOf('.') !== 0) {
todo++;
file = path.resolve(dir + '/' + file);
var stat = fs.stat(file, function (err, stat) {
if (stat) {
if (stat.isDirectory()) {
todo++;
changedSince(time, file, function (subChanged) {
if (subChanged.length) changed = changed.concat(subChanged);
done();
});
} else if (stat.mtime > time) {
changed.push(file);
}
}
done();
});
}
});
done();
});
});
}
files.pop(); // remove blank line ending and split
function startMonitor() {
changedSince(lastStarted, function (files) {
if (files.length) {

@@ -84,23 +126,21 @@ // filter ignored files

fs.writeFileSync(flag, '');
if (files.length) {
if (restartTimer !== null) clearTimeout(restartTimer);
restartTimer = setTimeout(function () {
sys.log('[nodemon] restarting due to changes...');
if (program.options.verbose) util.log('[nodemon] restarting due to changes...');
files.forEach(function (file) {
sys.log('[nodemon] ' + file);
if (program.options.verbose) util.log('[nodemon] ' + file);
});
sys.print('\n\n');
if (program.options.verbose) util.print('\n\n');
if (node !== null) {
node.kill('SIGUSR2');
if (child !== null) {
child.kill('SIGUSR2');
} else {
startNode();
}
}
}, restartDelay);
return;
}
}
setTimeout(startMonitor, timeout);

@@ -131,15 +171,6 @@ });

path.exists(ignoreFilePath, function(exists) {
// if (!exists) {
// we'll touch the ignore file to make sure it gets created and
// if Vim is writing the file, it'll just overwrite it - but also
// prevent from constant file io if the file doesn't exist
// fs.writeFileSync(ignoreFilePath, "\n");
// setTimeout(readIgnoreFile, 500);
// return;
// }
if (program.options.verbose) util.log('[nodemon] reading ignore list');
sys.log('[nodemon] reading ignore list');
// ignoreFiles = ignoreFiles.concat([flag, ignoreFilePath]);
addIgnoreRule(flag);
// addIgnoreRule(flag);
addIgnoreRule(ignoreFilePath);

@@ -153,107 +184,185 @@ fs.readFileSync(ignoreFilePath).toString().split(/\n/).forEach(function (rule, i) {

function usage() {
sys.print([
'usage: nodemon [options] [script.js] [args]',
'e.g.: nodemon script.js localhost 8080',
'',
'Options:',
' --js monitor only JavaScript file changes',
' (default if ignore file not found)',
' -d n, --delay n throttle restart for "n" seconds',
' --debug enable node\'s native debug port',
' -v, --version current nodemon version',
' -h, --help this usage',
'',
'Note: if the script is omitted, nodemon will try "main" from package.json',
'',
'For more details see http://github.com/remy/nodemon/\n'
].join('\n'));
}
function controlArg(nodeArgs, label, fn) {
var i;
if ((i = nodeArgs.indexOf(label)) !== -1) {
fn(nodeArgs[i], i);
} else if ((i = nodeArgs.indexOf('-' + label.substr(0, 1))) !== -1) {
fn(nodeArgs[i], i);
} else if ((i = nodeArgs.indexOf('--' + label)) !== -1) {
fn(nodeArgs[i], i);
}
}
// attempt to shutdown the wrapped node instance and remove
// the monitor file as nodemon exists
function cleanup() {
node && node.kill();
fs.unlink(flag);
child && child.kill();
// fs.unlink(flag);
}
// control arguments test for "help" or "--help" or "-h", run the callback and exit
controlArg(nodeArgs, 'help', function () {
usage();
process.exit();
});
function getNodemonArgs() {
var args = process.argv,
len = args.length,
i = 2,
dir = process.cwd(),
indexOfApp = -1;
controlArg(nodeArgs, 'version', function () {
sys.print('v' + meta.version + '\n');
process.exit();
});
for (; i < len; i++) {
if (path.existsSync(dir + '/' + args[i])) {
// double check we didn't use the --watch or -w opt before this arg
if (args[i-1] && (args[i-1] == '-w' || args[i-1] == '--watch')) {
// ignore
} else {
indexOfApp = i;
break;
}
}
}
// look for delay flag
controlArg(nodeArgs, 'delay', function (arg, i) {
var delay = nodeArgs[i+1];
nodeArgs.splice(i, 2); // remove the delay from the arguments
app = nodeArgs[0];
if (delay) {
sys.log('[nodemon] Adding delay of ' + delay + ' seconds');
restartDelay = delay * 1000; // in seconds
if (indexOfApp == -1) {
// not found, so assume we're reading the package.json and thus swallow up all the args
indexOfApp = len;
}
});
controlArg(nodeArgs, 'js', function (arg, i) {
nodeArgs.splice(i, 1); // remove this flag from the arguments
// sys.log('[nodemon] monitoring all filetype changes');
addIgnoreRule('^((?!\.js$).)*$', true); // ignores everything except JS
app = nodeArgs[0];
});
var appargs = process.argv.slice(indexOfApp),
app = appargs[0],
nodemonargs = process.argv.slice(2, indexOfApp),
arg,
options = {
delay: 1,
watch: [],
exec: 'node',
verbose: true,
js: false, // becomes the default anyway...
includeHidden: false
// args: []
};
// process nodemon args
while (arg = nodemonargs.shift()) {
if (arg === '--help' || arg === '-h' || arg === '-?') {
return help(); // exits program
} else if (arg === '--version' || arg == '-v') {
return version(); // also exits
} else if (arg == '--js') {
options.js = true;
} else if (arg == '--quiet' || arg == '-q') {
options.verbose = false;
} else if (arg == '--hidden') {
options.includeHidden = true;
} else if (arg === '--watch' || arg === '-w') {
options.watch.push(nodemonargs.shift());
} else if (arg === '--delay' || arg === '-d') {
options.delay = parseInt(nodemonargs.shift());
} else if (arg === '--exec' || arg === '-x') {
options.exec = nodemonargs.shift();
} else { //if (arg === "--") {
// Remaining args are node arguments
appargs.unshift(arg);
}
}
controlArg(nodeArgs, '--debug', function (arg, i) {
nodeArgs.splice(i, 1);
app = nodeArgs[0];
nodeArgs.unshift('--debug'); // put it at the front
});
var program = { nodemon: nodemonargs, options: options, args: appargs, app: app };
if (!nodeArgs.length || !path.existsSync(app)) {
// try to get the app from the package.json
// doing a try/catch because we can't use the path.exist callback pattern
// or we could, but the code would get messy, so this will do exactly
// what we're after - if the file doesn't exist, it'll throw.
try {
app = JSON.parse(fs.readFileSync('./package.json').toString()).main;
if (nodeArgs[0] == '--debug') {
nodeArgs.splice(1, 0, app);
} else {
nodeArgs.unshift(app);
getAppScript(program);
return program;
}
function getAppScript(program) {
if (!program.args.length) {
// try to get the app from the package.json
// doing a try/catch because we can't use the path.exist callback pattern
// or we could, but the code would get messy, so this will do exactly
// what we're after - if the file doesn't exist, it'll throw.
try {
// note: this isn't nodemon's package, it's the user's cwd package
program.app = JSON.parse(fs.readFileSync('./package.json').toString()).main;
} catch (e) {
// no app found to run - so give them a tip and get the feck out
help();
}
} else {
program.app = program.args.slice(0, 1);
}
program.app = path.basename(program.app);
program.ext = path.extname(program.app);
if (program.ext === '.coffee') {
//coffeescript requires --nodejs --debug
var debugIndex = program.args.indexOf('--debug');
if (debugIndex >= 0 && program.args.indexOf('--nodejs') === -1) {
program.args.splice(debugIndex, 0, '--nodejs');
}
} catch (e) {
// no app found to run - so give them a tip and get the feck out
usage();
process.exit();
// monitor both types - TODO possibly make this an option?
program.ext = '.coffee|.js';
program.exec = 'coffee';
}
}
sys.log('[nodemon] v' + meta.version);
function version() {
console.log(meta.version);
process.exit(0);
}
function help() {
util.print([
'',
' Usage: nodemon [options] [script.js] [args]',
'',
' Options:',
' -d, --delay n throttle restart for "n" seconds',
' -w, --watch dir watch directory "dir". use once for each',
' directory to watch',
' -x, --exec app execute script with "app", ie. -x python',
' -q, --quiet minimise nodemon messages to start/stop only',
' -v, --version current nodemon version',
' -h, --help you\'re looking at it',
'',
' Note: if the script is omitted, nodemon will try to ',
' read "main" from package.json and without a .nodemonignore,',
' nodemon will monitor .js and .coffee by default.',
'',
' Examples:',
'',
' $ nodemon server.js',
' $ nodemon -w ../foo server.js apparg1 apparg2',
' $ PORT=8000 nodemon --debug-brk server.js',
' $ nodemon --exec python app.py',
'',
' For more details see http://github.com/remy/nodemon/',
''
].join('\n') + '\n');
process.exit(0);
}
if (program.options.delay) {
restartDelay = program.options.delay * 1000;
}
// this is the default - why am I making it a cmd line opt?
if (program.options.js) {
addIgnoreRule('^((?!\.js|\.coffee$).)*$', true); // ignores everything except JS
}
if (program.options.watch && program.options.watch.length > 0) {
program.options.watch.forEach(function (dir) {
dirs.push(path.resolve(dir));
});
} else {
dirs.unshift(process.cwd());
}
// anything left over in program.args should be prepended to our application args
// like --debug-brk, etc
if (program.nodemon.length) {
program.args = program.nodemon.concat(program.args);
}
if (!program.app) {
help();
}
if (program.options.verbose) util.log('[nodemon] v' + meta.version);
// this was causing problems for a lot of people, so now not moving to the subdirectory
// process.chdir(path.dirname(app));
app = path.basename(app);
sys.log('\x1B[32m[nodemon] watching: ' + process.cwd() + '\x1B[0m');
sys.log('[nodemon] running ' + app);
dirs.forEach(function(dir) {
if (program.options.verbose) util.log('\x1B[32m[nodemon] watching: ' + dir + '\x1B[0m');
});
if (program.options.verbose) util.log('[nodemon] running ' + program.app);
startNode();
setTimeout(startMonitor, timeout);
path.exists(ignoreFilePath, function (exists) {

@@ -264,8 +373,9 @@ if (!exists) {

if (exists) {
sys.log('[nodemon] detected old style .nodemonignore');
if (program.options.verbose) util.log('[nodemon] detected old style .nodemonignore');
ignoreFilePath = oldIgnoreFilePath;
} else {
// don't create the ignorefile, just ignore the flag & JS
addIgnoreRule(flag);
addIgnoreRule('^((?!\.js$).)*$', true);
// addIgnoreRule(flag);
var ext = program.ext.replace(/\./g, '\\.');
addIgnoreRule('^((?!' + ext + '$).)*$', true);
}

@@ -283,10 +393,10 @@ });

// by accident and then try again later).
if (path.existsSync(flag)) fs.unlinkSync(flag);
fs.writeFileSync(flag, '');
fs.chmodSync(flag, '666');
// if (path.existsSync(flag)) fs.unlinkSync(flag);
// fs.writeFileSync(flag, '.'); // requires some content https://github.com/remy/nodemon/issues/36
// fs.chmodSync(flag, '666');
// remove the flag file on exit
process.on('exit', function (code) {
if (program.options.verbose) util.log('[nodemon] exiting');
cleanup();
sys.log('[nodemon] exiting');
});

@@ -305,7 +415,9 @@

// TODO on a clean exit, we could continue to monitor the directory and reboot the service
// on exception *inside* nodemon, shutdown wrapped node app
process.on('uncaughtException', function (err) {
sys.log('[nodemon] exception in nodemon killing node');
sys.error(err.stack);
util.log('[nodemon] exception in nodemon killing node');
util.error(err.stack);
cleanup();
});

@@ -12,5 +12,8 @@ {

"keywords": ["monitor", "development", "restart", "autoload", "reload", "terminal"],
"version": "0.5.7",
"version": "0.6.0",
"preferGlobal" : "true",
"dependencies": {
"commander": "0.5.1"
},
"main": "./nodemon"
}

@@ -39,4 +39,24 @@ # nodemon

Finally, if you have a `package.json` file for your app, you can omit the main script entirely and `nodemon` will read the `package.json` for the `main` property and use that value as the app.
If you have a `package.json` file for your app, you can omit the main script entirely and `nodemon` will read the `package.json` for the `main` property and use that value as the app.
# Automatic re-running
`nodemon` was original written to restart hanging processes such as web servers, but now supports apps that cleanly exit. If your script exits cleanly, `nodemon` will continue to monitor the directory (or directories) and restart the script if there are any changes.
# Running non-node scripts
`nodemon` can also be used to execute and monitor other programs. `nodemon` will read the file extension of the script being run and monitor that extension instead of .js if there's no .nodemonignore:
nodemon -exec python ./app.py
Now nodemon will run `app.py` with python, and look for new or modified files with the `.py` extension.
# Monitoring multiple directories
By default `nodemon` monitors the current working directory. If you want to take control of that option, use the `--watch` option to add specific paths:
nodemon --watch app --watch libs app/server.js
Now `nodemon` will only restart if there are changes in the `./app` or `./libs` directory. By default `nodemon` will traverse sub-directories, so there's no need in explicitly including sub-directories.
# Delaying restarting

@@ -71,5 +91,1 @@

* File patterns (this is converted to a regex, so you have full control of the pattern)
# Prerequisites
`nodemon` currently depends on the [unix find](http://unixhelp.ed.ac.uk/CGI/man-cgi?find) command (which also is installed on Macs)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc