In the last article we set up a new project with NPM and installed some dependencies including Webpack. In Node.js we build code in modules and export functionality that is required by other modules. This module system is called CommonJS and we will be using this approach for both our server side Node.js code and our front end React.js code. CommonJS is not natively supported in web browsers so we need tooling to help us develop and deploy our code in this way. This is where we want to start developing with Webpack. Webpack is a module bundler that provides us with a set of tools for building modules for the browser. With Webpack we build and bundle our code into a single file (or set of files) including the static dependencies of those modules such as CSS and images.

To see how Webpack works we need to start writing some code! First we create an index.html file in the project directory from the last article named react-isomorphic. This file is the entry point to our application from a web browser. In the index.html file we want to include the JavaScript file that will be the resulting bundle produced by Webpack and a root element that we will render our React.js application into. The approach we will take in our development on this project will be mobile first so we will also need a viewport meta tag to ensure the page displays correctly on mobile devices. Write out and save the following code in the index.html file using the code editor of your choice.

index.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> <title>React isomorphic</title> </head> <body> <main id="app">Hello world from HTML</main> <script src="bundle.js" async></script> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 < ! DOCTYPE html > < html > < head > < meta charset = "UTF-8" > < meta name = "viewport" content = "width=device-width, initial-scale=1, user-scalable=no" > < title > React isomorphic < / title > < / head > < body > < main id = "app" > Hello world from HTML < / main > <script src = "bundle.js" async > </script> < / body > < / html >

Open this file in a web browser and you should see the text “Hello world from HTML” displayed on a white page. You open a file in most browsers including Chrome in the File menu under Open or Open file.

Next we want to create our first JavaScript module so that we can build and view the bundle for the first time. This module will be the entry point to our application and will be responsible for initiating and rendering the different parts of the web page using React.js. But, before we can create this file we must install the required React.js packages using NPM.

NPM install react and react dom npm install react react-dom --save-dev 1 npm install react react - dom -- save - dev

This command installs the core React.js framework (react) and the React.js DOM library (react-dom). Before we build our main module let’s do a little set up and a create a new directory inside our project folder to house our React.js application. Add a new folder named client in the root of the react-isomorphic project directory and create a new file named index.js within this folder. Recreate the following code in the index.js file, feel free to copy and paste this code but we recommend typing it out so that you get a better understanding of what it does and how to debug the code as is changes.

index.js import React from 'react'; import ReactDOM from 'react-dom'; ReactDOM.render(<div>Hello world from React</div>, document.getElementById('app')); 1 2 3 4 import React from 'react' ; import ReactDOM from 'react-dom' ; ReactDOM . render ( < div > Hello world from React < / div > , document . getElementById ( 'app' ) ) ;

We begin this file with some import statements. Import statements are how we specify the external modules we wish to import into the current module so that we are able to use them in our own code. Here we import the React core library which we need for our JSX code and the React DOM library we need to render our root component into the main tag with the id of “app” in our index.html page. For now our root component is just a div with a message.

Let’s build the bundle with Webpack for the first time to test it is working. Run the following command from the root of the react-isomorphic project directory.

Webpack bundle webpack ./client/index.js ./bundle.js --module-bind 'js=babel?{"presets": ["es2015","react"]}' 1 webpack . / client / index .js . / bundle .js -- module - bind 'js=babel?{"presets": ["es2015","react"]}'

You should see a success message with some stats about the size of the resulting bundle.js file. If not try to correct the errors shown before continuing. Breaking down this command from right to left we call the webpack command line utility program and tell it that the entry point to our application code is ./client/index.js and that the output for our bundle is the ./bundle.js file. We are using JavaScript 2015 (or ES6) to write our code so we must first run it through Babel to transpile the code into a format that is able to run in all modern browsers. To do this we use the –module-bind option and inform it that all files with the extension .js must be loaded with the Babel loader which handles the transpilation. We also pass the presets we installed for React and es2015 in the query string as a JSON object. If talk of transpilers and the different versions of JavaScript go over your head right now don’t worry as we will be explaining the code in all of the examples in this series as we work through them.

Open the index.html file in a web browser again and you should now see the message “Hello world from React” which proves to us that the bundle is built and loaded and that our React code is working. Yay!

