Automatically refresh the browser on Node / Express

Quote from https://dev.to/cassiolacerda/automatically-refresh-the-browser-on-node-express-server-changes-x1f680-1k0o/.

One of the first things that most developers learn when starting with ExpressJS is using Express Generator to create a basic app structure. After install, a simple working app can be seen just running npm start in the command line. Other javascript frameworks like ReactJs, have something similar with Create React App.

Who already started a ReactJs project knows how good it is to make changes in source code with your favorite editor, and see all of them to be updated in the browser automatically. However, Express Generator unfortunately doesn’t give us that behaviour by default.

Create React App 🙂

Express Generator 😔

To do that, let’s make a few changes to our Express server so that it behaves the way we need it. Let’s code! 🤟

1) Create an ExpressJS server from scratch

Install the express-generator package:

npm install -g express-generator

Create the app:

express express-browser-reload --view=hbs
  • express-browser-reload: the folder name where the files will be created inside;
  • --view=hbs: the default template engine used to create the project (I like handlebars .hbs);

Install dependencies:

npm install

Start your Express.js app at http://localhost:3000/ :

npm start

Now we have the above example running.

2) Get the power!

Let’s add some extra packages to the project to achieve our goal:

npm i -D nodemon livereload connect-livereload
  • -D: install packages as dev dependencies is a good practice here;

3) Restart the server on changes

Currently, our server doesn’t even restart when we make changes in source code. Our first step is to set Nodemon to watch those changes. In the package.json, add watch script to enable it:

package.json

"scripts": {
  "start": "node ./bin/www",
  "watch": "nodemon"
},

By default, Nodemon watches for changes only to files with these extensions:

  • js
  • mjs
  • json

If you want to watch for changes in all project files, set additional param --ext with * or specific extensions separated with commas js,hbs,css:

package.json

"scripts": {
  "start": "node ./bin/www",
  "watch": "nodemon --ext *"
},

From now on, run the server with npm run watch instead of npm start.

Alt Text

Now your ExpressJS server restarts automatically on any file changes, but not yet updates the browser when they occur.

4) Refresh the browser on changes

In the app.js file, three main changes must be done.

app.js

var livereload = require("livereload");
var connectLiveReload = require("connect-livereload");

Import livereload and connect-livereload to enable the feature in our server.

app.js

const liveReloadServer = livereload.createServer();
liveReloadServer.server.once("connection", () => {
  setTimeout(() => {
    liveReloadServer.refresh("/");
  }, 100);
});

Create a Livereload server and listen to connection events. 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.js

app.use(connectLiveReload());

Lastly, we use connect middleware for adding the Livereload script to the response.

After all modifications, our app.js will be like this:

app.js (done)

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var livereload = require("livereload");
var connectLiveReload = require("connect-livereload");

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

const liveReloadServer = livereload.createServer();
liveReloadServer.server.once("connection", () => {
  setTimeout(() => {
    liveReloadServer.refresh("/");
  }, 100);
});

var app = express();

app.use(connectLiveReload());

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

.. and the magic happens!