Setting up React for ES6 with Webpack and Babel

ReactJS has been taking the world of front end development by storm. Described by its own homepage as the V in MVC, React allows you to build reusable UI components and makes maintaining changes in your data’s state effortless by abstracting the DOM. Combined with a bundler utility like Webpack, React greatly simplifies building and maintaining Single Page Applications.

Take the Twilio Javascript library for a spin here

Facebook has done a great job of keeping React up to date, and even made it compatible with new features from ECMAScript 6 (ES6), the significant update to the JavaScript language that is finally available for use. Unfortunately, browser support for ES6 is not as widespread as many would hope which is where handy utilities like Babel come into play. Babel lets us write code that uses new ES6 features, and then transpiles that code into standard ES5 code that can run in older JavaScript environments.

In this post, we’ll go through the steps of setting up two basic React components that use ES6 features, use Babel to transpile them to ES5 and bundle them using Webpack. This is going to be fun because React, ES6, Babel and Webpack play together particularly well.

Visiting the toolshed

Before we get started writing code we have to install the right tools. First make sure you have NodeJS and npm installed as we’ll use those to install the packages we need.

With Node and npm installed fire up your terminal, head over to the directory where you want your project to live and run:

Go through all of the prompts filling out whatever information you feel is appropriate and a package.json file should be generated. This will allow us to keep track of what node modules we need for future reference.

Now let’s install React and the React DOM:

We will also need to install Webpack and the Webpack development server for serving our bundled JavaScript application. You may need to use “sudo” to install the dev server package globally.

Now that our bundling tool is taken care of, we need a transpiler for interpreting our ES6 code. This is where Babel comes in. Let’s install the babel-loader and babel-core packages that we’ll use to work with Webpack, as well as the ES2015 and React presets for loading the code that we’ll write.

Creating your first React components

In React, components are the individual building blocks of how your data is viewed. You write components to handle how your data should look and to automatically render state changes. When you create a component, you define all of this by overriding React.Component’s render function.

Let’s dig into this by writing our first component whose job is to render the word “Hello” into the browser.

Open up a new file called “hello.jsx” in your text editor and enter this code:

There are a couple of things to note about the syntax. First off, we have ES6 import statements and class definitions, which makes our code more concise by not having to call React.createClass. But there is also some funky looking inline HTML type stuff in the component class definition’s render function. This XML-like syntax being returned from the function is called JSX. It was designed to make building React components easier because it is concise and familiar for defining tree structures with attributes.

All of this new syntax might look a bit strange, but don’t worry because in just a bit well use Babel to transpile both the ES6 syntax and the JSX syntax into ES5 JavaScript that can be run in a browser.

Here is what our Hello React component looks like without using ES6 and JSX:

When we use JSX, we are able to define our virtual DOM element more concisely without having to call React.createElement and passing which attributes the element should have. Our simple Hello component may have the same number of lines of code but JSX makes things much easier as you continue building components and combine them together.

Now that we have our component class, we need to add some code to “mount” this component to a DOM element. This will take our React component and render it to display within an element of an HTML page. To do this we import the React DOM and call its render function, passing in a component object as well as an actual DOM element to attach to.

Open up “hello.jsx” once again and add these lines:

Now let’s create our second component whose job is to render the word “world”. Create a new file called “world.jsx” and add the following code. Notice that it’s eerily similar to the code we wrote for our first component:

So we have two React components, but nowhere to use them. Let’s fix this by writing a simple HTML page that contains a <div> for each component we want to mount. Create an “index.html” file and write this bare bones web page:

We’ve now created all of the code we need to display “Hello World” in a browser using React components. The final step in getting this code ready to run is to pass it through Webpack.

Bundling everything with Webpack

Webpack is a module bundler that takes assets such as CSS, images or JavaScript files with lots of dependencies and turns them into something that you can provide to a client web page. It uses loaders that you specify in your configuration file to know how to transpile these assets. In our case, we want to transpile the JSX to JavaScript and ES6 code to browser-compliant ES5 code. We can do this by providing a JavaScript file as an entry point for Webpacks loader pipeline. Webpack will analyze this file and all of the subsequent dependencies used in your code to generate a bundle for you to include in your HTML. To tell Webpack about our React components, all we need to do is import those JavaScript files.

Create a “main.js” file in your text editor and add code to import both of the React components we made:

Next we need to tell Webpack that this will be our entry point and which loaders to use when creating the bundle. We are only using the Babel loader, but we could use other loaders for things like CoffeeScript and SASS if we had other dependencies.

Fire up your text editor one more time and create a new file called “webpack.config.js” and add the following configuration:

Finally, we need to make one more small modification to our HTML to include the “bundle.js” file that will be generated when we run the Webpack dev server:

Let’s fire up the Webpack dev server to see our components on the page live in action:

WebpackDevServer.gif

