Stages of Learning Webpack, Pt. 2 - The Config
Tags: webpack, javascript
Published: 2017-05-22 09:27:37

---
title: Stages of Learning Webpack, Pt. 2 - The Config
published: true
description: What is Webpack + basic configuration
tags: webpack, javascript
---

[0]: https://dev.to/nitishdayal/stages-of-learning-webpack

[1]: https://thepracticaldev.s3.amazonaws.com/i/ffzwgh10rw2c7pigx81j.png

[react + typescript boilerplate]: https://github.com/nitishdayal/react_from_scratch

[styled_components]: https://thepracticaldev.s3.amazonaws.com/i/ffzwgh10rw2c7pigx81j.png "Files under src/components/styled/elements/"

[webpack]: https://webpack.js.org

_**DISCLAIMER**: Webpack isn't the only option for module bundling. Module bundling isn't even the only option for solving the client-side module 'issue'. There's a whole lot of ways to do this stuff. I'm gonna take a crack at explaining some Webpack things because that's what I've been working with.  + my grammar isn't fantastic, and my vernacular is a mix of wannabe intellectual and obnoxious child. You've been warned._

This was supposed to go up last week, but things happened. ðŸ¤· The original draft was consumed by an unexpected system restart + me not saving my progress on the Dev.to platform, and on the second attempt I realized that trying to fit everything I mentioned at the end of my [first post][0] would lead to either a post which wouldn't go deep enough to be valuable, or one which would cause information overload. Instead, I'm going to break that content up into multiple posts.

The goal of **this** post is to explain what [Webpack] is by exploring the problem it attempts to solve, and to go over the basics of a Webpack configuration. The content will be targeted towards those who are new to the Webpack ecosystem. I don't know how much further above 'beginner' I would consider myself with Webpack, so if you're fairly seasoned read on regardless and provide feedback. ðŸ˜ƒ There are a _LOT_ of other posts similar to this one. I'm standing on the shoulders of slightly deprecated content.

## Introduction - The Problem With Client Side Modules

As users have come to expect more from their applications, client-side JavaScript development has evolved to meet those expectations. We're at a point where placing all your code in one JavaScript file can become very unwelcoming, very quickly. Applications are developed by splitting a codebase into small, relevant chunks and placing those chunks in individual files. These files are called _JavaScript modules_. When a piece of code in `fileA.js` is needed in `fileB.js`, that code can be imported into `fileB` so long as it was exported in `fileA`. In order to load these files into the browser, the approach when working with a more manageable number of files would be to add `<script>` tags as necessary. This is feasible when working with a handful of files, but applications can quickly grow to a point where manually loading all the files would be very, very complicated. Not only would you be responsible for making sure that all the files were properly referenced in your root document (main `index.html` file, whatever you call it), you would also have to manage the order in which they were loaded. I don't want to have to do that with 100+ files.

For example, here is the directory structure from my boilerplate:

```bash
  â”œâ”€â”€ LICENSE
  â”œâ”€â”€ README.md
  â”œâ”€â”€ TODO.todo
  â”œâ”€â”€ index.html
  â”œâ”€â”€ package.json
  â”œâ”€â”€ src/
  â”‚   â”œâ”€â”€ components/
  â”‚   â”‚   â”œâ”€â”€ containers/
  â”‚   â”‚   â”‚   â””â”€â”€ root.js #1
  â”‚   â”‚   â”œâ”€â”€ displayItems.js #2
  â”‚   â”‚   â”œâ”€â”€ hello.js #3
  â”‚   â”‚   â”œâ”€â”€ page2.js #4
  â”‚   â”‚   â””â”€â”€ styled/
  â”‚   â”‚       â”œâ”€â”€ elements/
  â”‚   â”‚       â”‚   â”œâ”€â”€ listwrapper.js #5
  â”‚   â”‚       â”‚   â”œâ”€â”€ navwrapper.js #6
  â”‚   â”‚       â”‚   â”œâ”€â”€ routerwrapper.js #7
  â”‚   â”‚       â”‚   â””â”€â”€ styledlink.js #8
  â”‚   â”‚       â””â”€â”€ index.js #9
  â”‚   â”œâ”€â”€ main.js #10
  â”‚   â”œâ”€â”€ routes/
  â”‚   â”‚   â””â”€â”€ index.js #11
  â”‚   â””â”€â”€ store/
  â”‚       â””â”€â”€ listItems.js #12
  â”œâ”€â”€ tslint.json
  â””â”€â”€ yarn.lock
```

Twelve JavaScript files for a **boilerplate**; we're talking about a glorified 'Hello World'. Are these large files? Not at all. Take the files found under `src/components/styled/elements/` [(full size)][1]:

![styled_components]

All of the files are under 25 lines of code. In fact, every file inside the `src/` folder comes in under 50 lines. I didn't do this for the sake of line count, however. That's a beneficial side-effect of writing _modular_ code. I split my code this way because it gives me a codebase that's easier to maintain, easier to read, easier to navigate, and easier to debug. If I need to change the way my links appear, I know exactly where I need to go to make that change, and I know that once the change is made it will reflect anywhere that a link is created. The folder structure, while probably not all that visually appealing, is nice when programming because it's logical and organized; a styled link element is found under `styled/elements/styledlink`. If there's an error or a bug (which there definitely will be), it's easy to trace the problem back to one file/module because they're split up with the intention of giving each module **one** job. If something breaks, it's probably because I didn't tell someone how to do their job correctly, and it's usually easy to tell where the error is originating from. Once the error is addressed at the module level, I know it's going to be fixed anywhere else that code was reused.

## Webpack as a Solution

So how do we get this loaded into the browser _without_ dealing with `<script>` tag shenanigans? Webpack! Webpack will crawl through our app starting from the _application root_, or the initial kick-off point (`src/main.js`), following any `import` statements until it has a complete _dependency graph_ of the application. Once it has that graph, it will create a bundled file (or files, depending on how you configure Webpack) which can be then be loaded into the browser from inside `index.html`. VoilÃ ! In it's simplest use case, that's what Webpack does. It takes a bunch of JavaScript files and puts them together into one (or a few) files that are more manageable to work with when loading into the browser, while allowing you to maintain the modularity and separation that you like in your codebase.

_"Wait a minute, guy. I've seen people use Webpack for CSS, pictures, videos...everything, and you're telling me it only does JS?"_ Yes! Out of the box, that's what Webpack is capable of understanding. However, at the beginning of my [first post][0] I mentioned that Webpack is much more than **just** a module bundler. With the right configuration settings, plugins, and loaders (more on this later), Webpack can be extended to understand most filetypes that front-end developers come across in order to bundle (and optimize) _ALL_ of your application assets. In most cases, my build process is entirely managed by Webpack & NPM scripts.

## A Basic Configuration

**Pre-requisites:**

-   Node
-   NPM/Yarn - Installing dependencies, running scripts
-   Git - Branch, clone, commit
-   Patience - I may be too wordy for my own good sometimes

Example code for this section can be found at: [github.com/nitishdayal/webpack-stages-example](https://github.com/nitishdayal/webpack-stages-example)

The rest of this post assumes you'll be following along by cloning the repo containing the example code. The repo is split into multiple branches that correspond with the upcoming sections.

Initial file layout & directory structure:

```bash
 â”œâ”€â”€ index.html
 â”œâ”€â”€ package-lock.json
 â”œâ”€â”€ package.json
 â”œâ”€â”€ src
 â”‚   â”œâ”€â”€ app
 â”‚   â”‚   â””â”€â”€ sayHello.js
 â”‚   â””â”€â”€ index.js
```

The example provided has a few files worth noting:

1.  `index.html`
2.  `src/app/sayHello.js`
3.  `src/index.js`

Let's break down what's happening in the example:

1.  `index.html` is an HTML document with two key items:
    -   The `div` HTMLElement with the id `root`
    -   The `script` tag loading a file `./build/bundle.js`

2.  `src/app/sayHello.js` _exports_ two items.
    -   An anonymous function which takes one argument and returns a window alert with the message 'Hello ' + the provided argument as the **default** export.
    -   A constant `donut` with a string value as a **named** export.

3.  `src/index.js` is the file that interacts with the document.
    -   The **default** export from `src/app/sayHello.js` is  _imported_ to `src/index.js` and is referred to as `Hello`.
    -   Two variables are declared & defined, `name` with a reference to a string value and `root` referencing the `div` HTMLElement w/ an ID of `'root'`.
    -   The `Hello` function (**default** export from `src/app/sayHello.js`) is called, and is provided
        the previously declared `name` variable.
    -   The _text content_ of the `div` HTMLElement referenced by `root` is updated to `'Helllloooo ' + name +'!'`

### Step 1

_Branch: Master_

First, we'll need to install Webpack. If you're using the example code, run `npm install/yarn` from your command line. If you're creating your own project to follow along with, run `npm install webpack -D/yarn add webpack -D`. The `-D` flag will save Webpack as a _developer dependency_ (a dependency we use when making our application, but not something that the core functionality of the application needs).

_**NOTE:** Sometimes I run Webpack from the command line. I have Webpack installed globally in order to do this. If you want this option as well, run `npm install --global webpack/yarn global add webpack` from the command line and restart your terminal. To check if Webpack is installed correctly, run `webpack --version` from the command line._

Once Webpack is installed, update the "scripts" section of the `package.json` file:

    "scripts" {
        "build:" "webpack"
    },

We've added a script, `npm run build/yarn build`, which can be called from the command line. This script will call on Webpack (which was installed as a _developer dependency_ via `npm install webpack -D/yarn add webpack -D`). From the command line, run `npm run build/yarn build`.

**Error message!** Woo!

    No configuration file found and no output filename configured via CLI option.
    A configuration file could be named 'webpack.config.js' in the current directory.
    Use --help to display the CLI options.

As far as error messages go, this one is pretty friendly. Webpack can be run in many ways, two of which are mentioned in this error message; the _command line interface_ (CLI) or a _configuration_ file. We'll be using a mixture of these two options by the end, but for now let's focus on the configuration file. The error message mentions that a configuration file could be named `webpack.config.js`; you can name your configuration file whatever you want to. You can name it `chicken.cat.js`. As long as that file exports a valid configuration object, just point Webpack in the right direction by using the `--config` flag. Example (from command line or as package.json script): `webpack --config chicken.cat.js`. If, however, you name your file `webpack.config.js`, Webpack will find it without the need for the `--config` flag. With great power comes great responsibility, etc.

We know that Webpack failed because we didn't configure it properly, so let's create a configuration file.

### Step 2

_Branch: init_

There's a new file in this branch named `webpack.config.js`:

```javascript
module.exports = env => ({
  entry: "./src/index.js",
  output: { filename: "./build/bundle.js" },
  resolve: { extensions: [".js"] }
});
```

_...wat_

Yeah, me too. Let's break this down! First, let's rewrite this without the arrow function and so the `output` and `resolve` objects are split into multiple lines:

```javascript
module.exports = function(env){
  return {
    entry: "./src/index.js",
    output: {
      filename: "./build/bundle.js"
    },
    resolve: {
      extensions: [".js"]
    }
  }
};
```

Currently we're not doing anything with this 'env' argument, but we might use it later. Exporting a function is an option, but at the end of the day all Webpack cares about is getting a JavaScript object with the key/value pairs that Webpack knows. In which case this example could be further simplified to:

```javascript
// Oh hey look! Somewhere in that mess was a good ol' JavaScript object. The kind 
// you can 'sit down and have a beer with'.
module.exports = {
    entry: "./src/index.js",
    output: {
        filename: "./build/bundle.js"
    },
    resolve: {
        extensions: [".js"]
    }
};
```

This object has 3 keys: entry, output, and resolve. **Entry** defines the entry point of our application; in our case, it's the `index.js` file. This is the file that first interacts with the HTML document and kicks off any communication between the other JS files in the application. **Output** is an object which contains options for configuring how the application's files should be bundled and outputted. In our case, we want our application to be bundled into a single file, `bundle.js`, which should be placed inside a folder named `build/`. **Resolve** is an object with an array `extensions` that has a single value, '.js'. This tells Webpack that if it comes across any `import` statements that don't specify the extension of the file that the `import` statement is targeting, assume that it's a `.js` file. For example, if Webpack sees this:

```javascript
import Hello from './app/sayHello';
```

Given the configuration provided, it would know to treat this as:

```javascript
import Hello from './app/sayHello.js';
```

To recap: The file `webpack.config.js` exports a _function which returns an object_ (that's what the whole `module.exports = env => ({ /*...Webpack config here...*/ })` thing is). The object that is returned consists of key/value pairs which is used to configure Webpack so that it can parse through our application and create a bundle. Currently, we're providing Webpack with the following:

- Where our application starts (entry)
- Where we want our bundle to go and how we want it to look (output.filename)
- How Webpack should treat imports that don't specify file extension (resolve.extensions)

Now, if we call `npm run build/yarn build` from the command line, Webpack should be able to do it's thing:

```bash
$ npm run build
> example@1.0.0 build /Projects/dev_to/webpack_configs/example
> webpack

Hash: fa50a3f0718429500fd8
Version: webpack 2.5.1
Time: 80ms
            Asset     Size  Chunks             Chunk Names
./build/bundle.js  3.78 kB       0  [emitted]  main
   [0] ./src/app/sayHello.js 286 bytes {0} [built]
   [1] ./src/index.js 426 bytes {0} [built]
```

There should now be a new folder `build/` with a file `bundle.js`. According to the output from calling `npm run build`, this file consists of `./src/app/sayHello.js` and `./src/index.js`. If we look at this file and look at lines 73-90 we see:

```javascript
"use strict";
/* harmony default export */ __webpack_exports__["a"] = (name => alert(`Hello ${name}`));

const donut = "I WANT YOUR DONUTS";
/* unused harmony export donut */


/**
 * Same code, ES5(-ish) style:
 * 
 * var donut = 'I WANT YOUR DONUTS';
 * 
 * module.exports = function(name) {
 *    return alert('Hello ' + name);
 * };
 * exports.donut = donut;
 * 
 */
```

That's `./src/app/sayHello.js`, and would you look at that, Webpack knew that even though `const donut` was _exported_ from the file, it wasn't used anywhere in our application, so Webpack marked it with `/* unused harmony export donut */`. Neat! It did some (read: a lot) of other stuff too, like changing the `export` syntax into...something else entirely. `./src/index.js` can be seen in lines 97-111. This time, anywhere that a piece of code from `./src/app/sayHello.js` is used, it's been swapped out for something else.

```javascript
"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__app_sayHello__ = __webpack_require__(0);

// Import whatever the default export is from /app/sayHello
// and refer to it in this file as 'Hello'

const name = "Nitish";
// Reference to the <div id="root"> element in
const root = document.getElementById("root");

// Call the function that was imported from /app/sayHello, passing in
// `const name` that was created on line 5.
__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_0__app_sayHello__["a" /* default */])(name);
root.textContent = `Helllloooo ${name}!`;
```

Going over everything that is happening in the bundle is best saved for another post; the intention of looking at this file to prove that, yes, Webpack did indeed go through our code and place it all into one file.

If we remember, the `index.html` document had a `<script>` tag which referenced this bundled JS file. Open `index.html` in your browser to be greeted by an alert and a sentence inside a div! Congratulations, you've used Webpack to create a bundle!

EDIT: [Part 3 is finally up!](https://dev.to/nitishdayal/stages-of-learning-webpack-pt-3---sourcemaps-loaders--plugins)