Building self contained modules

Now we have some working code we can start to add the main component modules of our application. We will be developing these components in a self contained way where each component lives in it’s own folder. We do this so that we can keep all of the files that make up each component together to ensure that our application code is well organised and easy to restructure should we ever need to do so in the future. Let’s start this approach by creating a root component named App and importing it. Update ./client/index.js to import this new module.

index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from 'components/app'; ReactDOM.render(<App />, document.getElementById('app')); 1 2 3 4 5 import React from 'react' ; import ReactDOM from 'react-dom' ; import App from 'components/app' ; ReactDOM . render ( < App / > , document . getElementById ( 'app' ) ) ;

Here we added a new import statement to import the App component we are about to build. If we try to build our bundle with Webpack now we will see an error message telling us that the App component can’t be found so let’s add it. Before we do so we need to create two new directories. First create a folder named components inside of the client directory where our index.js file lives then inside of the components directory create another folder named app. Write out and save the following code in a file named index.js within the new app folder.

./client/components/app/index.js import React, {Component} from 'react'; class App extends Component { render() { return <div>Hello world from a React component</div>; } } export default App; 1 2 3 4 5 6 7 8 9 import React , { Component } from 'react' ; class App extends Component { render ( ) { return < div > Hello world from a React component < / div > ; } } export default App ;

We name this file index.js so that when we require it from another module using the name “components/app” the module importer knows implicitly which file is the entry point to that module. You can read more about folders as modules in the node documentation.

In the App module code we import two separate things from React. First is the default export from React which is the core library with all of it’s features and second we see the name of the Component feature in braces. We have this named import so that we can reference the Component class by just specifying the name Component in our code but we could have just as easily written this as follows.

