DEV Community

Cover image for Webpack to run React.
Tallan Groberg for ITNEXT

Posted on • Edited on

Webpack to run React.

Shall we start with why and then move to how. 

for most aspiring devs, webpack seems like this mysterious black box only assessable to the rock star coders among us. You may have seen the word is some sort of console logged javascript method with the name in all caps

Alt Text

if you make react apps (or any other JS libraries using webpack).
this is my attempt to demystify webpack and let the world know, with a little effort you can add webpack to your tool kit. 

webpack is powerful because it breaks your code into what browsers can read from what browsers can't. A few examples are... 

compiling SASS into CSS.
 
compiling React into ES5.

This is the topic I'm about to show you.

NOTE: if this is scaring you away I want you to know the syntactically webpack is just a javascript object. 

PREREQUISITES: 
unix command line experience and a unix operating system to follow along. I will be using a mac.

(if you don't have this you can figure out how to do this without it)

Understanding of the basics of React, javascript, javascript objects and JSON objects.

node needs to be installed. you can do so with homebrew (if you don't have homebrew follow the link and find the curl command on the page)
if you have brew installed you can run this command.

brew install node

  1. The latest version of npm.
  2. a text editor of your choice, I recommend VScode

CREDITS: 
This is tutorial is largely inspired by Nate Jensens's article on the subject. however I'm trying to improve upon the delivery and accessibility for less experienced devs.
 
Let's start by opening our command line and making a new folder where we want our webpack project.

mkdir webpack-stuff && cd webpack-stuff
Enter fullscreen mode Exit fullscreen mode

NOTE: the && symbol lets us use multiple commands one after the other.(but only if the previous command worked.)

if you are using vscode, you can press control and the ~ right below the escape button at the same time to open a command-line, so you can see the project files and the command-line at the same time. 

Inside the directory run the following command to make a package JSON file.

npm init -y
Enter fullscreen mode Exit fullscreen mode

Press ENTER and you should see a package.json.

install webpack by this into the command line.

npm i webpack webpack-cli --save-dev
Enter fullscreen mode Exit fullscreen mode

Almost every command in this tutorial is going to be used with the - save-dev flag at the end. 

your package.json should now have a devDependencies section.

Alt Text
If you made a typo or you don't have a devDependencies section.
you can run this command then copy and paste the command above.

 

npm uninstall webpack webpack-cli 
Enter fullscreen mode Exit fullscreen mode

you can run npm uninstall for any of the commands that we enter. 

Next, make the webpack.config.js

touch webpack.config.js
Enter fullscreen mode Exit fullscreen mode

This is where the heavy lifting of our application will be. 

It helps me to think of a webpack.config.js file like a garden and our code is like the nutrients for the soil. 

Inside the webpack file we want to tell webpack where to start(entry:) and where to place the complied-code(output:)

module.exports = {
   entry: '',
   output: {},
}
Enter fullscreen mode Exit fullscreen mode

Since we have to give a file for an entry point lets go back to the command line and make the directory to start looking like it does in create-react-app with an scr/ folder and an index.js file.

mkdir src && touch src/index.js
Enter fullscreen mode Exit fullscreen mode

now that we have the entry point lets add that to the webpack.config.js

 

module.exports = {
   entry: 'src/index.js',
   output: {},
}
Enter fullscreen mode Exit fullscreen mode

Let's tell webpack where to save this code once it's compiled.

To save the code we need to use a default node method called path.
At the top of the file, lets add that.

const path = require('path')
Enter fullscreen mode Exit fullscreen mode

Now inside of the curly brackets for the key: value, pair for output. Add the following code.

 

path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
Enter fullscreen mode Exit fullscreen mode

This block of code will make a new folder called dist and inside the folder a file called main.js with the compiled code.

NOTE: These are now webpack defaults but it's really important to understand that this is what is happening and it will prove foundational to helping you develop custom modifications later.

Now lets make a module section of our exports object underneath the }, of our output object.

 

module: {}
Enter fullscreen mode Exit fullscreen mode

inside of a module: {… [rules go here] …} you can define an array of rules for webpack to follow.
The nutrients of the soil if you will. 

Lets add that.

 

rules: []
Enter fullscreen mode Exit fullscreen mode

The first one is a dependency called babel-loader. It will define how to interpret some elements of javascript
lets go to the command line and do that right now.

npm i babel-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

inside of our rules array we need to tell each dependency how to behave in babel-loader's case we want to.

  1. test: for a specific file type with a regular expression. 
  2. exclude: doing this for node_modules folder. 
  3. use: {loader: } in this case babel-loader

Inside of our rules array we want an object that looks like this.

 

{
   test: /\.js$/,
   exclude: /node_modules/,
   use: { loader: 'babel-loader'}
},
Enter fullscreen mode Exit fullscreen mode

in the test: section is a regrex to test for .js and the $ tells it to test for the ending of a file name. 

our code is looking like this. 

Alt Text

This is a lot of code and dependencies if you follow along this will work. 

we are going to add the next few rules for .html .css and image files. 
inside of the rules array go ahead and add this object

{
   test: /\.html$/,
   use: { loader: "html-loader"}
},
Enter fullscreen mode Exit fullscreen mode

then run this in the command line.

 

npm i html-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

now for css

 

{
   test: /\.css$/,
   use: ['css-loader', 'style-loader']
},
Enter fullscreen mode Exit fullscreen mode

the command to install

 

npm i css-loader style-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

to do this for images we need to add more testing because images come with more file endings then other files we want to test for, but we want them all to use the same loaders. we don't want to compile images, instead we want to save them as is.

 

{
   test: /\.(jpg|jpeg|png|gif)$/,
      use: [
         {
            loader: 'file-loader',
            options: {
               outputPath: './resources/images',
               name: '[name].[ext]'
               }
          }
    ]
}
Enter fullscreen mode Exit fullscreen mode

the | symbol indicates an or statement the options key gives us access to just save the images in the compiled folder 'dist' and declare a new path. The [name].[ext] lets us keep the file name and extension you may have seen similar syntax with form handling in JS. 

lets install the file-loader

 

npm i file-loader --save-dev
Enter fullscreen mode Exit fullscreen mode

our file thus far should look like this…

const path = require('path')
module.exports = {
 entry: 'src/index.js',
  output: {
   path: path.resolve(__dirname, 'dist'),
   filename: 'main.js',
  },
  module: {
   rules: [
  {
    test: /\.js$/,
    exclude: /node_modules/,
    use: { loader: 'babel-loader'}
  },
  {
    test: /\.html$/,
    use: { loader: "html-loader"}
  },
  {
    test: /\.css$/,
    use: ['css-loader', 'style-loader']
  },
  {
    test: /\.(jpg|jpeg|png|gif)$/,
    use: [
        {
          loader: 'file-loader',
          options: {
            outputPath: './resources/images',
            name: '[name].[ext]'
            }
          }
        ]
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

now we get into babel and how it is used in this process.
lets make a .babelrc by running this command.

 

touch .babelrc
Enter fullscreen mode Exit fullscreen mode

we are going to make a babel configuration to be best friends with webpack and with some syntactic changes. 

All the rest of the npm i commands for babel will start with @ 
we set up our .babelrc file with a single json object.

 

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}
Enter fullscreen mode Exit fullscreen mode

lets run the npm installs for the packages that these represent.

 

npm i @babel/preset-env @babel/preset-react @babel/plugin-proposal-class-properties --save-dev
Enter fullscreen mode Exit fullscreen mode

@babel/preset-env: helps manage javascript syntax transformations 

@babel/preset-react: this is a bundle of other packages to compile react specific syntax into ES5 giving us the ability to use JSX and other react functionality. 

@babel/plugin-proposal-class-properties: this gives us the ability to use arrow functions in classes with auto binding and ES6 syntax. 

we need to install one more that called @babel/core. this is the landing platform for all babel configurations.

npm i @babel/core --save-dev
Enter fullscreen mode Exit fullscreen mode

we have babel and webpack working together, so now let's give them something to work with. 

to do this we need a couple more installs and a little more code in our webpack.config.js 

add the html-webpack-plugin

npm install --save-dev html-webpack-plugin
Enter fullscreen mode Exit fullscreen mode

then at the top of the webpack.config.js require the dependency.

const HtmlWebpackPlugin = require('html-webpack-plugin')
Enter fullscreen mode Exit fullscreen mode

jump to the bottom of the file and above the last curly bracket write this code.

 

plugins: [
    new HtmlWebpackPlugin({
    template: './public/index.html',
    filename: './index.html'
  })
],
Enter fullscreen mode Exit fullscreen mode

the plugins looks a little different from the rest because this is telling webpack where to display all of the compiled code. The rest of this file was saying where to start compiling, what to do when it found different kinds of files and where to keep the code it compiled.

you'll notice that the template and the file name need to be created and then we should make it look like a regular .html file.

 

mkdir public && touch public/index.html
Enter fullscreen mode Exit fullscreen mode

if your text editor has emmet you can just write ! and press tab then #root tab inside the

to make the file but for the rest us you can copy this.

 
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>custom webpack</title>
</head>
  <body>
    <!-- dont forget the root id!!!!!!!! -->
    <div id="root"></div>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

now we have to create our index.js to append our whole application to the root id. 
this is going to look almost exactly like an index.js file in create-react-app but without the fluff.

lets start by installing react and reactDOM.

 

npm i react react-dom 
Enter fullscreen mode Exit fullscreen mode

notice we didnt do the save dev. thats because these will work in production as well. 

now lets import them in our index.js at the top of the file.

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
Enter fullscreen mode Exit fullscreen mode

now we are ready to make an App.js to be the platform for the rest of our components. 

we are going to use a reactDOM method called render which takes 2 arguments. 1.what we are rendering 2. where we are displaying it.

 

ReactDOM.render(<App />, document.getElementById('root'))
Enter fullscreen mode Exit fullscreen mode

lets make an App.js Component.

touch src/App.js 
Enter fullscreen mode Exit fullscreen mode

fill it with the normal things we would for the start of a react app

import React from 'react';


const App = () => {
  return (
    <div>
      my first webpack!!!!!!
    </div> 
  );
};


export default App;


Enter fullscreen mode Exit fullscreen mode

now lets go back to our package.json and add the start and build scripts
under the scripts section right under

"test" "echo \"Error: no test specified\" && exit 1",

"start": "webpack-dev-server --open --mode development",
"build": "webpack --mode production"
Enter fullscreen mode Exit fullscreen mode

one more install to get the script to work

 

npm i webpack-dev-server --save-dev
Enter fullscreen mode Exit fullscreen mode

this allows you to actually run a server. When you run npm start you should see this in the browser.

Alt Text
 
It might not look like a lot now but you can make this application do anything a react app can do and more because you can add further configuration from here. and you can deploy this as a live website if you enter this into the command line.

npm run build
Enter fullscreen mode Exit fullscreen mode

Alt Text

look at all the pretty colors!!

Conclusion: 
webpack is a very powerful thing to have in your tool kit as a developer and now you have an idea of the basics. I encourage you to try and come up with your own order of install and code and practice a couple of times until you can do this from memory. 
I think that the constant referencing of material in development will slow you down as a dev in the long run and so I'm going to tell you that I do get caught in the syntax and learn them but I also try and pick out the most relevant things to learn. 
webpack is one of them. 
please comment if you liked it.

Link to the github. https://github.com/TallanGroberg/webpack-for-react

Top comments (2)

Collapse
 
slashgear_ profile image
Antoine Caron

Great article!

Made a complete list of workshops to learn the tricky parts of webpack

Collapse
 
tallangroberg profile image
Tallan Groberg

thanks Antoine!! I skimmed through the workshop and want to give it a closer look when I can.