Webpack, React.js and modern JavaScript application development

Phil Parsons

Tagged: , ,

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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.

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

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.

It's only fair to share...Tweet about this on TwitterShare on FacebookShare on Google+Buffer this pageShare on LinkedInPin on Pinterest

/ 9 Articles

Phil Parsons

29 Comments

  1. Tony

    I want to use stylus so the code is

    I was going to ask how to hookup browser-sync with webpack so you don’t have to keep doing webpack to rebuild the script, but I hope that’s coming in the next article.

    Great tutorial so far!

    Reply

    • Phil Parsons

      Yes you can use Stylus or Sass interchangeably for LESS if you wish.

      We will be setting up webpack-dev-server, hot loading and nodemon very soon so stay tuned for that!

      Reply

  2. Sam

    So I tried the first webpack command and it threw an error. Not knowing what to do, I just tried my hand at creating the webpack.sonfig.js that is later in the tutorial and the command worked after that.

    Just wondering how it’s working for others without creating this file, but not for me.

    Reply

    • Phil Parsons

      Hey Sam, what was the error you were seeing? If you post the stack trace I may be able to help you understand what was wrong.

      Reply

      • thomas

        This one in my case :

        C:\Users\thomas\Desktop\aciiid\test_aciiid>webpack ./client/index.js ./bundle.js –module-bind ‘js=babel?{“presets”: [“es2015″,”react”]}’
        Hash: 90d2ddada0a452b50606
        Version: webpack 1.12.9
        Time: 82ms
        Asset Size Chunks Chunk Names
        [es2015,react]}’ 1.67 kB 0 [emitted] main
        [0] multi main 40 bytes {0} [built] [1 error]
        [1] ./client/index.js 0 bytes [built] [failed]
        [2] ./bundle.js 0 bytes {0} [built]

        ERROR in ./client/index.js
        Module parse failed: C:\Users\thomas\Desktop\aciiid\test_aciiid\client\index.js Line 1: Unexpected token
        You may need an appropriate loader to handle this file type.
        | import React from ‘react’;
        | import ReactDOM from ‘react-dom’;
        |
        @ multi main

        Reply

  3. Abel Wang

    Amazing article. I’ve been looking at webpack/React tutorials all day and yours is the only one that is not only concise, but also up to date with the most recent versions.

    Reply

  4. Devin

    Thanks for the great tutorial! Small heads up — the second webpack.config.js snippet is missing the babel query presets.

    Reply

    • Phil Parsons

      Thanks, I probably moved them to .babelrc but forgot to document it!

      Reply

      • Thomas Jones

        Anxiously awaiting the next article.

        Reply

        • Phil Parsons

          I’ll do it soon! I’ve been very busy recently but plan to crack on with these ASAP.

          Thanks!

          Reply

      • jared

        It would be extremely helpful if you could add it back. I was following the tutorial and got stuck, tried to fix it for a while, then started over cutting and pasting your code exactly which didn’t help. It took me several hours to figure this out. I was thinking it was my machine config since after the first try, I cut and pasted the code.

        When dealing with a tutorial like this, I assume I did something wrong and kept rechecking my code. I am sure a lot of newbies will get stuck here and won’t be able to do the rest of the tutorial.

        Thanks for the tutorial.

        Reply

        • Phil Parsons

          Done, apologies for that!

          Reply

  5. Markus Bergh

    I agree with previous comments, it is awesome that you have written these articles. Thank you very much for taking your time to do so, this really helps to get onboard with React.js and Node.

    Reply

    • Phil Parsons

      Thanks, I’m glad that you appreciate them.

      Reply

  6. Damien

    Hi thanks for this awesome tutorial!

    I had an error while building the app with the React component :

    ERROR in ./client/index.js
    Module not found: Error: Cannot resolve module ‘components/app’ in /Users/damien/Documents/react-iso/client
    @ ./client/index.js 11:11-36

    To fix this i’ve replaced

    import App from ‘components/app’;

    By

    import App from ‘./components/app’;

    It could be a version issue (my babel-core version is 6.5.1).

    Reply

    • Phil Parsons

      Thanks. Only reason I can think you saw that error would be not having the components alias set in your webpack configuration.

      Reply

  7. Dan

    Any advice on writing tests for the hello world? thanks!

    Reply

  8. denis

    Thanks for this great tutorial!

    I received some Errors when running:

    webpack ./client/index.js ./bundle.js –module-bind ‘js=babel?{“presets”: [“es2015″,”react”]}’

    I had to replace the single quation marks with the double ones and escaped the double one in the text:

    webpack ./client/index.js ./bundle.js –module-bind “js=babel?{\”presets\”: [\”es2015\”,\”react\”]}”

    This worked for me.

    Reply

    • rambutan

      Yes, I had the same problem, but i got around it by using double quotes for js=babel……to end
      and used single quotes for thee json block within

      webpack ./client/index.js ./bundle.js
      –module-bind “js=babel?{‘presets’: [‘es2015’, ‘react’]}”

      Reply

    • fazbat

      I think thats it. Thanks sooo much! struggled for over an hour! I just reversed the singles and double quotes BTW. “js=babel?{‘presets’: [‘es2015′,’react’]}” and it worked. Makes sense now. The terminal didn’t like the single quotes.

      Reply

  9. Rich

    Not a bad tut so far. My only challenge has been you kind of skipped the part about what to do about the index.html file. It’s gone in the sample code, and you keep mentioning all this dynamic stuff happening. If it’s a static file, it’s always going to give me the same message. Not sure where react was supposed to come into play.

    Reply

    • Phil Parsons

      index.html gets swapped for the server views which are built with handlebars and render the application on the server side initially then on the client once the scripts are loaded.

      Reply

  10. sean

    Great tutorial. Having issues when using ‘babel-node server’ when adding react to the express index.js. I keep getting and error:

    ReferenceError: react is not defined
    at Object. (app.js:98:19)

    It seems like import react but this is in the generated file so am unsure what to do.

    Any suggestions?

    Reply

    • Phil Parsons

      Hey, sorry I didn’t respond sooner! Sounds like something to do with the Webpack build, do you have React installed for the server module?

      Reply

  11. Rich Brown

    NB: npm install for the current project gives a warning (“WARN deprecated graceful-fs@3.0.8”). The dependency is express-handlebars: that 3.0.0 version (from January 2016) now depends on a current version of graceful-fs. I updated package.json to say:

    “express-handlebars”: “^3.0.0”,

    and all is well

    Reply

  12. Daniel

    Hi Phil, excellent tutorial series compared with many others.

    I like that you show code and then explain what’s happening. Saves significant time and also ramps up speed of understanding. I look forward to more 🙂

    Reply

  13. Gedas

    Great tutorial.

    In the webpack.config.js, I needed to add this:

    const path = require(‘path’);

    Only then the webpack command stopped failing.

    Reply

    • Gedas

      Scratch that 🙂 I actually scrolled down and missed the require statement:) My bad.

      Reply

Leave a Comment

Your email address will never be published or shared and required fields are marked with an asterisk (*).