Skip to content

Instantly share code, notes, and snippets.

@webdesserts
Last active April 3, 2023 08:16
Show Gist options
  • Select an option

  • Save webdesserts/5632955 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

👍 worked great!

@jhartman86
Copy link
Copy Markdown

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

@grebett
Copy link
Copy Markdown

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
Copy Markdown

Great !. It work for me.

@machadogj
Copy link
Copy Markdown

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

@RodrigoBastos
Copy link
Copy Markdown

Great work! 👍

@khalilovcmd
Copy link
Copy Markdown

Perfect!

@josephjaniga
Copy link
Copy Markdown

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

@roobottom
Copy link
Copy Markdown

Brilliant! Thanks for this, saved me countless hours.

@connect-dips
Copy link
Copy Markdown

Works just perfect! Awesome!

@Squeezo
Copy link
Copy Markdown

Squeezo commented Feb 23, 2016

Thanks for sharing!

@robmclarty
Copy link
Copy Markdown

great little piece of nodesauce. <3

@TejasCMehta
Copy link
Copy Markdown

Awesome!! 👍

@sylvery
Copy link
Copy Markdown

sylvery commented Jul 6, 2016

Thanks a million! Saved me a lot of research :) 👍

@mircolac
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

ghost commented Nov 18, 2016

Thanks!

@alpertuna
Copy link
Copy Markdown

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

@ncodes
Copy link
Copy Markdown

ncodes commented Dec 30, 2016

Awesome! Thanks

@behrank
Copy link
Copy Markdown

behrank commented Jan 31, 2017

nice work!

@crowmagnumb
Copy link
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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

@tiagosiebler
Copy link
Copy Markdown

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
Copy Markdown

Awesome! Big thanks

@0xjorgev
Copy link
Copy Markdown

Awesome! this saves tons of time!

@longtc
Copy link
Copy Markdown

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
Copy Markdown

B3none commented Aug 4, 2018

👍

@lgcavalheiro
Copy link
Copy Markdown

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