The Hitchhiker’s guide to mastering React with ES6, WebPack and Docker. Part 1
Everyday, new tools and frameworks emerge, each of them with its pros and cons. This has led to a continuous learning curve for every programmer in the quest to finding the most efficient tool in writing highly optimised applications.
I stumbled upon React a couple of months ago and I immediately fell in love with it. The beauty of its Virtual DOM and the new ideology of components as opposed to the “2-way data binding overtly bloated frameworks” like Angular had to offer.
In this part of the series, we shall be looking at the basic configuration required to get up and running with React using ES6 and WebPack. Adopting the Repository driven development (RDD) workflow, we shall be using Docker to create an image of the React app which we shall ship to docker hub.
Lets start by initialising a node app by running in the terminal npm init
and following the prompt. You can just hit enter for now at every prompt to retain the default configuration.
This would initialise a Node app with a package.json file having a configuration that may look like this:
{ “name”: “react-tutorial”, “version”: “1.0.0”, “description”: “”, “main”: “webpack.config.js”, “scripts”: { “test”: “echo \”Error: no test specified\” && exit 1" }, “author”: “adim”, “license”: “ISC”}
At this stage, we are more concerned about the devDependencies and dependencies section of our package.json , all other configurations do not have to match.
Next, lets install all our development dependencies by running:
npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react webpack webpack-dev-server
This fetches the latest versions of the dependencies and installs them as local development dependencies for our app.
The babel-preset-es2015 and babel-preset-react are plugins used by the babel-loader to tranpile ES6 syntax and JSX syntax respectively into ES5 javascript for browsers to understand.
webpack will be used in bundling all our jsx/js files into a single js file that we shall use in our index.html file. webpack can use loaders to first transpile our files before bundling them. This is why we used the babel-loaders.
Webpack transpilation of JSX code into JS using Babel-loader
The babel loader needs some configuration and we need to tell it to use the ES6 and JSX plugins. For this we shall create a new file called .babelrc
:
nano .babelrc
Update the file to look like below:
{ "presets" : ["es2015", "react"]}
Next, we need to tell Webpack to use the babel-loader while bundling our files. For this, we shall create a new file named webpack.config.js and update it to look like below:
var path = require('path');
var BUILD_DIR = path.resolve(__dirname, 'public/js');var APP_DIR = path.resolve(__dirname, 'app/js/components');
var config = { entry: APP_DIR + '/app.jsx', output: { path: BUILD_DIR, filename: 'bundle.js', publicPath: 'public/js' }, module: { loaders : [{ test : /\.jsx?/, include : APP_DIR, loader : 'babel' }] }};
module.exports = config;
Lets take a look at the config object. We have defined an entry point called app.jsx located at public/js folder of our app’s directory. This tells webpack to start from this file to begin bundling.
The output property of our config object takes a path attribute which specifies the directory path for our bundled js file. The filename defines the name of our bundled file. We have added an optional attribute named publicPath. This is used by webpack-dev-server as its output directory. Please note that webpack-dev-server does not create an actual output file, but rather an in-memory representation of the output file. To create a production ready bundled js file, we need to run this:
webpack -p
The loaders property takes an array of loaders, here we are just using babel-loader. Each loader property should specify what are the file extension it has to process via the test property. Here we have configured it to process both .js and .jsx files using the regular expression. The include property specifies what is the directory to be used to look for these file extensions. The loader property represents the name of the loader.
The webpack-dev-server is a great tool similar to nodemon which runs a server that listens for any file changes in our app and updates the browser upon such changes.
We are done with setting up our development dependencies. Lets round up by installing our projects dependencies. Type this in the terminal:
npm install --save react react-dom
And finally, we are done with our basic configuration. Our package.json should now look like this:
{ "name": "react-tutorial", "version": "0.0.1", "description": "React tutorial using ES6, webpack and docker", "main": "webpack.config.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack -d --watch", "dev-server": "webpack-dev-server --host 0.0.0.0 --port 8080 --progress --colors", "build": "webpack -p" }, "author": "Adim", "license": "ISC", "dependencies": { "react": "^15.3.1", "react-dom": "^15.3.1" }, "devDependencies": { "babel-core": "~6.7.*", "babel-loader": "~6.2.*", "babel-preset-es2015": "^6.14.0", "babel-preset-react": "^6.11.1", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.1" }}
Please update the script section of your package.json to look like above. We shall be using it soon enough. Now, lets write some React to ensure our configuration worked out. For this, lets ensure we have this project structure:
Project-Root-Directory | |- app/ | |- js/ | |- components/ | |- app.jsx |- public/ | |- js/ | |- index.html | |- node_modules/ |- .babelrc |- webpack.config.js |- package.json
Update app.jsx to look like below:
import React from 'react';import { render } from 'react-dom';
class App extends React.Component { render(){ return <div> Hello React! </div> }}
render(<App/>, document.getElementById('container'));
Your index.html should look like this:
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>React Tutorial</title> </head> <body> <div id="container"></div> <script src="js/bundle.js"></script> </body></html>
Notice how we have included our bundled js file as a script souce.
Lets start our development server and test our app.
Run npm run dev-server
Navigate to your browser and type: http://localhost:8080
And voila!, you should see a Hello React! displayed on the browser page.
Docker
I have created a docker image for this project which is available on docker hub. Please pull this image from docker hub to get quickly running with this by typing:
docker pull adim/react-tutorial
Then run this to start a container for the image:
docker run --rm -p 8080:8080 adim/react-tutorial
You can now navigate to your browser and type: http://localhost:8080
If using docker-machine, you may need to get the address of the docker machine to open up app in the browser, use this shorthand in the terminal if you are running the default machine.
open http://$(docker-machine ip default):8080
Summary
In this post, we have seen how to get up and running with react using webpack and babel-loaders. In the next part of this tutorial, we shall see how to hook up more loaders like sass or coffee-script loaders to use alongside with react and delve deeper into react by building components.
Thanks for reading!