./client/components/app/index.js import React from 'react'; class App extends React.Component { 1 2 3 import React from 'react' ; class App extends React . Component {

The Component class is the base class for all React components which provides a set of life cycle methods that we can choose to implement to make our own components behave in a way that React understands. One method we must provide is the render method so that React can render the component into the page. We set the App class as the default export from our module and this is the only thing that we export.

Let us try to build our bundle again.

Rebuild the bundle webpack ./client/index.js ./bundle.js --module-bind 'js=babel?{"presets": ["es2015","react"]}' 1 webpack . / client / index .js . / bundle .js -- module - bind 'js=babel?{"presets": ["es2015","react"]}'

Running this should show you an error. The new component we are trying to import from ./client/index.js can’t be found. This is due to the path portion of the import statement “components/app”. We can fix this by prefixing the path “./components/app” so that the import knows to start looking for the components directory from the ./client folder where the index.js file lives or we can tell Webpack explicitly where to find the component modules. Let’s do the latter so that our code remains clean and maintainable.

For this to work we have to create a configuration file for webpack, much like the package.json configuration file for NPM. The default Webpack configuration file is named webpack.config.js and from this file we export a Node.js module containing the configuration options. We add the options we have been using up to this point with additional options for resolving our component imports.

webpack.config.js const path = require('path'); const CLIENT_DIR = path.resolve(__dirname, 'client'); module.exports = { context: CLIENT_DIR, entry: './index.js', output: { path: __dirname, filename: 'bundle.js' }, module: { loaders: [ { test: /\.js$/, include: CLIENT_DIR, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } } ] }, resolve: { alias: { components: path.resolve(CLIENT_DIR, 'components') } } }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const path = require ( 'path' ) ; const CLIENT_DIR = path . resolve ( __dirname , 'client' ) ; module . exports = { context : CLIENT_DIR , entry : './index.js' , output : { path : __dirname , filename : 'bundle.js' } , module : { loaders : [ { test : / \ . js $ / , include : CLIENT_DIR , loader : 'babel-loader' , query : { presets : [ 'es2015' , 'react' ] } } ] } , resolve : { alias : { components : path . resolve ( CLIENT_DIR , 'components' ) } } } ;

We use the older CommonJS syntax seen in Node.js to export from our module in this file which may be a little confusing at this point. We will write our Node.js code in JS2015 format at a later stage using babel-node but here we will stick to this format to save additional setup.

In the configuration we tell Webpack the same information as before but in a different format. We define where our source code lives with the context option and which file is the entry point. We provide the output options for the bundle in the output section and list which loaders we require to use to build our code in the modules section. For each loader we define how to test the file name using a simple regular expression to know which files the loader should be applied. In addition there is now the resolve section with an alias telling Webpack where to resolve the components directory that is was unable to find before. With this file in the root of our react-isomorphic directory we can build our bundle by just running.

Build the bundle using webpack.config.js webpack 1 webpack

Once successfully built open the index.html file once again in the browser and you should see the message “Hello world from a React component”.

Component style imports

Although it may not feel like it right now you have come a long way toward building some meaningful components for our application. Before we move on to these though let us first install a some new loaders for Webpack that will allow us to include styling for our components. In this series we will be using LESS to write our CSS code so we will need to install the less, css and style loaders.

Install less and style loaders npm install less less-loader style-loader css-loader --save-dev 1 npm install less less - loader style - loader css - loader -- save - dev

The style-loader is responsible for injecting the component styles into the head tag of the index.html page, the css-loader for parsing the css rules from our stylesheets and the less loader for generating these rules from our LESS files. For these loaders to work we need to add a new loader entry to our webpack.config.js file to handle files with the .less file extension.

webpack.config.js with new less stylesheet loader const path = require('path'); const CLIENT_DIR = path.resolve(__dirname, 'client'); module.exports = { context: CLIENT_DIR, entry: './index.js', output: { path: __dirname, filename: 'bundle.js' }, module: { loaders: [ { test: /\.js$/, include: CLIENT_DIR, loader: 'babel-loader', query: { presets: ['es2015', 'react'] } }, { test: /\.less$/, loader: 'style-loader!css-loader!less-loader' } ] }, resolve: { alias: { components: path.resolve(CLIENT_DIR, 'components') } } }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 const path = require ( 'path' ) ; const CLIENT_DIR = path . resolve ( __dirname , 'client' ) ; module . exports = { context : CLIENT_DIR , entry : './index.js' , output : { path : __dirname , filename : 'bundle.js' } , module : { loaders : [ { test : / \ . js $ / , include : CLIENT_DIR , loader : 'babel-loader' , query : { presets : [ 'es2015' , 'react' ] } } , { test : / \ . less $ / , loader : 'style-loader!css-loader!less-loader' } ] } , resolve : { alias : { components : path . resolve ( CLIENT_DIR , 'components' ) } } } ;

We can now add a style sheet for our App component. In the ./client/components/app directory create a new file named style.less containing the following styles and save it.

style.less for the App component html { background-color: #f2f2f2; font-family: Helvetica, Arial, sans-serif; } #app { background-color: white; margin: 0 auto; max-width: 600px; padding: 20px; text-align: center; } 1 2 3 4 5 6 7 8 9 10 11 12 html { background-color : #f2f2f2 ; font-family : Helvetica, Arial, sans-serif ; } #app { background-color : white ; margin : 0 auto ; max-width : 600px ; padding : 20px ; text-align : center ; }

Import these styles into the App component in ./client/components/app/index.js by adding a new import statement for the style sheet.

App component with styles imported import React, {Component} from 'react'; import {} from './style.less'; class App extends Component { render() { return <div>Hello world from a React component</div>; } } export default App; 1 2 3 4 5 6 7 8 9 10 import React , { Component } from 'react' ; import { } from './style.less' ; class App extends Component { render ( ) { return < div > Hello world from a React component < / div > ; } } export default App ;

Note that the import statement specifies no name for the module being imported as we do not require any reference to the imported styles in our code. All we want here is for Webpack to build them into the page for us. Run the webpack command once again to build the bundle and open the index.html page in the browser. If successfully built you should see the component message displayed on a grey background in a white box in the centre of the page.

We’ve covered a lot in this article but there is much more in Webpack for us to explore yet. In the next article we will be setting up our application server with Express so that we are able to serve our index.html page dynamically. After that we will return to building React.js components with the addition of development tooling that will automatically build our bundle after each change and reload our application for us.

If you’ve enjoyed the series so far why not sign up for free and receive updates about new article as we release them.