DEV Community

Cover image for Setup a React app with Webpack and Babel
Anubhav Sarkar
Anubhav Sarkar

Posted on • Edited on

Setup a React app with Webpack and Babel

This article is part of a two part series on how to configure a React app from scratch with Webpack and Babel and eventually add TypeScript to it. To read the second article in this series, click on the below link.


So you want to start with a new React app or would like to add React to an already existing project, but don't want to use the create-react-app. Well you have come to the right place. I am here to guide you today on how to setup a react app from scratch with Webpack and Babel.

To create a new react app using Webpack and Babel, the first thing which we would need to install is Node JS. You can install the latest version for your machine by going to this link.

Once you have Node JS installed, we can start with the below steps.

  1. Create a new folder. You could use the following commands to create a new folder. Once the folder is created navigate to the folder using the cd command.

    mkdir <folder_name>
    
    cd <folder_name>
    
  2. While you are inside the folder, create a new package.json file, using the command given below.

    npm init -y
    

    This above command generates a package.json file, no questions asked. You could use the below command to generate the file by manually providing all the information.

    npm init
    

    It asks for these few details at the time of creation.

    a. package name (name for your app)
    b. version (1.0.0 - initially)
    c. description (a small description for your app)
    d. entry point (entry point for the module)
    e. test (any test command)
    f. author (author of the app)
    g. git (git repository url and type)
    h. license (MIT/ ISC etc.)
    
  3. Once the package.json file is created, go ahead and create a 'src' folder. This is where our code will live.

    Now use the touch command to generate these two files:

    touch index.html - (the page which is rendered and visible to the user)
    
    touch index.js - (the entry point for our application)
    
  4. Setup an index.html file with the below code and save it.

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8" />
            <meta name="viewport"
                content="width=device-width, initial-scale=1, shrink-to-fit=no"
            />
            <meta name="theme-color" content="#000000" />
            <title>React with Webpack and Babel</title>
        </head>
        <body>
            <noscript>
                You need to enable JavaScript to run this app.
            </noscript>
            <div id="root">
                <!-- This div is where our app will run -->
            </div>
        </body>
    </html>
    

    Note: The file should look like the screenshot below.

    Leave the index.js as it is for now. We will configure it after installing all the required packages.

    index.html

  5. Now let's add Webpack to our project.

    Install these packages through npm or yarn, whichever you prefer.

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

    webpack allows us to configure our app, webpack-cli helps us to use webpack on command line, webpack-dev-server is used to live reload the webpage so that we can view our changes without refreshing the page manually.

    Once those packages have been installed, the packages should be visible in the devDependencies section like below.

    package.json

    P.S: You may want to remove the caret(ˆ) from the version of the packages, as we don't know whether the new updates might bring breaking changes or not. It's always better to manually update the versions.

  6. It's time to add a new file again. Use the touch command as you did above to add the webpack.config.js. It should be installed at the root directory.

    touch webpack.config.js
    
  7. Let's go ahead and install the path package as a devDependency since we need to work with paths in our app. We wouldn't want to inject the index.js file inside the HTML file. Go ahead and install the html-webpack-plugin to help us do that automatically.

    npm install path html-webpack-plugin --save-dev
    

    This is how your package.json should look at the moment.

    updated package json

  8. Replace the contents of index.js with the below content.

     (function helloWorld() {
          console.log('Hello World');
     }());
    
    

    Once this is done, let's run webpack and see what happens. Use the command provided below.

     npm run webpack
    

    Webpack will automatically take the src/index.js file, compile it and output it to dist/main.js
    and minify the code.

    npm run  webpack

    npm run webpack output

    main js location

    main.js added to dist folder

    We can now go ahead and run the npm start command to run the app.

     npm start
    

    npm start

    npm start output

    Naviage to localhost:8080 and you should be able to see a screen just like below.

    localhost initial

    localhost started on the default browser

    To stop the server press, Ctrl + C on Windows and Command + C on Mac.

  9. Copy the code below and paste it in the webpack.config.js file.

    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
        entry: path.join(__dirname, "src", "index.js"),
        output: { path: path.join(__dirname, "build"), filename: "index.bundle.js" },
        mode: process.env.NODE_ENV || "development",
        resolve: { modules: [path.resolve(__dirname, "src"), "node_modules"] },
        devServer: { contentBase: path.join(__dirname, "src") },
        plugins: [
            new HtmlWebpackPlugin({
                template: path.join(__dirname, "src", "index.html"),
            }),
        ],
    };
    

    webpack config js

    webpack.config.js

    Let's go over the various components in the file.

    a. entry and output: tells our server what has to be compiled and from where. Also tells the server where the compiled version should be outputted.

    b. mode: this is the mode of our output, which is set to ‘development’ for now. Should be changed to 'production' when the app is build for production.

    c. resolve: used so that we can import anything from the src folder in relative paths rather than the absolute ones, same goes for node_modules as well.

    d. devServer: this tells the webpack-dev-server what files are needed to be served. Everything from our src folder needs to be served (outputted) in the browser.

    e. plugins: here we set what plugins we need in our app. As of this moment we only need the html-webpack-plugin which tells the server that the index.bundle.js should be injected (or added if you will) to our index.html file

    If we now run the earlier command, we will see some differences.

     npm run webpack
    

    npm run webpack

    npm run webpack output

    build folder

    build folder with index.build.js and index.html

    If you start the app now, using the npm start command, you would see a blank screen on the browser, without any content.

     npm start
    

    Open the developer tools on your browser and you should be able to see the entire code of the index.html file in the Elements tab. Check the Console tab to see Hello World logged over there. The webpack-dev-server took everything from the src folder and outputted it to our browser.

  10. We have configured the app to build everything from the src folder and output it to the browser. It's time to add React and spice things up a little.

    Follow the following steps to add React and Babel to the project. Run the following command to add
    react and react-dom to the project.

    Add react and react-dom as normal dependencies.

      npm install react react-dom --save
    

    At this moment in our development, if we were to add React code inside our JS file, Webpack will give us an error. It doesn’t know how to compile React inside the bundle.js file.

    Modify the index.js file as follows:

    import React from 'react';
    import ReactDOM from 'react-dom';
    
    const HelloWorld = () => {
        return (
            <h1>
                Hello World
            </h1>
        );
    }
    
    ReactDOM.render(<HelloWorld />, document.getElementById("root"));
    

    Let's start the server now and see what is rendered.

    npm start
    

    babel loader error

    webpack error for not having **appropriate loaders for react**

  11. This is where Babel comes to our aid. Babel will tell Webpack how to compile our React code.

    Let’s add a bunch of Babel packages to our app as devDependencies.

      npm install --save-dev @babel/core @babel/node @babel/preset-env @babel/preset-react babel-loader
    

    Some two pointers about these packages.

    a. @babel/core: used to compile ES6 and above to ES5.

    b. @babel/preset-env: determines which transformations or plugins to use and polyfills (i.e it provides modern functionality on older browsers that do not natively support it) based on the browser matrix you want to support.

    c. @babel/preset-react: compiles the React code into ES5 code.

    d. babel-loader: a Webpack helper that transforms your JavaScript dependencies with Babel (i.e. will transform the import statements into require ones)

  12. You will probably need to add some styles to the project, as well as have the ability to display images on the webpage.

    Go ahead and add these few packages as devDependencies. (Remove the sass-loader and node-sass if know you won't be working with SCSS files).

     npm install style-loader css-loader sass-loader node-sass image-webpack-loader --save-dev 
    

    a. style-loader: will add styles to the DOM (injects a style tag inside the HTML file).

    b. css-loader: lets us import CSS files in our project.

    c. sass-loader: lets us import SCSS files in our project.

    d. node-sass: compiles SCSS files into normal CSS files.

    e. image-webpack-loader: lets us load images in our project.

  13. Next thing to do is add a configuration file for Babel. For this we need to create a file named .babelrc in which we will configure Babel. Create this file in the root directory.

    touch .babelrc
    

    Add these lines to let babel-loader know what to use to compile the code.

    {
        "presets": [
            "@babel/env",
            "@babel/react"
        ]
    }
    

    After these steps, we will need to add something to our project so we can import all sorts of files such as images. We will also need to add a plugin that will let us work with classes and much more. Let us add class properties in our classes. Basically, it will let us work with Object Oriented Programming.

    npm install file-loader @babel/plugin-proposal-class-properties --save-dev
    

    Once that is done, we need to make some changes inside webpack.config.js so that Webpack will now use Babel. We’ll also configure Webpack to listen for style files and we are going to change the require statements to import ones.

    Change your webpack.config.js to the below code:

    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
        entry: path.join(__dirname, "src", "index.js"),
        output: { path: path.join(__dirname, "build"), filename: "index.bundle.js" },
        mode: process.env.NODE_ENV || "development",
        resolve: { modules: [path.resolve(__dirname, "src"), "node_modules"] },
        devServer: { contentBase: path.join(__dirname, "src") },
        module: {
            rules: [
                { 
                    test: /\.(js|jsx)$/, 
                    exclude: /node_modules/, 
                    use: ["babel-loader"] 
                },
                {
                    test: /\.(css|scss)$/,
                    use: ["style-loader", "css-loader"],
                },
                { 
                    test: /\.(jpg|jpeg|png|gif|mp3|svg)$/,
                    use: ["file-loader"] 
                },
            ],
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: path.join(__dirname, "src", "index.html"),
            }),
        ],
    };
    

    Your webpack.config.js should look like this now.

    new webpack config

  14. Match the package.json in your project with the below image.

    final package json

    Another thing that we will have to still add is the @babel/plugin-proposal-class-properties to the .babelrc file. Babel will know how to deal with class properties.

    {
        "presets": [
            "@babel/env",
            "@babel/react"
        ],
        "plugins": [
            "@babel/plugin-proposal-class-properties"
        ]
    }
    

    We have reached the end of this tutorial. Now let's run the previous commands and they shouldn't give us any error.

    npm run webpack
    
    npm start
    

    final render

    final output on browser

    If you have reached this step, make sure to remind yourself that you are awesome. You have learned something new today. Have a great day. Thanks for reading the entire thing.

    Here's the link to the Github Repo in case you have faced some issue during the entire process. Feel free to make some tweaks if you find something breaking because of updates to any of the packages.

