Webpack And ReactJs

By: Stephen Patrick | 26 Sep 2016 | Category: ReactJs Packaging

Webpack And React

Webpack is a packaging tool that can be used to bundle web resources, such as JavaScript, css etc. When approaching React development it is important to have a build environment in place to aid with development activities. One such activity, is transforming JSX to JavaScript code, another is modularizing our JavaScript code. Webpack supports both of these tasks. We can use Webpack to break our JavaScript code into modules following the CommonJs format, ES6 module format, or a different format that we choose. Webpack can also transform our JSX code to its JavaScript equivalent.

We will first create a simple application and configure Webpack, to build our project. Then we will modify the application integrating React. We will begin by setting up Webpack.

Webpack Setup

To install Webpack Node.js is required, and NPM is required for managing dependencies. We will begin by setting up Webpack. Create a new directory named reactjs-webpack

mkdir reactjs-webpack

Next, NPM must be initialized from inside of reactjs-webpack.

npm init

Next, we will install Webpack as a local development dependency. This has the advantage of using a project specific version. Webpack will be installed to the local node_modules directory.

npm install webpack --save-dev

Moreover, notice above that we used the save-dev instead of save to save the dependency as a development dependency rather than a application dependency. The difference is that when we bundle the project, development dependencies will not be included as part of the build.

Project Directory Structure

We will create a simple project directory structure.

/app
   - index.js
/build
   - index.html
- package.json
- webpack.config.js

Application Resources

As mentioned we will begin by creating a simple application without using React. We will add the following code to index.js.

(function() {
   var elementH1 = document.createElement('h1');
   elementH1.innerHTML = 'Hello Webpack!';


   var app = document.createElement('div');
   document.body.appendChild(app);
   app.appendChild(elementH1);
})();

We will also create the file index.html that will be configured as the root of our application. This file will link to the bundle created by Webpack.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Webpack, Reactjs Hello World</title>
</head>
<body>
<div id="app"></div>
<script src="./bundle.js"></script>
</body>
</html>

Webpack Configuration

With our Application resources in place we will configure Webpack to bundle our simple application. To configure Webpack a configuration file is required. We will add the configuration to the file webpack.config.js

const path = require('path');

const PATHS = {
   app: path.join(__dirname, 'app'),
   build: path.join(__dirname, 'build')
};


module.exports = {
   entry: {
       app: PATHS.app
   },
   output: {
       path: PATHS.build,
       filename: 'bundle.js'
   }
}

To build Webpack through npm we will update our package.json to add a build script.

"scripts": {
   "build": "webpack"
}

To execute the build we can now use npm.

npm run build

When the build completes, we can open up index.html in a web browser.

Webpack Hot Replacement

Instead of opening up the application in the browser, we can use the Webpack development server, that will run in the background and, refresh the content in the browser. To use the Webpack development server it must be installed as a dependency.

npm install webpack-dev-server --save-dev

With the server installed, it needs to be configured. To do this the Webpack configuration is split into separate files as the development server has its own requirements. We will create a common configuration file for building and then add this as a dependency for the server configuration and the default Webpack configuration.

First a new file webpack-build.js is created. This file holds the common configuration for building the application.

module.exports = function(options) {
   const path = require('path');

   const PATHS = {
       app: path.join(__dirname, 'app'),
       build: path.join(__dirname, 'build')
   };


   var configOptions =  {
       PATHS: PATHS,
       entry: {
           app: PATHS.app
       },
       output: {
           path: PATHS.build,
           filename: 'bundle.js'
       },
       plugins: [

       ]
  };

  if(options.devServer) {
      configOptions.devServer = options.devServer;
      configOptions.devServer.contentBase = PATHS.build;
  }

  if(options.plugins) {
      configOptions.plugins = configOptions.plugins.concat(options.plugins);
  }

  return configOptions;
}

Next we update the webpack.config.js file to use the above configuration file.

module.exports = require("./webpack-build")({

});

Next we add a new configuration file for the development server named webpack-dev-server.config.js.

var webpack = require("webpack");

module.exports = require("./webpack-build")({
   devServer: {
       historyApiFallback: true,
       hot: true,
       inline: true,
       progress: true,
       stats: 'errors-only',
       host: process.env.HOST,
       port: process.env.PORT
   },
   plugins: [
       new webpack.HotModuleReplacementPlugin()
   ]
});

Finally, we update the NPM package.json to run the development server.

"scripts": {
   "build": "webpack",
   "dev-server": "webpack-dev-server --config webpack-dev-server.config.js --content-base build",
},

The development server can now be started from the command-line.

npm run dev-server

By default the server should be started on localhost:8080. Open your browser at http://localhost:8080, and make changes to the application. The browser should update automatically to reflect these changes.

Babel

To work with JSX we will install the babel loader. Again, we install this as a development dependency.

npm install babel-loader babel-core --save-dev

We now need to change our Webpack configuration to use Babel. To do this we modify webpack-build.js. First, we need to add a resolve.extensions property to our config options.

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

We also need, to add the babel loader, to module.loaders.

module:  {
   loaders: [
       ....
       {
           test: /\.jsx?$/,
           loaders: ['babel?cacheDirectory'],
           include: PATHS.app
       }
   ]
},

With the loader configured, the next step is to configure Babel. Babel relies on a number of plugins. To make it easier to configure Babel, we can use Babel presets. A preset can consist of a number of plugins and you are free to create your own plugins.

We will use npm to install the presets for react and ES2015.

npm install babel-preset-es2015 babel-preset-react --save-dev

Babel can then be configured by creating a .babelrc file and adding it to the root of the project folder. This file will contain the presets for es2015 and react.

{
   "presets": [
       "es2015",
       "react",
   ]
}

React

To use react we will install react and react-dom as a dependency.

npm install react react-dom --save

Next we will modify our application to replace our JavaScript with a React component. We will add a file called app.jsx with the following contents

var React = require('react');
   return <div>Hello World, Components With JSX !</div>
}});

We will also rename index.js to index.jsx and update its contents.

(function() {
   var App = require('./app');
   var React = require('react');
   var ReactDom = require('react-dom');

   ReactDom.render(<App />, document.getElementById('app'));

})();

The file app.jsx contains a very simple React component. Also, above the index.jsx file imports the App component along with React. It adds the react component, to the HTTP div element with the id of app. Webpack will bundle our application converting the JSX code to JavasScript code.

Css Style Sheets

We will now add a very simple style sheet to the application, in order to see how it can be configured with Webpack. In order to use style sheets with Webpack we need to install a new loader.

npm install css-loader style-loader --save-dev

We also need to add the loader to the Webpack configuration file.

module: {
   loaders: [
       {
           test: /\.css$/,
           loaders: ['style', 'css'],
           include: PATHS.app
       }
       ...
   ]
}

Above we added the style sheet loader to recognize any file ending with .css. The loader will resolve any @import and url statements within css files. The loader is also configured to use the app directory. Add a css file named app.css with the following contents to the app directory.

body {
   background-color: #000;
   color: #FFF;
}

We must also add a reference to the app.css file within the index.jsx file.

require('./app.css');

The next time the application is viewed in the browser, Webpack will have included the app.css file as part of the bundle.