Webpack FUNdamentals
Tags: webpack, javascript, react, npm
Published: 2021-08-19 12:10:52

Hello super devs, 👋

How is everybody doing there? Good? 

~~Are you watching lot of sports on Olympic Games? Has your country conquered many medals?
Remember to leave your chair sometimes and go outside to make some exercises also. There is no `git revert HEAD` for life.~~

As you can see above it took me a little bit to publish this article. 😅 Never mind about **OG** anymore. 😉

Today I am going to talk a little bit about **Webpack** and we are going to try to recreate a very simple **React** application, step by step.

OK, but what the heck is **Webpack**?

![What the heck](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/99p39eed7pblulmzed7k.png)

## Webpack 🕸️ 📦

**Webpack** is an open-source JavaScript module bundler. I know, blah blah blah ...

![Blah Blah](https://media3.giphy.com/media/OBUnW8FIqb04/200.gif)

Let's break into pieces so it becomes easy (or not) to understand:

- **module**: a component or part of a program that contains one or more routines.
- **bundler:** A group of objects held together, wrapped in a package.

Until yesterday, browsers couldn't handle code divided into multiple modules. The **Webpack**'s mission is to **wrap all the source code into a single file** containing all the application code.

Do you really need to know about it? Sincerely you do not. I particularly like to understand how things work under the hood. Believe me, it can surprise you.

![Under the hood](https://i.pinimg.com/originals/c0/b3/72/c0b372b37ebf6f0c7949aefc8e39b68e.gif)

If you are still here, it is time to get hands dirty! 

### Project Bare-bones 💀 🦴

Let's start by creating a project structure similar to the image below: 

![Folder Structure on VS Code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f78lv0gbi6o6v3dmvsff.png)

- `package.json` file:
```json
{
  "name": "webpack-fun",
  "version": "0.0.1",
  "description": "webpack fundamentals",
  "license": "MIT"
}
```
### Installing the Webpack package

```bash
npm install --save-dev webpack webpack-cli
```
Here we are installing the **Webpack package** as a development dependency as well as its **cli** (Command Line Interface).

Once done that, we should define the initial **Webpack settings** (`webpack.config.js` file): 

### Webpack Configuration File

```javascript
const path = require("path");

const config = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "build"),
    filename: "main.js"
  }
};

module.exports = config;
```
Don't you worry I will explain it: 🙌 

- **path:** `NodeJS` path module used for handling file paths.

- **config:** Object that holds the **Webpack configuration**.
  - **entry:** Where **Webpack** looks to start building the bundle. The context is an absolute string to the directory that contains the entry files. 
  - **output:** contains set of options instructing **Webpack** on **how** and **where** it should output your **bundles**, **assets** the **bundle** or **load** with **Webpack**.

- **module.exports:** `NodeJS` special object that represents the current module, and exports is an object that will be exposed as a module.

### Defining the build script (`package.json`) 🏗️

Now, we need to define the build script responsible for triggering the **Webpack bundling**.

```javascript
{
  // ...
  "scripts": {
    "build": "webpack --mode=development"
  },
  // ...
}
```
I guess we are ready to test the application. Let's add some dummy code in a brand new `src/index.js` file, just to verify if it works:

```javascript
const consoleLogTricks = name => {
  console.log("Look at this:")
  console.group("Question:")
    console.log(`Did you now about it, ${name}?`)
    console.log("Probably yes!")
  console.groupEnd()
};
```
Now, if we **run the build script** created previously (`npm run build`), a new **bundled file** should be created at `/build/main.js`. It is the bundled content of our `index.js` file.

Isn't it amazing? Well, nothing special I guess. 🥱 🥱 

Let's try to mimic a **React**-like application. Under the `src` directory create a file called `App.jsx`. 

💡 People often use the `.js` extension which is fine. 
As my personal preference, when I am creating components I use the `.jsx` one. Their icons also change on **VSCode** and I know what that's about. 😉 ⚛️

- `src/App.jsx`.
```javascript
const App = () => {
  return null;
}
// Remember to export :)
export default App;
```
- Import the App component in the `index.js` file we created previously:

```javascript
import App from "./App"

const welcome = user => {
  console.log(`Welcome ${user}`)
}

App();
```
We are almost there. At the moment your application is not doing too much. It is **missing some packages** that will help us to transform it in a minimal **React** application.

Go ahead and install them: 💪

```bash
npm install --save react react-dom
```

Done that, it is time to **rewrite** your `index.js` and `App.jsx` files and use the packages we have just installed.

- `index.js`
```javascript
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("root"));
```
- `App.jsx`

```javascript
import React from "react";

const App = () => {
  return (
    <div>
      <h1>Hello from Webpack!</h1>
    </div>
  );
}
export default App;
```
Now we need to create an `index.html` file that will be the entry point of our application and load our bundled JavaScript code.

```html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Minimal React App</title>
  </head>

  <body>
    <div id="root"></div>
    <script type="text/javascript" src="./main.js"></script>
  </body>
</html>
``` 

### Loaders 🔄

We have an issue here. Do you remember that **Webpack** is a **JavaScript** bundler? Our components are using `JSX` that is a syntax extension to JavaScript.

🗒️ If it confuses you, please refer to [Introducing JSX](https://reactjs.org/docs/introducing-jsx.html).

The **loaders** come to our rescue.

1. Installing the necessary **Babel** packages:
```bash
npm install @babel/core babel-loader @babel/preset-react --save-dev
```
2. Setting up a **loader** in the `webpack.config.js` file, under the `module` property. 

This **loader** is responsible to transform **JSX** code into regular **JavaScript**.

```javascript
// ...
module: {
  rules: [
    {
      test: /\.js$/,
      loader: "babel-loader",
      query: { presets: ["@babel/preset-react"] }
    }
  ]
}
// ...
```

We should be able to bundle our application "properly" now. 🎉 🎊 🥳 

### 🥤 `<Hydration Time>` 🥤

I know, it is quite overwhelming all this "setup" process. Luckily, you won't be configuring **Webpack** from scratch that often or maybe you never will. 
Understanding at least the basics of how it works may be useful to you someday. Who knows? **¯\_(ツ)_/¯** 

Take your time to wrap up things in your head, eat a snack, drink a glass of Tang / Kool-aid and come back here when you feel ready.
 
No pressure at all! See you in **5** minutes. 😂

### 🥤 `</Hydration Time>` 🥤

There is just one important detail. If we try to make any `async` operation (e.g. REST API operations), it may happen that some browsers **won't understand** what is going on. 

![Joker](https://c.tenor.com/wFOq9TrnBxgAAAAd/you-wouldnt-get-it-joker.gif)

**Babel** has the `polyfill` package for solving this issue, so let's go for it. 💪

- Installing `polyfill`:

```bash
npm install --save @babel/polyfill
```
- Add it into the `entry` property in our `webpack.config.js` file.

```diff
const config = {
+  entry: ['@babel/polyfill', './src/index.js'],
-  entry: "./src/index.js",
  output: {
    // ...
  }
  // ...
}
```
### Transpilers 🤔 ⁉️ 

This word looks weird. Actually it sounds like a **pile** of **Transformers**. 🥁 😭

![Transformers pile](https://www.picclickimg.com/d/l400/pict/263635869483_/TRANSFORMERS-GOBOTS-Misc-ROBOTS-PARTS-PILE-LOT.jpg)

Bad jokes aside, it is the term used to mean that a source code is **transformed** from a language to another. (Maybe **Transformed** + **Compiled** ?)

Anyway, the question is why do we need a **transpiler**?
It is known that most browsers don't really support the newest **JavaScript** features such as **ES6, ES7, ES11** and so on. 
The function of a **transpiler** is (guess what? 🫂) to transpile those new features into standard **ES5**.

- Installing the preset:

```bash
npm install @babel/preset-env --save-dev
```

- Adding the `@babel/preset-env` plugin in the `webpack.config.js` file. 

```javascript
// ...
{
  test: /\.js$/,
  loader: 'babel-loader',
  query: {
               // 👇 H e r e ! 👇 
    presets: ['@babel/preset-env', '@babel/preset-react']
  }
}
```

Finally we are able to write **JavaScript** code using all the latest features. 👨‍💻

### Adding CSS 💅

A web application without **CSS** is like a cheese burger without the hamburger. 🍔 🧀 
I mean, it is totally possible but it is not the same thing. There is a flavor missing somewhere. 🤣

![Cheese burger without a burger](https://i.imgur.com/Z546MhC.gif)

1. Let's create a **CSS** file on `src/index.css`:

⚠️ **The commercial usage of this file is prohibited by law** ⚠️

```css
.wrapper {
  empty-cells: show;
  background-color: mediumaquamarine;;
  color: blanchedalmond;
}
```
2. Import it on `index.js` file:

```javascript
import './index.css'
```
3. Apply it in the `App.jsx` component:

```javascript
const App = () => {
  return (
    <div className="wrapper">
      <h1>Hello from Webpack</h1>
    </div>
  )
}
```

🤺 **Touché moment:** Yes, we need to **install** more **loaders** in order to make our **CSS** styles work as well. How did you know that? 🤓

```bash
npm install style-loader css-loader --save-dev
```
**In short:**

- **style-loader:** Generates and injects a `<style>` element which contains all of the application styles.
- **css-loader:** Transforms **CSS** into a **JavaScript** module and allows **minification**. E.g.(**Input:** CSS ➡ **Output:** JavaScript)

Please, don't forget to also add the **loaders** in your `webpack.config.js` file, otherwise all our effort and the _RSI_ (Repetitive Strain Injury) acquired by typing `npm install` hundred times will be in vain: 😂 👌

```javascript
{
  rules: [
    {
      // ... previous config
    },
    // ⬇️  👇  👇  ⬇️
    {      
      test: /\.css$/,
      loaders: ['style-loader', 'css-loader'],
     },
     // ⬆️  ☝️  ☝️  ⬆️
  ];
}
```

### Webpack Development Server 🖥️ ⬆️

One thing that drive me nuts is having to manually refresh the page every time I make changes in the application. 🥴

![Drive me nuts](https://c.tenor.com/JlZBGvRWIFMAAAAM/crazy-ppl-make-me-crazy.gif)

Don't stress yourself, at this point of the article you have already **mastered** using `npm` to install packages. 🎓 😂

1. Install the server package:

```bash
npm install --save-dev webpack-dev-server
```
2. Define the **start script** in your `package.json` file.

```javascript
{
  // ...
  "scripts": {
    "build": "webpack --mode=development",
    //  👇  👇  👇  👇
    "start": "webpack-dev-server --mode=development"  
    },
  // ...
}
```
3. Add the `devServer` property into `webpack.config.js` file:

```diff
const config = {
  entry: './src/index.js',
  output: {
    // ...
  },
+  devServer: {    
+    contentBase: path.resolve(__dirname, 'build'),
+    compress: true,    
+    port: 3000  
+   },
  // ...
};
```
Running the `npm start` script in your terminal should start the server at `http://localhost:3000`.

### Error Handling 🚫

The way **Webpack** shows error differs a little if compared to an application created using `create-react-app`. 
Very often a error is shown but not its real location.

**Source maps** provide us with the source code that is actually causing the error.

![Bug tracking](https://i.gifer.com/NWuJ.gif)

This time, as an rare exception, you won't need to install anything. 🎉 🥳 👯‍♀️

Just add the `devtool` property in our `webpack.config.js` file and a source map will be generated (`build/main.js.map`).

```diff
const config = {
  entry: './src/index.js',
  output: {
    // ...
  },
  devServer: {
    // ...
  },
+  devtool: 'source-map', 👈
  // ..
};

```
## Minifying the source code in production

Since we are using **Webpack** in its latest version, no further configuration is need in order to **minify** the source code.

Ah, ok. I almost forget to explain what `minifiyng` code means.

**Minifying** means that your code that was previously **classified as illegible by your workmates** becomes officially gibberish. 😂 🤣 😆 😭 

![Pair Programming](https://i.gifer.com/FBtL.gif)

**Minifying** is the process that removes both comments, whitespaces, newline characters, replaces variable names with a single character and so on, in order to minimize code and reduce file size (**TLDR;** to optimize performance).

As result of minifying we would have something like this:

```javascript
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;
```
 
We need to add a `npm` script (`package.json`) to do so. 
⚠️ **Note:** `--mode=production`. ⚠️

```diff
"scripts": {
+  "build": "webpack --mode=production",
  // ...
},
```
### Conclusion, Frenzies and Farewell 💭💡👋

Indeed, there a lot more concepts to cover regarding **Webpack** but hopefully this introduction is enough for you to go and start exploring it by your own. 🗺️ 📍

Albert Einstein once said: 🧠

>If you can't explain it to a six year old, you don't understand it yourself.

After finish reading this whole article to my 2 years old sibling, he starts to uncontrollably crying. 
I guess it is **happy crying** because it looks like he got it even being younger than the expected! 👶

![Happy Crying](https://c.tenor.com/ZYa6ah7Iof8AAAAC/crying-cry.gif)

Sorry, I must go now. He is becoming really loud. 🏃‍♂️💨
Maybe I should read him my other article about **Regex**. 😬 🤭

Congratulations for reaching the end 🎉 and I wish you all a great weekend. 🙏

See ya!