Setting up a minimal Node environment with Webpack and Babel
Tags: node, webpack, react, express
Published: 2018-02-15 21:53:54

---
title: Setting up a minimal Node environment with Webpack and Babel
published: true
description: A starter project that can be use with express and react
tags: nodejs, webpack, react, expressjs
---

Today I am going to explain how I use babel to quickly enable ES6 when working in node, and how webpack can be used when working with react.

Since this is for node, we would obviously need to have node and npm (or yarn) installed - the installation for those two is beyond the scope of this tutorial.

Next, we should install `nodemon` and `babel-node` globally. 

    npm install -g nodemon babel-node

This means that those two packages are installed on your computer and will work for any future projects and any set up independent on your local computer. 

## Getting started

As per every node project, the best way to start is by creating a directory and running `npm init -y` into it from the terminal (`-y` automatically answers yes to all the questions that you'd otherwise need to answer or manually skip). This would create the `package.json` file which keeps track of the packages required. 

Now create another file, you can do this through the terminal `touch .babelrc`. This is the babel configuration file. This is where we'll let babel know what we need it to look out for. In it add the following code: 

    {"presets": ['env']}

Up to the point of writing this tutorial I had used `es2015-node5` (which I can't remember why it worked better than `es2015`) but according to the documentation we just need to use the `env` preset.

As per the [documentation](http://babeljs.io/env):

> `babel-preset-env` is a new preset, first released over a year ago that replaces many presets that were previously used including: babel-preset-es2015, babel-preset-es2016, babel-preset-es2017, babel-preset-latest [and] other community plugins involving es20xx: **babel-preset-node5**, babel-preset-es2015-node, etc

With `.babelrc` configured, we just need to install the `babel-preset-env`

    npm install babel-preset-env --save-dev

## Testing what we have so far

To the setup we have so far, let's make a `server.js` file (it can be called anything you like) and write the boilerplate for an express application 

```javascript 
import express from 'express'; 
const app = express();
app.get('/', (req, res) => {
    res.send('Hello World')
})
app.listen(4000, () => {
  console.log('Listening');
});
```

That's just to test whether the ES6 code will work. With that in place, lets use the two globally installed modules to compile and run the above file:

    nodemon --exec babel-node server.js

Running `nodemon` is like running `node` but with the first the script reruns when ever we make changes to `server.js` whereas `babel-node` compiles the code in `server.js` based on the settings we specified in `.babelrc` 

## Using webpack to configure react

On top of the above setup, we are able to add support for react but this time we need to make use of webpack (and express).

Lets visualise the file structure that our boilerplate is going to end up with

```
root/
    .babelrc
    package.json
    server.js
    webpack.config.js
    client/
        style/
            style.css
        index.html 
        index.js
```

We already created the first three files. The `client` folder is going to have the react project files. A very basic setup would be the following:

In `client/index.js` lets write the basics of a react app:

```javascript 
import React from 'react';
import ReactDOM from 'react-dom';
import './style/style.css';
const App = () => {
  return <div>Hello World</div>
}
ReactDOM.render(
  <App />,
  document.querySelector('#root')
);
```

(Remember you'd need to install the `react` and `react-dom` packages)

In `client/index.html` we have the most basic html code:

```html
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
	<div id="root" />
</body>
</html>
```

(Clearly you'd want more in there, `viewport` settings and so forth)

Note how even though `index.js` should be connected to `index.html` at the moment we aren't connecting them. We'd do that with webpack.

First let's tell babel to watch for the react syntax as well - we do that in `.babelrc`: 

    {"presets": ['env', 'react']}

Of course we'd need to install the preset: `npm i --save-dev babel-preset-react`

## Configuring webpack 

Lets create `webpack.config.js` and write the basic structure.

```javascript 
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import LiveReloadPlugin from 'webpack-livereload-plugin'

export default  {
  entry: './client/index.js',
  output: {
    path: '/',
    filename: 'bundle.js'
  },
  module: {
    rules: [... ]
  },
  plugins: [..]
};
```

First we import all the packages that need: `webpack` of course, and two plugins which we'll cover when we use then. 

The object that we're exporting contains all the webpack configuration. Again, since we are using webpack to manage our react code, we're specifying the entry point to be the main react code, webpack will take that, compile it and output it as es5 code at `bundle.js` (it never appears as a raw file in your directory but it can be accessed in the browser `/bundle.js`)

Before we move on, lets install the packages we imported above

    npm install --save-dev webpack html-webpack-plugin webpack-livereload-plugin 

## Setting up webpack rules

Inside `module.rules` we are able to get webpack to perform all sorts of operations based on the rules we specify. 

The first rule of course will be for webpack to compile all our javascript code to ES5, and the second rule is to treat all our css code as css!

```javascript
export default  {
  ...
  module: {
    rules: [
      {
        use: 'babel-loader',
        test: /\.js$/,
        exclude: /node_modules/
      },
      {
        use: ['style-loader', 'css-loader'],
        test: /\.css$/
      }
    ]
  },
  ...
};
```

Very self explanatory, we are basically making sure that if the file being processed is with a `.js` extension, run it through `babel-loader` package (excluding the node modules).

If the file has a `.css` extension, run it through the `style-loader` and `css-loader` package.

Whilst we do not import these packages, we do need to have them installed 

    npm i --save-dev babel-loader style-loader css-loader babel-core

Note that using `babel-loader` seems to require `babel-core` as well.

There are so many other rules you can add, rules concerning images, fonts, svg, minifications and lots more. 

I love SASS so let's write another rule to handle files with `.scss` extensions. Still within the `rules` array:

```javascript
{
	test: /\.scss$/,
  use: [{
      loader: "style-loader"
  }, {
      loader: "css-loader", options: {
          sourceMap: true
      }
  }, {
      loader: "sass-loader", options: {
          sourceMap: true
      }
  }]
}
```

I took the above setup straight from the [documentation](https://github.com/webpack-contrib/sass-loader#source-maps). It's similar to the other tests, however because we needed to add the options the values of the `use` array are objects. We are simply ensuring that when our SASS compiles to CSS, source maps are generated (very useful for debugging SASS in the browser).

We know that we need to install the `sass-loader` just as we did with other loaders.

    npm i --save-dev sass-loader node-sass

(`sass-loader` requires the use of `node-sass`)

With that setup, in `./client/index.js` we would be able to import SASS files in our react code and webpack would handle the conversion.


## Setting up webpack plugins

So far we configured the output and the rules. Webpack knows exactly what to do when it encounters our code. Now we want to merge all our code (from the entry point) and bundle it all together

```javascript 
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import LiveReloadPlugin from 'webpack-livereload-plugin'

export default  {
  entry: './client/index.js',
  ....
  plugins: [
    new HtmlWebpackPlugin({
      template: 'client/index.html'
    }),
    new LiveReloadPlugin()
  ]
};
```

The first plugin `HtmlWebpackPlugin` takes care to put everything together, read to be shipped. Note the entry point, and the template, webpack links the two, hence we didn't need to manually add any script tags in the `client/index.html`

## Using the bundle

We've already decided to use express to send content to the browser. It makes sense that we need to get the bundle from webpack and serve it through express. Let's do that in `server.js`:

```javascript
import express from 'express'; 
import webpack from 'webpack';
import webpackMiddleware from 'webpack-dev-middleware';
import webpackConfig from './webpack.config.js';

const app = express();
app.use(webpackMiddleware(webpack(webpackConfig)));

app.get('/api', (req, res) =>  )

app.listen(4000, () => {
  console.log('Listening');
});
```

Within our express code, we import our webpack file and let webpack create the bundle (`webpack(webpackConfig)`), then we convert it to a middleware which express can understand (`webpackMiddleware(webpack(webpackConfig))`) and finally let express use it as it's middleware.

That middleware takes the bundled react application and serves it to the home route. We can still create react routes (the `/api` is an example) but the home route is taken over by the express application.

All that's left to do is to install the middleware package we used above

    npm i --save-dev webpack-dev-middleware

## Runnig the server

Inside `package.json` lets add an `npm` start script.

```javascript
  "scripts": {
    "start": "nodemon --exec babel-node server.js  --ignore client"
  }
```

Then, in the terminal we just need to run `npm start` which in turn runs the above line. What we are doing there is; we're running `server.js` with `nodemon` and `babel-node` but we are telling them to ignore the `/client` folder. That's because, that particular folder is going to be handled by webpack instead.

## Conclusion 

You can clone the project from [github](https://github.com/aurelkurtula/minimal-node-environment)

I've hesitated to write this tutorial as I rarely need to set up my environment from scratch. However I feel I've learned a lot more about how babel, webpack and express work together by writing this. I hope you learned something too. (**If you have anything to add, please comment :)**)