Skip to content

Instantly share code, notes, and snippets.

@webdesserts
Last active April 3, 2023 08:16
Show Gist options
  • Save webdesserts/5632955 to your computer and use it in GitHub Desktop.
Save webdesserts/5632955 to your computer and use it in GitHub Desktop.
Automatically reload your node.js app on file change with Gulp (https://github.com/wearefractal/gulp).
// NOTE: I previously suggested doing this through Grunt, but had plenty of problems with
// my set up. Grunt did some weird things with scope, and I ended up using nodemon. This
// setup is now using Gulp. It works exactly how I expect it to and is WAY more concise.
var gulp = require('gulp'),
spawn = require('child_process').spawn,
node;
/**
* $ gulp server
* description: launch the server. If there's a server already running, kill it.
*/
gulp.task('server', function() {
if (node) node.kill()
node = spawn('node', ['index.js'], {stdio: 'inherit'})
node.on('close', function (code) {
if (code === 8) {
gulp.log('Error detected, waiting for changes...');
}
});
})
/**
* $ gulp
* description: start the development environment
*/
gulp.task('default', function() {
gulp.run('server')
gulp.watch(['./index.js', './lib/**/*.js'], function() {
gulp.run('server')
})
// Need to watch for sass changes too? Just add another watch call!
// no more messing around with grunt-concurrent or the like. Gulp is
// async by default.
})
// clean up if an error goes unhandled.
process.on('exit', function() {
if (node) node.kill()
})
@Gerst20051
Copy link

πŸ‘ worked great!

@jhartman86
Copy link

Nice work - nodemon seemed to be causing a lot of unneccessary overhead. So... thanks!

@grebett
Copy link

grebett commented Aug 13, 2015

I've used my own version based on your idea. Simple, but very efficient. Thanks for sharing!

@inspective
Copy link

Great !. It work for me.

@machadogj
Copy link

Nice and simple! You might want to throw gulp-util to the mix, gulp.log will throw an error.

@RodrigoBastos
Copy link

Great work! πŸ‘

@khalilovcmd
Copy link

Perfect!

@josephjaniga
Copy link

Awesome, was in the process of writing this myself but you beat me to the punch. cheers 🍻

@roobottom
Copy link

Brilliant! Thanks for this, saved me countless hours.

@connect-dips
Copy link

Works just perfect! Awesome!

@Squeezo
Copy link

Squeezo commented Feb 23, 2016

Thanks for sharing!

@robmclarty
Copy link

great little piece of nodesauce. <3

@TejasCMehta
Copy link

Awesome!! πŸ‘

@sylvery
Copy link

sylvery commented Jul 6, 2016

Thanks a million! Saved me a lot of research :) πŸ‘

@mircolac
Copy link

mircolac commented Jul 7, 2016

Thanks a lot for this code. Works great!
Unfortunately gulp.run() is going to be deprecated and i was wondering if you're going to update this.
Meanwhile, i'll try to do it myself but i'm new with gulp so ... i'll try to do my best.
Thanks again anyway!

@anchal20
Copy link

anchal20 commented Aug 12, 2016

hi,
I am new to gulp and I am using gulp watch to watch the js changes. This was working fine sometime back but now gulp watch isnt watching anymore and every time I have to restart my server and run gulp command again. Please help me out!

Here is my sample gulp watch code :

**gulp.task('watch-babel', function() {
  gulp.watch('app/assets/javascripts/**/*.js', ['compile-babel']);
});**

@fyears
Copy link

fyears commented Aug 16, 2016

Great code!

But one improvement: The latest gulp does not have run(). We could use something like it to achieve the same goal:

gulp.task('default', ['server'], function() {
  gulp.watch(['./index.js', './lib/**/*.js'], ['server']);
})

(Also cc to @mircolac: My solution is the answer to your question).

Copy link

ghost commented Nov 18, 2016

Thanks!

@alpertuna
Copy link

Nice! Also thanks @machadogj for gulp-util to log.

@ncodes
Copy link

ncodes commented Dec 30, 2016

Awesome! Thanks

@behrank
Copy link

behrank commented Jan 31, 2017

nice work!

@crowmagnumb
Copy link

crowmagnumb commented Feb 10, 2017

Yes, thank you! I just made server() a function so that you don't have to rely on gulp.run or any alternative...

const gulp = require('gulp');
const spawn = require('child_process').spawn;
let node;

function server() {
    if (node) {
        node.kill();
    }

    node = spawn('node', ['src/index.js'], {stdio: 'inherit'});
    node.on('close', function (code) {
        if (code === 8) {
            gulp.log('Error detected, waiting for changes...');
        }
    });
}

gulp.task('server', function() {
    server();
});

gulp.task('watch', ['server'], function() {
    gulp.watch(['./src/**/*.js'], function() {
        server();
    });
});

gulp.task('default', ['watch']);

// clean up if an error goes unhandled.
process.on('exit', function() {
    if (node) {
        node.kill();
    }
});

