DEV Community

Cássio Lacerda
Cássio Lacerda

Posted on

Automatically refresh the browser on Node / Express server changes 🚀

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 🙂
Alt Text

Express Generator 😔
Alt Text

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
Enter fullscreen mode Exit fullscreen mode

Create the app:

express express-browser-reload --view=hbs
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode

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

npm start
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • -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"
},
Enter fullscreen mode Exit fullscreen mode

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 *"
},
Enter fullscreen mode Exit fullscreen mode

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");
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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());
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

.. and the magic happens!

Alt Text

Note that a javascript is added to our HTML page and that points to the server created by Livereload on port 35729.

Conclusion

Eliminating repetitive actions during development helps to optimize our performance as developers. Taking a few minutes to properly setup our application before you even start development is something you should always consider.

Get this working example in Github.

Top comments (18)

Collapse
 
ali_dot_ali profile image
Ali Ali

I did the same but its not reloading my files. I am using ejs.
//Newbie

Collapse
 
emasuriano profile image
Ema Suriano

Most probably is because by default nodemon watch for .js, .mjs, .coffee, .litcoffee, .json extensions. Therefore you can send the flag of -e ejs to the command of watch to make it watch your files :)

Collapse
 
faridanthony profile image
Fred Anthony

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

Collapse
 
sadkodev profile image
sadko

Config package.json thus. "dev": "nodemon --ext * ' js,html,ejs,css,scss" app.js"

Great...

Collapse
 
rdavis0 profile image
Ryan Davis

@cassiolacerda thanks for the guide! It worked great for me. Is there a way to make livereload run only in my development environment? Right now if I try to deploy to production with liveserver changes in my app.js, it breaks everything.

Collapse
 
steveblue profile image
Stephen Belovarich • Edited

You need to have a concept of environments. Typically process.env.NODE_ENV is used. After you have a environment declared, conditionally set the middleware.

const env = process.env.NODE_ENV || "development";

if (env === "development") {
  app.use(connectLiveReload());
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
iway1 profile image
iway1 • Edited

Eliminating repetitive actions during development helps to optimize our performance as developers.

Great quote! Even if something only takes a few seconds, automating it can save us hours and hours in the long run. As I've improved as a software developer, the more and more I prioritize these types of things

Collapse
 
denelvis profile image
denelvis • Edited

Hello. Can you help?
Why when I did some changes page on localhost:port/users or any other endpoint nodemon don't reload this page?

Working only on root.

Collapse
 
cassiolacerda profile image
Cássio Lacerda • Edited

Hello, guy!

Livereload works only with rendered HTML pages. It needs to inject a script tag that points to the server created by Livereload on port 35729 (see in the last section).

The endpoint /users encountered in the repo send data to client-side with res.send method, where data type generated by that is application/json. In home endpoint /, the application uses res.render to outputs text/html data, so it works here, and not in /users.

Collapse
 
denelvis profile image
denelvis

Thanks.

Collapse
 
steveblue profile image
Stephen Belovarich

This works for me although live reload is kinda slow compared to HMR in other build tools.

Collapse
 
gilenomasc profile image
gilenomasc

Worked like a charm for me. Thank you!

Collapse
 
steveblue profile image
Stephen Belovarich

This works for me although live reload is kinda slow.

Collapse
 
aklougbo profile image
aklougbo • Edited

How this can be used with NodeJs using the HTTP module to create the webserver and not EXPRESSJS

Collapse
 
hohogpb profile image
bh

good

Collapse
 
royalvictor profile image
Royal VICTOR

Thank you very much for that ! I was looking for something like that since few months !

Collapse
 
dan_kinsella_83911e371adb profile image
Dan Kinsella

bin file issues that deem this not working for me

Collapse
 
kohjean profile image
kohjean

Hi. I had a problem with bin and it didn't work like you.
This worked fine. bytearcher.com/articles/refresh-ch...
I wish you well🙏