Webpack to run React.
Published: 2019-10-28 03:58:35


Shall we start with why and then move to how. 

for most aspiring devs, [webpack](https://webpack.js.org/) 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](https://thepracticaldev.s3.amazonaws.com/i/ab4tlss724wh4pgibp54.png)

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](https://sass-lang.com/guide) into CSS.
 
**compiling [React](https://reactjs.org/) into [ES5](https://en.wikipedia.org/wiki/ECMAScript).**

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](https://macpaw.com/how-to/use-terminal-on-mac) 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](https://javascript.info/object) and [JSON objects](https://www.w3schools.com/js/js_json_objects.asp).

[node](https://nodejs.org/en/) needs to be installed. you can do so with [homebrew](https://docs.brew.sh/Installation) (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
4. The latest version of [npm](https://docs.npmjs.com/about-npm/).
5. a text editor of your choice, I recommend [VScode](https://code.visualstudio.com/download)

CREDITS: 
This is tutorial is largely inspired by [Nate Jensens's article](https://coursework.vschool.io/webpack-for-react-2018/) 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
```

NOTE: the [&&](https://www.unix.com/unix-for-beginners-questions-and-answers/263924-meaning-unix.html) 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
```

Press ENTER and you should see a package.json.
 
install webpack by this into the command line.
```
npm i webpack webpack-cli --save-dev
```
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](https://thepracticaldev.s3.amazonaws.com/i/zwne0k9bd5eva2ypplu7.png)
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 
```

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

Next, make the webpack.config.js
```
touch webpack.config.js
```
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:)
```javascript
module.exports = {
   entry: '',
   output: {},
}
```

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
```
now that we have the entry point lets add that to the webpack.config.js 
```javascript
module.exports = {
   entry: 'src/index.js',
   output: {},
}
```
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](https://nodejs.org/api/path.html).
At the top of the file, lets add that.
```javascript
const path = require('path')
```
Now inside of the curly brackets for the key: value, pair for output. Add the following code. 
```javascript
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
```
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. 
```javascript
module: {}
```
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. 
```javascript
rules: []
```
The first one is a dependency called [babel-loader](https://webpack.js.org/loaders/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
```
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: <type-of-loader>} in this case babel-loader

Inside of our rules array we want an object that looks like this. 
```javascript
{
   test: /\.js$/,
   exclude: /node_modules/,
   use: { loader: 'babel-loader'}
},
```
in the test: section is a [regrex](https://www.rexegg.com/regex-quickstart.html) 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](https://thepracticaldev.s3.amazonaws.com/i/1qb8sjpmnxdzrljrmah6.png)

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
```javascript
{
   test: /\.html$/,
   use: { loader: "html-loader"}
},
```
then run this in the command line. 
```
npm i html-loader --save-dev
```
now for css 
```javascript
{
   test: /\.css$/,
   use: ['css-loader', 'style-loader']
},
```
the command to install 
```
npm i css-loader style-loader --save-dev
```
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. 
```javascript
{
   test: /\.(jpg|jpeg|png|gif)$/,
      use: [
         {
            loader: 'file-loader',
            options: {
               outputPath: './resources/images',
               name: '[name].[ext]'
               }
          }
    ]
}
```

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
```
our file thus far should look like this…
```javascript
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]'
            }
          }
        ]
      }
    ]
  }
}
```


now we get into [babel](https://babeljs.io/docs/en/) and how it is used in this process.
lets make a .babelrc by running this command. 
```
touch .babelrc
``` 
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. 
```json
{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["@babel/plugin-proposal-class-properties"]
}
```
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
```
[@babel/preset-env:](https://babeljs.io/docs/en/babel-preset-env) helps manage javascript syntax transformations 

[@babel/preset-react:](https://babeljs.io/docs/en/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:](https://babeljs.io/docs/en/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](https://babeljs.io/docs/en/6.26.3/babel-core). this is the landing platform for all babel configurations.
```
npm i @babel/core --save-dev
```
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](https://webpack.js.org/plugins/html-webpack-plugin/#root)
```
npm install --save-dev html-webpack-plugin
```
then at the top of the webpack.config.js require the dependency.
```javascript
const HtmlWebpackPlugin = require('html-webpack-plugin')
```
jump to the bottom of the file and above the last curly bracket write this code. 
```javascript
plugins: [
    new HtmlWebpackPlugin({
    template: './public/index.html',
    filename: './index.html'
  })
],
```

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
```
if your text editor has [emmet](https://emmet.io) you can just write ! and press tab then #root tab inside the <body> to make the file but for the rest us you can copy this. 
```html
<!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>
```


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 
```
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.
```javascript
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
```

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. 
```javascript
ReactDOM.render(<App />, document.getElementById('root'))
```
lets make an App.js Component.
```
touch src/App.js 
```
fill it with the normal things we would for the start of a react app
```javascript
import React from 'react';


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


export default App;


```

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",
```json
"start": "webpack-dev-server --open --mode development",
"build": "webpack --mode production"
```
one more install to get the script to work 
```
npm i webpack-dev-server --save-dev
```

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

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/f0dy28y598ecx9pou8gi.png)
 
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
```
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/q7fgfecspu4aczrfnkx7.png)

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