Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js - Auto Refresh In Dev

I am trying to improve the DEV experience in my Node. To do that, I want to:

a) restart my server when server-side code is changed
b) refresh the browser when client-side code is changes.

In an effort to accomplish this, I began integrating nodemon and browserSync into my gulp script.

In my gulp script, I have the following task:

gulp.task('startDevEnv', function(done) {
    // Begin watching for server-side file changes
    nodemon(
        { script: input.server, ignore:[input.views] })
        .on('start', function () {
            browserSync.init({
                proxy: "http://localhost:3002"
            });
        })
    ;    

    // Begin watching client-side file changes
    gulp.watch([ input.css, input.js, input.html ], function() { browserSync.reload(); });
    done();
});

When the above task runs, my browser opens to http://localhost:3000/. My app is visible as expected. However, in the console window, I notice:

Error: listen EADDRINUSE :::3002

I understand to some extend. I have app.set('port', process.env.PORT || 3002); in my server.js file. Yet, I thought that was purpose of setting the proxy value. Still, whenever I make a code change, I see the following related error in my console window:

[07:08:19] [nodemon] restarting due to changes...
[07:08:19] [nodemon] starting `node ./dist/server.js`
events.js:142
      throw er; // Unhandled 'error' event
      ^

TypeError: args.cb is not a function
    at Object.init (/Users/me/Website/Develop/node_modules/browser-sync/lib/public/init.js:25:25)
    at null.<anonymous> (/Users/me/Website/Develop/gulpfile.js:142:25)
    at emitNone (events.js:73:20)
    at emit (events.js:167:7)
    at Object.run (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:97:7)
    at Function.run.kill (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:221:7)
    at null.<anonymous> (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:333:7)
    at emitOne (events.js:83:20)
    at emit (events.js:170:7)
    at restartBus (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/watch.js:162:7)
Me-MBP:Develop me$ events.js:142
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE :::3002
    at Object.exports._errnoException (util.js:856:11)
    at exports._exceptionWithHostPort (util.js:879:20)
    at Server._listen2 (net.js:1238:14)
    at listen (net.js:1274:10)
    at Server.listen (net.js:1370:5)
    at Object.<anonymous> (/Users/me/Website/Develop/dist/server.js:70:8)
    at Module._compile (module.js:399:26)
    at Object.Module._extensions..js (module.js:406:10)
    at Module.load (module.js:345:32)
    at Function.Module._load (module.js:302:12)

At this point, my code changes do not appear in my browser. I do not understand what I'm doing wrong. I suspect I have my ports misconfigured. But, I'm not really sure how they should be setup.

By default BrowserSync uses port 3000. BrowserSync also uses port 3001 for the BrowserSync UI. For these two reasons, I thought I would set the port to 3002 in my server.js file and create the proxy shown above. What am I doing wrong?

like image 853
JQuery Mobile Avatar asked Mar 03 '16 12:03

JQuery Mobile


People also ask

Which package is used to refresh the node js code automatically as we save it?

Introduction. Nodemon is an open-source utility package that keeps track of the changes made to your source code and restarts your project server automatically when new modifications are made.

How do I restart node server automatically?

Running non-Node code While Nodemon is running, we can manually restart our application. So instead of stopping and restarting Nodemon, we can just type rs and press enter, and Nodemon will restart the server or the running process for us.

Can Nodemon refresh browser?

When Nodemon restarts the ExpressJS server on changes, Livereload recreates the server and sends to the browser a refresh command when connected liveReloadServer. refresh("/"); . app.

How does live reloading work?

Live reload is an automated approach to restarting our application during development. It enables our app to automatically and simultaneously pick up code changes while we are coding. Enabling this saves you countless manual and tedious restarts.


4 Answers

You actually don't need to use gulp for this to work.

a) restart my server when server-side code is changed

Install nodemon globally using npm i -g nodemon then on your app folder do nodemon or nodemon ${index-file-of-your-app}.

b) refresh the browser when client-side code is changes.

Use browserify or webpack. I prefer using webpack; you may need to learn about the configuration a little bit but the good thing with webpack is that you don't need to refresh it. Once changes are found the changes will be reflected on the browser automatically. https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack

like image 129
mateeyow Avatar answered Oct 21 '22 17:10

mateeyow


You can livereload both front and backend changes to the browser by using the 'livereload', 'connect-livereload', and 'nodemon' packages together. Also, this way you don't need Gulp or Grunt. Here's how the packages play together:

  • livereload opens a high port and notifies the browser of changed public files
  • connect-livereload monkey patches every served HTML page with a snippet that connects to this high port
  • nodemon is then used to restart the server on changed backend files

Set up livereload in Express

Set up the Express to both start livereload server watching the public directory and ping the browser during nodemon-induced restart:

const livereload = require("livereload");
const connectLivereload = require("connect-livereload");

// open livereload high port and start to watch public directory for changes
const liveReloadServer = livereload.createServer();
liveReloadServer.watch(path.join(__dirname, 'public'));

// ping browser on Express boot, once browser has reconnected and handshaken
liveReloadServer.server.once("connection", () => {
  setTimeout(() => {
    liveReloadServer.refresh("/");
  }, 100);
});

const app = express();

// monkey patch every served HTML so they know of changes
app.use(connectLivereload());

Start Express with nodemon

Then you'd start the server with nodemon, for example, with a dedicated watch script by running npm run watch.

The key point here is to ignore the public directory that's already being watched by livereload. You can also configure files with non-default extensions, like pug and mustache, to be watched.

"scripts": {
  "start": "node ./bin/www",
  "watch": "nodemon --ext js,pug --ignore public"
},

You can read a longer explanation in "Refresh front and backend changes to browser with Express, LiveReload and Nodemon."

like image 25
pspi Avatar answered Oct 21 '22 19:10

pspi


@mateeyow is right.

But if you want the browser to reload automaticaly, you also need livereload-plugin.

Enable webpack-hot-replacement only replace code in browser's memory, livereload-plugin do reload it.

See rock for example: https://github.com/orange727/rock/blob/master/app/templates/webpack/webpack.make.js#L255

Just as:

webpackConfig.plugins: [
  new webpack.HotModuleReplacementPlugin(),
  new LiveReloadPlugin({
    appendScriptTag: true,
    port: config.ports.livereload,
})];
like image 1
Jane Avatar answered Oct 21 '22 18:10

Jane


I might be missing some context (e.g. I'm not sure what input represents), however, I think the npm module reload might solve your problem. Here's an example from the npm package page:

var express = require('express')
  , http = require('http')
  , path = require('path')
  , reload = require('reload')
  , bodyParser = require('body-parser')
  , logger = require('morgan')

var app = express()

var publicDir = path.join(__dirname, '')

app.set('port', process.env.PORT || 3000)
app.use(logger('dev'))
app.use(bodyParser.json()) //parses json, multi-part (file), url-encoded  

app.get('/', function(req, res) {
  res.sendFile(path.join(publicDir, 'index.html'))
})

var server = http.createServer(app)

//reload code here 
//optional reload delay and wait argument can be given to reload, refer to [API](https://github.com/jprichardson/reload#api) below 
reload(server, app, [reloadDelay], [wait])

server.listen(app.get('port'), function(){
  console.log("Web server listening on port " + app.get('port'));
});
like image 1
Trevor Avatar answered Oct 21 '22 18:10

Trevor