Photo by Tamara Bitter on Unsplash

Top comments (29)

Collapse
 
idiglove profile image
Faith Morante

In latest webpack, it should be devServer -> static instead of devServer -> contentBase. Otherwise will get this error:

[webpack-cli] Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
Enter fullscreen mode Exit fullscreen mode

Other than, that thanks for the article, cheers

Collapse
 
chengdongxue profile image
VictorXue

Are you met the same error?

Collapse
 
deadwing7x profile image
Anubhav Sarkar

Hey, if you are comfortable with it. You can raise a PR with the changes and I will merge the changes to the repo. Thanks for letting everyone know about the recent changes.

Collapse
 
nguyenhien16091997 profile image
NGUYEN HIEN
Collapse
 
msabtainanwar profile image
Muhammad Sabtain Anwar

Same issue .

Collapse
 
greaperdev profile image
Ioannis Kotsonis

Hello,
When i run "npm run webpack", the webpack script was missing. I did all the steps but for a strange reason, i had to add the scripts manually to make it work.
By the way, it's not a problem at all.
Very nice topic, you helped me A LOT!

Collapse
 
deadwing7x profile image
Anubhav Sarkar

Hey, thank you for your feedback! 😃 I missed adding a line to add webpack in the script! I just attached the image after adding it! That might have caused the confusion! Anyways thank you! 😁