@safizn
Copy link

safizn commented Mar 1, 2017

For using BrowserSync (Browser reload) with server reload.

import childProcess from 'child_process'
var browserSync = require('browser-sync').create();
let node;
const INTERVAL = 10000;
const usePolling = true;

function serverLivereload() {
    if(node) node.kill()

    node = childProcess.fork('app.entrypoint.js', { cwd: '/app', stdio:'inherit' })
    node.on('message', (m) => {
        console.log('Server ready & listening.', m);
        browserSync.reload()
    });
    node.on('close', (code) => {
        if(code === 8) {
            gulp.log('Error detected, waiting for changes.')
        }
    })
}

gulp.task('watch:livereload', ()=> {
    browserSync.init({
        proxy: {
            target: 'localhost'
        },
        logLevel: 'debug',
        logConnections: true,
        ui: {
            port: 9901,
            weinre: {
                port: 9902
            }
        },
        port: 9903,
        open: false // open browser false.
    });
    serverLivereload()

	gulp.watch(
		[ 
            '/app/**/*.js', 
            '/app/**/*.css', 
            '/app/**/*.html', 
            '!/app/**/node_modules{,/**/*}' // equals to '!/app/{node_modules,node_modules/**/*}'
        ], 
	{ interval: INTERVAL, usePolling: usePolling },  // Fixed Windows issue, requiring legacy watch 'polling'
	async (done) => {
            serverLivereload()
            done()
        }        
	);
});

Then on forked child process: /app/app.entrypoint.js

import http from 'http'
import Koa from 'koa'
const serverKoa = module.exports = new Koa()
serverKoa.use(<middlewares>)
...
    http.createServer(serverKoa.callback()).listen(APP.port, ()=> {
        console.log(`listening on port ${APP.port}`)
        process.send({ message: 'Server ready & listening'});
    })

Run with gulp watch:livereload

@tiagosiebler
Copy link

This makes everything SO much easier, awesome & thank you for sharing!

@tiagosiebler
Copy link

tiagosiebler commented Nov 16, 2017

By the way, if this launches too quickly and gets stuck. Instead of node.on('close') use node.on('sigterm') to handle the relaunch properly:

gulp.task('server', function() {
	runLiveServer();
	node.on('SIGTERM', function(code) {
		if (code === 8 || code === 12) {
			console.log('Error detected, attempting reboot...');
			setTimeout(runLiveServer, 500);
		} else {
			console.log('Relaunced with code: ', code);
		}
	});
})

@felixcatto
Copy link

Awesome! Big thanks

@0xjorgev
Copy link

Awesome! this saves tons of time!

@longtc
Copy link

longtc commented Jun 2, 2018

Never mind, I got it to work.
Make sure the task signal [Async Completion](https://github.com/gulpjs/gulp/blob/9f4a2e96506dec1d85804de8884678e72ffc5aa0/docs/getting-started/4-async-completion.md). Or, just define your task as an [`async` function](https://github.com/gulpjs/gulp/blob/9f4a2e96506dec1d85804de8884678e72ffc5aa0/docs/getting-started/4-async-completion.md#using-asyncawait):

```javascript
async function startServer() {
  if (node) node.kill();
  node = await spawn("node", ["./src/server.js"], { stdio: "inherit" });

  node.on("close", function (code) {
    if(code === 8) {
      console.log("Error detected, waiting for changes...");
    }
  });
}

gulp.task("default", function () {

  // Start the server, if a change is detected restart it
  gulp.watch(
    ["src/**/*", "src/server.js"],
    {
      queue: false,
      ignoreInitial: false // Execute task on startup 
    },
    startServer);
});
```

@B3none
Copy link

B3none commented Aug 4, 2018

πŸ‘

@lgcavalheiro
Copy link

Hey man thanks for sharing your gulpfile, you got me out of one hell of a pickle haha!
Here's how mine endend up looking, works great now :D

const gulp = require('gulp');
const watch = gulp.watch;
const series = gulp.series;
const { exec, spawn } = require('child_process');
var serverProc = undefined;

const watcher = watch(['./frontend/**/*', './backend/**/*', '!./backend/**/*.json']);

watcher.on('change', function (path, stats) {
    console.log(`File ${path} was changed - Relaunching...`);
    serverProc.kill('SIGINT');
    exports.default();
});

watcher.on('error', function (e) {
    console.error(e.stack);
});

function purge() {
    return exec('shx rm -rf ./public/*');
}

function bundle() {
    return exec('parcel build ./frontend/html/*.html --out-dir public --no-source-maps');
}

function serve() {
    if (serverProc) serverProc.kill('SIGINT');
    serverProc = spawn('node', ['backend/server.js'], { stdio: 'inherit' });
    serverProc.on('close', function (code) {
        if (code === 8) {
            gulp.log('Error detected, waiting for changes...');
        }
    });
}

exports.default = series(purge, bundle, serve);

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