Alejandro Napoles

The simplest Webpack and Express setup

March 11th, 2016

There are lots of documentation and tutorials out there for Webpack and how to configure it with React, Babel, CSS, etc., but I haven’t seen simple documentation explaining how to use Webpack bundling your client-side code with a Node server with Express, or any other similar framework, using the bundle, and having both development and production settings.

Webpack (and development in general) can be confusing sometimes. All those really new cool things you read about can be very enticing and also overwhelming if you try to have them all in your project. In the very end they are optional, and you shouldn’t feel force to use them, especially in an scenario where you’re just learning or want to make a simple application. That’s why I wanted to go back to the basics: a really simple Express server serving the bundled files, with no added complexity. Later on, we can start adding things on top of this.

In this scenario we’ll have a Node server sending an html file to the user, and this html needs the bundle file, this means the server will need to know its location. The bundle file is the result of using Webpack on the client-side code.

Make sure you have Webpack and Express installed:

npm i express -S
npm i webpack -D

We’re going to organize our project first. A src folder to save all our client code and a dist directory to save the production/development files.

The html page is not a big deal, create an index.html inside src, you can have some element with an id or class to prove that everything works:

<!DOCTYPE html >
  <html lang="en">
    <head>
      <meta charset="UTF-8">
        <title>App</title>
        <script defer src="/bundle.js"></script>
</head>
      <body>
        <div id="hello"></div>
      </body>
</html>

Webpack Configuration

Webpack can be run in the CLI, but writing all the options every time can be a chore. To solve this we’ll want to create a config file called webpack.config.js that Webpack will look to get the configuration. This is the configuration in webpack.config.js:

const path = require("path");

const DIST_DIR = path.join(__dirname, "dist");
const CLIENT_DIR = path.join(__dirname, "src");

module.exports = {
  context: CLIENT_DIR,

  entry: "./main",

  output: {
    path: DIST_DIR,
    filename: "bundle.js"
  },

  resolve: {
    extensions: ['', '.js']
  }
};

As we can see, Webpack looks for an entry file, main.js in our case in the src directory and outputs a bundle.js in dist.

If you now write webpack in the console you should see the bundle.js in the corresponding directory.

Since the main.js file doesn’t exist yet, create it inside src (the context in our Webpack config). In here, we’re going to add a text to the hello div, just to make sure everything works when we’re finished, for example:

const hello = document.getElementById("hello");
hello.innerHTML = "Hello World!";

We want to copy index.html to dist every time the project is built. You could have other requirements for your project, but mine are:

  • I want to write only npm scripts, no Gulp, Grunt, etc.

  • I want my npm scripts to be cross-compatible. E.g.: cp src/index.html dist/index.html doesn’t work on cmd.

There are several options to accomplish this, one of them could be copying the index.html with the Node API, shelljs or some other library, inside a JavaScript file and calling it in an npm script. Since we have Webpack installed, we could use it to copy the file. As you can see in the link, there are several way to do this in Webpack, I’ll use file-loader. Install the loader with: npm i file-loader -D and require the index.html inside main.js:

require("file?name=index.html!./index.html");

const hello = document.getElementById("hello");
hello.innerHTML = "Hello World!";

The require line will call the file loader with the index.html, copy it to the dist folder and give it the name index.html. Changing the name after ?name= give us, obviously, the same file but with a different name:

require("file?name=hello.html!./index.html");

The server

Now we need to set up the server, having it listen at some port and sending the index.html to the user when they enter the web. Inside server.js in the root directory we have:

const path = require("path");
const express = require("express");

const DIST_DIR = path.join(__dirname, "dist");
const PORT = 3000;
const app = express();

//Serving the files on the dist folder
app.use(express.static(DIST_DIR));

//Send index.html when the user access the web
app.get("*", function (req, res) {
  res.sendFile(path.join(DIST_DIR, "index.html"));
});

app.listen(PORT);

Final touches

We’re almost done. We need a way to tell Webpack to do its job and to start the server. For this, I’ll use npm scripts, but you can do it with other tools like Gulp or Grunt. Inside package.json we’ll write two quite simple scripts in the script section:

"scripts": {
  "start": "node server.js",
  "dev": "webpack && npm start"
}

And… we’re done. We have automated our build. Every time we want to start the server we use npm run dev. http://localhost:3000 in the browser should show our Hello World! message.

With this really basic setup, which shows the fundamental ideas, we can easily build up from here.

From this we’ll probably want a production script, a hot reloading feature to avoid having to type npm run dev every change, add support for ES6, etc. We’ll look at a few of these things in the future.


Alejandro Napoles

Written by Alejandro Napoles. Web developer. Twitter Github

Creative Commons Licence
alejandro napoles dot com byAlejandro Napoles is licensed under aCreative Commons Attribution - ShareAlike 4.0 International License