Collapse
 
venkatramy profile image
Venkatramy

Same thing happened to me, which step i had to replace to come out of this error. Please suggest. TIA

Collapse
 
deadwing7x profile image
Anubhav Sarkar

So, you need to add these two scripts in the package.json file.

You can find the link to the file in this link below:

github.com/deadwing7x/react-with-w...

Collapse
 
sergeylukin profile image
Sergey Lukin

Great and useful article. It's always best to know how stuff works behind the scenes.
The only correction is that @babel /plugin-proposal-class-properties is not required as long as @babel /preset-env is used, see babeljs.io/docs/en/babel-plugin-pr...

Collapse
 
deadwing7x profile image
Anubhav Sarkar

Thanks :) Merged your PR ;)

Collapse
 
sergeylukin profile image
Sergey Lukin

Cheers

Collapse
 
sabhas profile image
Sabir Hassan

can somebody guide me about the alternatives of node-sass image-webpack-loader. these two packages contains some vulnerabilities. However these packages are only being used in dev mode but still I want alternatives of these two with out vulnerabilities.

Collapse
 
a89529294 profile image
Albert Chang

Thank you for the article.
From the last sentence in point 9, you said 'The webpack-dev-server took everything from the src folder and outputted it to our browser.'
However I do not understand how is webpack-dev-server able to do that since the src/index.html does not link index.js.

Collapse
 
deadwing7x profile image
Anubhav Sarkar • Edited

Thanks for your feedback. 😄

So, what webpack-dev-server does is, it just shows whatever files are needed to be displayed on the browser. If you check the devServer attribute in the config file, you will see that I mentioned it to take all files from the ‘src’ folder and display them on the browser. However the part which you are looking for, is done by the html-webpack-plugin. This is another npm package, which takes the output js file, i.e, the single/ final prod build file and then calls it in the index.html file.

Collapse
 
pavindulakshan profile image
Pavindu Lakshan • Edited

If you are going to refer this tutorial to create an NPM package using React, just remember to edit main property in your package.json to point to the build directory. Other than that, great article 😃

Collapse
 
deadwing7x profile image
Anubhav Sarkar

That’s right! Thanks for sharing that! 😁🙌🏻

Collapse
 
sgoulas profile image
sgoulas

This is a quality article. I especially like how you take time to talk about why each package is needed, instead of just adding everything and throwing the final configuration. Thank you.

Collapse
 
deadwing7x profile image
Anubhav Sarkar

Thank you so much! 😁🙌🏻

Collapse
 
dplopezsioux profile image
Daniel

Nice! it works perfectly fine!

Collapse
 
deadwing7x profile image
Anubhav Sarkar

Thanks 😬

Collapse
 
xahii_majeed_38243b114755 profile image
Xahii Majeed

Hey I want apply Webpack to existing project,is that even possible ,if it’s what are the extra steps I have to follow apart from this article, I followed all the steps but once I import my existing app.js to this workflow and try npm run build it’s creates a build successfully but while running index.html it’s throws an error

Collapse
 
bor_63 profile image
Stan

Hi there, after the build script I noticed that the index.bundle.js is using eval();
Example: eval("console.log(\"aaa\");\n\n//# sourceURL=webpack://reactapp/./src/components/a.js?");

In this example I have a folder in "src" called "components", there I have 1 script that simply has "console.log('aaa')". I include this script in "index.js" like so: import './components/a';. After the build command I can see it with eval() in index.bundle.js. Is this correct ?