Watch as your terminal comes alive while Webpack builds your code to run in-browser. Now that the dev server is running, you can navigate to “http://localhost:8080/webpack-dev-server/” in your browser to see your Hello World React app displayed beautifully on the page.

Screen Shot 2015-08-14 at 1.09.47 AM.png

What comes next?

We’ve just built two React components using Babel for JSX and ES6 syntax and bundled them together using Webpack. This may not seem like much, but it is a solid start on the path to building bigger single page applications. You’ve now overcome the hurdle of getting a bunch of new technologies to work together and can finally start making awesome stuff with React.

If you want to dive into building an actual React application, you can check out this other hands on blog post I wrote recently about building a dashboard with React for monitoring phone calls using the Twilio REST API.

I’m looking forward to seeing what you all build. Feel free to reach out and share your experiences or ask any questions.

  • Apoorv Verma

    Nice!

  • Tony

    actually is babal-core needed in the dependency? I think it is already included in babel-loader

    • Sam Agnew

      Hey Tony,

      You are right when you say that babel-core comes with babel-loader. It is currently a peer dependency. However, when you install babel-loader without babel-core, you will get a warning from npm that this will be deprecated in npm 3 and higher. In the future babel-core will need to be explicitly installed on its own.

      Here’s the output from “npm install –save-dev babel-loader”:

      npm WARN peerDependencies The peer dependency babel-core@* included from babel-loader will no
      npm WARN peerDependencies longer be automatically installed to fulfill the peerDependency
      npm WARN peerDependencies in npm 3+. Your application will need to depend on it explicitly.

  • SocialChooozy

    Thanks

  • tonyspiro

    Great tutorial. Thank you!

  • Haris

    Seems simple enough yet I receive the following error
    ERROR in ./app/app.js
    Module parse failed:
    /Users/user/Sites/reactproject/node_modules/babel-loader/index.js!/Users/user/Sites/reactproject/reactproject/app/app.js Line 1: Unexpected token
    You may need an appropriate loader to handle this file type.
    | import Hello from ‘./hello.jsx’;
    | import World from ‘./world.jsx’;

    • Robert L

      Double check your webpack config file and be sure you are using your loader on jsx files and not plain js.

      • Haris

        Thanks for getting back to me. I’m loading the following line under my test: /.jsx?$/
        I’ve also tried

        test: /.jsx?$/

        Unfortunately, I’m still getting the same error. I thought it had to do something with me npm installing both babel-loader & babel-core on the same line, so I build the project again and I still get the same error.

        Thank you.

    • Dongxiang Fang

      same to you, I am sure my config file is the same as this blog. Have you solve this issue?

      • Haris

        Hey, thanks for your concern. Unfortunately, I’m still getting the same error. Can it be something with the current versions that I’m running ?

    • Sam Agnew

      Hey it looks like you’re right. I just copy/pasted the code and commands from this post and got the same error. I suspect it’s because one of these libraries was recently updated. I’ll go through and look into it, and then I’ll make sure to add specific version numbers to the npm install statements so this doesn’t happen in the future.

      Thanks a ton for pointing this out!

      • Haris

        Hey, thank you!

    • Sam Agnew

      Yeah so it turns out Babel just upgraded from version 5 to 6: https://medium.com/@malyw/how-to-update-babel-5-x-6-x-d828c230ec53#.yqxukuzdk

      Now you need to install the “es2015” and “react” presets in order for the loader to recognize the ES6 and JSX code. Try these commands:

      npm install babel-preset-es2015
      npm install babel-preset-react

      And replace the loaders section of your webpack config with this:

      loaders: [
      {
      test: /.jsx?$/,
      loader: ‘babel-loader’,
      exclude: /node_modules/,
      query: {
      presets: [‘es2015’, ‘react’]
      }
      }
      ]

      Going to add this to the post immediately.

      • Haris

        Yep, looks like it’s working now. Thank you!

      • Haris

        Although, Webpack is still not building a bundle.js file. So it works until I restructure my app to look something more like the following:
        Root
        – app
        – main.js
        – hello.jsx
        – world.jsx
        – build
        – index.html
        webpack.config.js
        package.json

        Webpack still does the build, however, it just renders the directory structure instead of Hello World.

      • Haris

        actually , I wasn’t aware that I had to run webpack as well before webpack-dev-server –progress –colors
        So now it’s building the bundle.js but I’m still only getting the folder structure.

        Anyway, thank you so much for this walk through as it works great now, I just wanted to see how it would build with a more manageable folder structure.

      • Haris

        Just wanted to say thanks again, I deleted my previous 2 comments because I had a syntax error and those comments might have confused other readers.

      • Dongxiang Fang

        It’s OK now, Cool. Thanks

  • Logan

    Nice tutorial. This was perfect for me getting used to Webpack and React.

  • René Verheij

    Hey, as this was the best tutorial / info I could find today, I’m using this excact webpack / babel setup but with React 0.14. But I’m getting an error from React: Uncaught TypeError: Super expression must either be null or a function, not object

    Ive asked a React oriented question about it on SO:
    http://stackoverflow.com/questions/33699613/react-0-14-2-error-super-expression-must-either-be-null-or-a-function

    But now I’m wondering if it’s not something related to webpack / babel / the babel presets of this setup.

    Any idea?

  • Johnny

    How can i integrage react-hot-loader with babel-loader 6.x.x

  • pgol

    Shouldn’t ‘World’ and ‘Hello’ classes be exported in module to be able to import them in ‘main.js’?

  • MadChuckle

    ERROR in Cannot find module ‘babel-runtime/helpers/interop-require’

    Why I am getting this error?

  • Andrew Byrne

    Good base for development here, thanks for the article.
    BTW Installed everything here on edge, and everything runs as expected.

  • Alexei Kozhushkov

    Excellent tutorial :) One update:

    If you see

    in browser console consider update component files with

    import:

    [/crayon]

    • X Rene

      you can do it like this:

      import {render} from ‘react-dom’;

      xxx

      render(, document.getElementById(‘world’));

  • YS

    Encountered issue while following the steps. Anyone can help?

    https://github.com/webpack/webpack/issues/1925

  • horken

    thanks for the tutorial, but i got the same error as Haris, error like following

    ./main.js
    Module parse failed: C:UsersusersDocumentsIceNovareactnode_modulesmain.js Line 1: Unexpected token
    You may need an appropriate loader to handle this file type.
    | import Hello from ‘./hello.jsx’;
    | import World from ‘./world.jsx’;

    but I only copy and paste the code from this tutorial, anyone idea??

  • Matt M

    When I tried to run ‘webpack-dev-server –progress –colors’ I received the error:
    ‘webpack-dev-server /usr/bin/env: node: no such file or directory’

    I found the answer here: http://stackoverflow.com/questions/30281057/node-forever-usr-bin-env-node-no-such-file-or-directory

    I ran: ‘sudo ln -s “$(which nodejs)” /usr/bin/node’ after which webpack worked fine.

    Also, I have looked through a number of tutorials for this set up; This is the most precise, informative and well presented I have found. Thanks for helping me :)

  • shemeeermali

    Good Job :)

  • musbell

    The components are not displaying, this is the error messages i got from the console “Error: _registerComponent(…): Target container is not a DOM element.”

  • musbell

    never mind, i made a mistake on the target container id ‘hello’. Great tutorial

  • Steven

    Thanks! A very handy tutorial. The easiest I’ve seen to get the basics of webpack working.

  • fdklnj

    l;asckjvjhcv

  • For some reason this page can’t be loaded in Safari

    • having the same issue with a similar setup, have you managed to fix it :) ?

  • Jason Polydor

    Awesome tutorial! Thanks

  • Alexey Luchaninov

    Tried today – it doesn’t build.
    Simply copy-pased all examples.
    “webpack: bundle is now VALID.” but it doesn’t create bundle.js
    Also didn’t get it, why did you add this

    var path = require(‘path’);

    var webpack = require(‘webpack’);

    They are not used in the code below…

    • Sam Agnew

      Hey there. Thanks for commenting! I wasn’t able to recreate the error you were having, but I suspect it might have something to do with your version of Webpack. It isn’t creating the bundle.js?

      It also might be because the Webpack dev server is serving bundle.js and the file does not exist when you kill the server. If you try just running webpack in your terminal from the same directory then things should work if that’s the problem. Let me know if that helps.

      Thanks
      Sam

      • Alexey Luchaninov

        Hi Sam!

        Thanks for explanation. If I run just “webpack” it works :) File is created. If I run “webpack-dev-server” it’s not. I was not careful with “Content Base” description in the documentation and missed that moment.

  • naresh

    i am follow the doc did all the steps but here i got one error .
    actually i new in React js please help me ! My error is GET file:///home/nareshbabu/myworkspace/react-hello-world/bundle.js net::ERR_FILE_NOT_FOUND

    • Sam Agnew

      Hey naresh

      It looks like you might trying to open the file directly instead of visiting the webpack dev server running locally. Also keep in mind that the webpack dev server must be running in order for bundle.js to exist. You need to visit http://localhost:8080/webpack-dev-server/ on your machine to see everything correctly.

      When you run the following command in your terminal:

      webpack-dev-server –progress –colors

      Do you see something along the lines of “webpack: bundle is now VALID.”?

  • Charlie

    I get this error when I try to run webpack-dev-server –progress –colors for the first time. Any help?

  • Inessa Atnovember

    Thank you!! Very Much!!
    Dont even image how musc my nerves you saved with this article!

  • Keyur Patel

    was never able to use query entry inside webpack.configure.js.
    Got success by adding

    {

    presets: [‘es2015’, ‘react’]

    }

    in .babelrc file

  • Worked well for me. It’s a little weird, though, that we do it like this:

    import World from ‘./world.jsx’;

    So many projects seem to exclude the “.jsx” part. Why do we have it here?

    And I ran into problems when I tried separating out my project in Actions, Components, etc folders… it just wouldn’t compile. It would ignore changes in any files in folders, and I couldn’t get a component to properly call an Action like import World from ‘./Action/worldAction.jsx’; or with any combination of ‘.././ ./../../’ that I tried for a path. I don’t see why, the webpack config should do all folders, but for some reason… maybe you know why?

    Anyway I should probably just look at your other posts:) thanks very much!!

  • Niranjan Sharma

    i copied the code and everything. it’s not working for me. m not getting any error or warning either. not getting Hello World on page.

  • Error here: Module build failed: Error: Couldn’t find preset “react” relative to directory

  • Pier

    I’m getting an “Uncaught SyntaxError: Unexpected token import” from “import Hello from ‘./hello.jsx'” Any idea?

  • Uk Jo

    I followed your introduction. But there is no react components in my html page.
    https://github.com/verystrongjoe/sunday-realty-ui please see my source and let me find my problem if you could. thanks in advacne!!!

  • Uk Jo

    I followed your introduction. But there is no react components in my html page. https://github.com/verystrongjoe/sunday-realty-ui Please help me..

  • Me

    Great tutorial! I only had one problem. When I installed webpack-dev-server with -g, it wouldn’t find the webpack dependency in my project. If I uninstalled it globally and installed it locally, it worked fine. Is there something extra I need to do to make dependencies in that direction work?

  • JimTheMan

    How do you put components inside of other components?

  • Lolly

    Localhost:8080 wouldn’t load on my MacOS X El Capitan, so I changed the port number with webpack-dev-server --progress --colors --port 15001 (with 15001 being just a fairly random high number to avoid any ‘well known’ ports).

    • Kyle

      Thanks! I had the same issue. What do you think causes the conflict?

      • eddiezane

        There might be something already running on port 8080. sudo lsof -iTCP -sTCP:LISTEN -P -n will spit out what ports are already used on your Mac.

        • Kyle

          Thanks! I checked and nothing appeared on that port? The only difference visible with lsof was if the node listener was on port 8080 or port 3000 respectively

  • Jaran Flaath

    Great article for getting up and running quickly with webpack and React.js! Thanks! Only thing I had to do was to install the webpack module with ‘npm install webpack -g’. Installing with –save-dev did not work for me.

  • Jag

    This is an excellent tutorial. I happened to come across a video which follows the above article in a very similar fashion. Hopefully, the following link helps for future readers: https://www.youtube.com/watch?v=wy3Pou3Vo04

  • Murali M Murliz

    pretty nice and straight forward example, but i ended up with the following error.

    events.js:154
    throw er; // Unhandled ‘error’ event
    ^
    Error: listen EADDRINUSE 127.0.0.1:8080
    at Object.exports._errnoException (util.js:890:11)
    at exports._exceptionWithHostPort (util.js:913:20)
    at Server._listen2 (net.js:1234:14)
    at listen (net.js:1270:10)
    at net.js:1379:9

    How ever later changing the port in webpack.config.js,and was able to resolve this issue.

    devServer: {
    historyApiFallback: true,
    contentBase: ‘./’,
    inline: true,
    port : 3000
    }

  • nuts

    thank you!

    i’ve just spent 2+ hours on finding the right tutorial. this one finally was exactly what i was looking for

  • Jimmy

    Hi Sam. I followed the tutorial and everything works fine but I would like to know where the bundle.js is stored. I cannot see it anywhere, and I don’t know why the is actually working… Thanks!

  • andres rosvel

    Thanks man!

  • Kevin Crews

    NICe tutorial!! Only problem Im getting is that on the browsers it just says app ready and not hello world.

  • Jaxon

    /.jsx?$/ is incorrect. That would match “testjsx” in addition to “test.jsx”. Escaping the dot fixes this: /.jsx?$/

  • michael walston

    So our site we run under sections so if webpack bundles all files to one how could we use it. Ex. Home from server loads up one set of jsx and about would be a new set of jsx. These are not the menu names but the idea. More like multi spa sections.

  • Wilko Van Der Veen

    Nice tutorial, but why the hell is it so complex to do simple things like splitting up ReactJS controls into different jsx files…

  • John Linton

    What I don’t understand is doesn’t including the ReactDOM.render statements in each .jsx module end up tightly coupling those modules based on the div id? So what if you need to have lots of different uses of a module?

    Also what’s a little tricky to me is if you have multiple pages and you presumably don’t want just one mega .js file for say 150 .jsx React components, or do you?