Skip to content

Instantly share code, notes, and snippets.

@narirou
Last active August 29, 2015 14:02
Show Gist options
  • Save narirou/9f5ed528614dacb45459 to your computer and use it in GitHub Desktop.
Save narirou/9f5ed528614dacb45459 to your computer and use it in GitHub Desktop.
a tiny gulp-plugin: automatically restart your server for development.
'use strict';
var _ = require( 'lodash' ),
gutil = require( 'gulp-util' ),
Transform = require( 'stream' ).Transform,
fork = require( 'child_process' ).fork;
function started( callback ) {
return function() {
gutil.log( 'development server listening. ( PID:', gutil.colors.magenta( app.child.pid ), ')' );
if( callback ) callback();
};
}
function stopped( callback ) {
return function() {
gutil.log( 'development server was stopped. ( PID:', gutil.colors.magenta( app.child.pid ), ')' );
app.child = null;
if( callback ) callback();
};
}
function restarted( callback ) {
return function( error ) {
if( ! error ) {
gutil.log( gutil.colors.cyan( 'development server was restarted.' ) );
}
if( typeof callback === 'function' ) {
callback( error );
}
};
}
function app() {
var stream = new Transform({ objectMode: true });
stream._transform = function( file, encoding, callback ) {
this.push( file );
app.changed( callback );
};
stream.changed = app.changed;
return stream;
}
app.child = null;
app.defaultOptions = {
path: '',
env: { NODE_ENV: 'development' },
nodeArgs: [],
delay: 600,
messages: {
listening: /server listening/,
}
};
app.options = _.cloneDeep( app.defaultOptions );
app.listen = function( options, callback ) {
// throw error when options is not set
if( ! app.options.path && typeof options.path !== 'string' ) {
throw new gutil.PluginError( 'gulp-develop-server', 'application `path` required.' );
}
// fallback arguments
if( typeof options === 'function' ) {
callback = options;
options = {};
}
// override default options
else if( typeof options === 'object' ) {
_.merge( app.options, options );
}
// add Node's arguments
var args = app.options.nodeArgs;
if( args instanceof Array && args.length ) {
args.forEach( function( arg ){
process.execArgv.push( arg );
});
}
// run server process
app.child = fork( app.options.path, { silent: true, env: app.options.env } );
// run callback
// if not receive an error after `options.delay` seconds,
// regard the server listening success.
var timer = setTimeout( started( callback ), app.options.delay );
// timer.unref();
app.child.on( 'message', function( message ) {
if( timer && typeof message === 'string' && message.match( app.options.messages.listening ) ) {
clearTimeout( timer );
started( callback )();
}
});
app.child.stderr.on( 'data', function( error ) {
gutil.log( gutil.colors.red( 'development server error:' ) );
if( timer ) clearTimeout( timer );
if( callback ) {
var errorMessage = '' + error || null;
callback( errorMessage );
}
});
// pipe child process's stdout / stderr
app.child.stdout.pipe( process.stdout );
app.child.stderr.pipe( process.stderr );
};
app.kill = function( signal, callback ) {
// fallback arguments
if( typeof signal === 'function' ) {
callback = signal;
signal = 'SIGTERM';
}
// sending kill signall
if( app.child && app.child.connected ) {
app.child.on( 'exit', stopped( callback ) );
return app.child.kill( signal );
}
// server already stopped
if( typeof callback === 'function' ) {
process.nextTick( callback );
}
};
app.changed = app.restart = function( callback ) {
app.kill( function() {
app.listen( restarted( callback ) );
});
};
app.reset = function( callback ) {
app.kill( function() {
app.options = _.cloneDeep( app.defaultOptions );
if( callback ) callback();
})
}
module.exports = app;
// example usage:
// automatically restart by gulp-develop-server.
// livereload by gulp-livereload.
'use strict';
var gulp = require( 'gulp' ),
server = require( 'gulp-develop-server' ),
livereload = require( 'gulp-livereload' );
var src = {
server: [
'routes/**/*.js',
'models/**/*.js',
'libs/**/*.js',
'app.js',
],
resources: [
'views/**/*.jade',
'public/scripts/**/*.js',
'public/images/**/*.{png,jpg,jpeg,gif,webp,svg}'
]
};
gulp.task( 'server', function() {
server.listen( { path: 'app.js' }, livereload.listen );
});
gulp.task( 'watch', function() {
function restartServer() {
server.changed( function( error ) {
if( ! error ) livereload.changed();
});
}
gulp.watch( src.server, restartServer );
gulp.watch( src.resources, livereload.changed );
});
gulp.task( 'default', [ 'server', 'watch' ] );
@narirou
Copy link
Author

narirou commented Jul 5, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment