# Webpack is awesome!

There are an endless amount of javascript libraries out there today, and webpack is one that you should learn how to use. Webpack is a module builder, which allows you to bundle all of your javascript and css into a single minified file.

I am by no means an expert with webpack, but I feel I have used it enough to explain how it works and give my opinion on it. I've use it with both React and Angular applications and it works very well. It also includes tools such as [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html), which offers hot module reloading.

## Why use webpack?

If you want an easier life, use webpack. It's as simple as that. It's something that seems intimidating and hard to understand at first (especially if you have never used a mondule bundler like myself). It keeps your files clean and modularized. There are also many different useful tools and plugins such as [PostCSS](https://github.com/postcss/postcss-loader) and [autoprefixer](https://github.com/postcss/autoprefixer). Autoprefixer adds many different browser prefixes to your css as it goes through the build process.

Webpack is something that is extremely useful when you start using javascript frameworks such as React and Angular. It may seem unnecessary until you start building projects with a lot of javascript. It may seem easier to just include your javascript tag at the end of your HTML files. With webpack, this is done for you.

## Getting started

First we will create a new project and initialize it with npm. Then install webpack globally and save it. This will allow us to run `webpack` from the command line.

```bash
    npm init
    npm install -g --save webpack
```

You should now have a package.json file. Create an `index.html` file in a `public` folder and create an `src` folder as well. Within src create `app.js`. This is your main javascript file in which everything will be contained.


Let's put some dummy code in `app.js`

```javascript
    window.onload = function(){
        console.log("test123");
    }
```

Create a new file called webpack.config.js. This is the file that webpack will look for when you run the command `webpack`. Within this file we need to define a few things in order to get started.

`webpack.config.js`

```javascript
    //dependencies
    var webpack = require('webpack');
    var path = require('path');

    module.exports = {
        //our main javascript file where everything is included
        entry: ['./src/app.js'],
        //the path we want to output all files
        output: {
            path: './public',
            filename: 'bundle.min.js'
        }
    }
```

The folder structure will look like this

```bash
    root
      |-package.json
      |-webpack.config.js
      |-src
         |-app.js
```

Let's issue the command `webpack`. You will notice the public directory is created with `bundle.min.js`. When we are ready to deploy to production we can use `webpack -p` to minify the javascript.

The new folder structure will look like:

```bash
    root
      |-webpack.config.js
      |-package.json
      |-src
         |-app.js
      |-public
         |-index.html
         |-bundle.min.js
```

## Webpack Loaders

Loaders allow us to do things with our code before it is bundled and minified. I say "things" because there are all sorts of loaders out there that do various things. I will go over a few of the more common loaders and how they work. Every time we include a new file type into our javascript we need to make sure there is a loader for it (like css, scss, jpg, svg, etc.).

Let's upgrade to ES6, because it is the new thing right? If you are unaware, ES6 or referred to as ES2015 is a newer version of javascript with some different syntax. I will not be covering ES6 at all here, but it isn't a whole lot different than ES5 so don't worry.

There are a few different things we need to install to get all of the features of ES6. We need babel-loader as well as babel-preset-2015 for syntax and babel-polyfill for extra features.

```bash
    npm install --save babel-loader babel-preset-es2015 babel-polyfill
```

Let's add the loader to the webpack config file so our ES6 gets converted to ES5 when we build with webpack. Notice `babel-polyfill` and `presets: ['es2015']`.

```javascript
    //dependencies
    var webpack = require('webpack');
    var path = require('path');

    module.exports = {
        //our main javascript file where everything is included
        entry: ['babel-polyfill', './src/app.js'],
        //the path we want to output all files
        output: {
            path: './public',
            filename: 'bundle.min.js'
        },
        module: {
            //defines how we want to process each type of file before building
            loaders: [
                {   
                    //all files with .js extension are loaded
                    test: /\.js?$/,
                    //exclude folders here
                    exclude: [/(node_modules)/],
                    loader: 'babel-loader',
                    //include the presets
                    query: {
                        presets: ['es2015']
                    }
                }
            ]
        }
    }
```

Just like that we can start writing ES6 javascript. We can also start using imports now and split up our javascript into multiple files.

`print.js`

```javascript
    //this is imported by default if functions aren't specified
    export default function print(text){
        console.log(text);
    }
    
    export function printAgain(text){
        console.log(text);
    }
    
    export function printAgainAgain(text){
        console.log(text);
    }
```

Let's import these functions into the app. Only javascript files do not need to have file extensions when imported.

`app.js`

```javascript
    //x can be named anything because it is exported from print.js by default
    //we have to specify each function in {} if it is not default
    import x, {printAgain, printAgainAgain} from './print';

    window.onload = function(){
        x(1);
        printAgain(2);
        printAgainAgain(3);
    }
```

## Loading CSS with webpack

This part is going to seem confusing at first because you are probably used to including css in the HTML head. Now, with webpack, we can include this in our javascript file. It gets bundled in as well which is nice. When the page loads the javascript will inject the css into the head of the HTML document.

It may seem odd to load CSS this way, but it's nice loading everything as if the webapp is a complete javascript application. For example, in Angular or React the CSS can be loaded in each component separately. This can be nice since all of your application is going to be injected into a div of the index.html file. This will make more sense if you are familiar with single page web applications.

```bash
    npm install --save style-loader css-loader
```

Let's now add the loader object to the loaders array in our webpack.config.js file.

```javascript
    {
        test: /\.css$/,
        loader: "style-loader!css-loader"
    }
```

We can add some CSS now. It's also a good idea to adjust the folder structer now that we are adding some new types of files. Keep in mind when we do this the entry in webpack.config.js needs to be updated accordingly. We must also adjust the imports in the javascript files.

Create a CSS file in a new folder.

```bash
    root
      |-webpack.config.js
      |-package.json
      |-src
         |-js
           |-app.js
           |-print.js
         |-style
           |-app.css
      |-public
         |-bundle.min.js
         |-index.html
```

Let's add some CSS to test it out.

```CSS
    html{
        color: red;
    }
```

Now we can import the CSS into our `app.js` file.

```javascript
    //x can be named anything because it is exported from print.js by default
    //we have to specify each function in {} if it is not default
    import x, {printAgain, printAgainAgain} from './print';

    //import css
    import '../style/app.css';

    window.onload = () => {
        x(1);
        printAgain(2);
        printAgainAgain(3);
    }


```

We can then start creating more CSS files and import them into relative Angular/React components.

CSS is boring these days so let's use [SCSS](http://sass-lang.com/). Let's also add [autoprefixer](https://github.com/postcss/autoprefixer) so our CSS works across browsers out of the box.

```bash
    npm install --save sass-loader node-sass postcss-loader autoprefixer
```

We have a few more thins to do now before this works. We need to add a new loader for SCSS files.

```javascript
    {
        test: /\.scss$/,
        loader: "style-loader!css-loader!postcss-loader!sass-loader"
    }
```

We also need to import `autoprefixer` and tell postcss to use it. The new `webpack.config.js` file is below.

```javascript
    //dependencies
    var webpack = require('webpack');
    var path = require('path');

    //autoprefixer for css
    var autoprefixer = require('autoprefixer');

    module.exports = {
        //our main javascript file where everything is included
        entry: ['babel-polyfill', './src/js/app.js'],
        //the path we want to output all files
        output: {
            path: './public',
            filename: 'bundle.min.js'
        },
        module: {
            //defines how we want to process each type of file before building
            loaders: [{
                //all files with .js extension are loaded
                test: /\.js?$/,
                //exclude folders here
                exclude: [/(node_modules)/],
                loader: 'babel-loader',
                query: {
                    presets: ['es2015']
                }
            }, {
                test: /\.css$/,
                loader: "style-loader!css-loader"
            }, {
                test: /\.scss$/,
                loader: "style-loader!css-loader!postcss-loader!sass-loader"
            }, ]
        },
        //use postcss for autoprefixer
        postcss: function() {
            return [autoprefixer]
        }
    }
```

Now we just need to change our CSS file to an SCSS file. Also remember to change the import in the javscript file. Just like that we can start writing SCSS and not have to worry about the annoyance of adding CSS prefixes.

I am going to end this post right here before it gets too long. There are many other things that webpack offers, but now you should have the general idea of how it works. I may discuss some of the other plugins in future posts.

[A link to the branch that I used in this post can be found here.](https://github.com/mgerb/javascript-resources/tree/Part_3)