Introduction to Webpack!

July 20th, 2016

webpack-logo

Webpack is all the rage these days, but it seems like getting started with Webpack is kind of tough. Let’s take some time to walk through the fundamentals of Webpack and get started by using Webpack with babel to transpile our ES6 code.

Module loader

At its base, Webpack is just a module loader, it allows us the ability to make our code nice and modular. Modularity gives us the capacity to create more maintainable code through organization. We have had this ability before, we have tools like browserify that allow us to compile our modules into a single source. The key to Webpack is that it is not only JS that it allows us to import and make module, it is CSS, Images and more!

Let’s start simple

To get started let’s create a directory like the one shown below. There are two folders I want to talk about src, and dist. The src will act as our source folder, or the folder that holds the code we will be writing, in that is a folder for any of our modules. The dist folder will be the final destination for our code, this is where our bundled code will end up.


- src
   |- app.js
   |- modules
        |- //module files
- dist
   |- //where out bundle will go.
- webpack.config.js
- index.html

We also have the webpack.config.js file which we will spend a lot of time in, and an `index.html` file so we can see our work!

Writing our first modules

Before we configure Webpack, let’s right a module first, so we can understand what it is doing for it. In the modules folder, create a new file called header.js. For this example, we will play around with using ES6 Template Literals to create markup! We will also be using ES6 module syntax for our example, if you are unfamiliar with ES6 modules check out my video Let’s Learn ES6 – Module. Note that we have to use a module loader like Webpack or Browserify to actually load our ES6 modules. At this point, there is no mechanism in the browser for actually importing these files just yet.

src/modules/header.js


export default `<header>
    <h1>My first Webpack!</h1>
</header>`

Neat, a simple little template literal with our code in it! Next we will want to work in the src/app.js file and import that in!

src/app.js


import header from './modules/head';

document.body.innerHTML = header;   

Here we import the header from the module, this variable has the value of just that string. Notice how when we import it, we do not need the .js at the end. After importing it then we just apply it to the .innerHTML of our body for now. In our index.html we should have the following.

    
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <script src="dist/bundle.js"></script>
</body>
</html>

Opening this in your browser will not work, mostly because there is no bundle.js in your dist folder!!

Webpack

Finally we can start working on our webpack.config.js file. The Webpack config file is just that, a config file. This differs from a task runner like gulp, in gulp you program how you want certain things to happen, with Webpack we configure the different tools to work together. This is similar to grunt in my mind, grunt, before gulp, was more about creating a file that configured how your build system should run.

Webpack base

Before we get started, you need to make sure you have Webpack installed. Run npm install -g webpack so that it is available in the terminal. The beginnings of our Webpack file look like this.

webpack.config.js


module.exports = {
    entry:  `${__dirname}/src/app.js`,
    output: {
        path: `${__dirname}/dist`,
        filename: 'bundle.js'
    }
}    

First we export, using a CommonJS style module, our config object. There are a few properties we need to add to this. The first is the entry property, what is the entry point of our configuration. In our case this is going to be our src/app.js. Here we are using the Node global __dirname to make sure it is loading the file from our specific folder.

Next we need to configure our output. This is an object that will define the path we want place it in, and the filename for the output file.

We can actually run this to see what happens by running webpack from the terminal where the webapack.config.js file lives. What should happen, is you should see an output something like this.


Hash: 5f31a0038d1d3ae4b38e
Version: webpack 1.13.1
Time: 34ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.46 kB       0  [emitted]  main
   [0] ./src/app.js 73 bytes {0} [built]

If we look in our dist folder we will see our bundle.js file! However there is a problem still! Looking at the index.html file in the browser, we will see this error!


Uncaught SyntaxError: Unexpected token import

Because we are using ES6 modules, we need to transpile them. More importantly, even though they are in the language, browsers have no mechanism for loading modules yet. There is a lot of discussion going on about this at the moment, especially in the node community.

Loaders

In order for us to get this to work we need to use Babel to transpile our code, before we configure this we have to install a few more packages.

Since we have not created a package.json yet we should run npm init and run through those steps, mostly you can just hit enter to speed things up for now. The package.json will allow us to track our dependencies for our project when we use the --save or --save-dev flags.


npm install --save-dev babel-core babel-loader babel-preset-es2015

There are a few things we install here, we need Babel core to transform our code, and the es2015/es6 Babel preset to actually take our code and make it ready for older browsers.

The important piece here is the babel-loader package. Webapack has lots of loaders, maybe we can explore more of them in future posts, but this is the package that will configure our files and help us it all bundled up! Now we must configure our webpack.config.js file to work with this loader, below you will find the final code.


module.exports = {
    entry: `${__dirname}/src/app.js`,
    output: {
        path: `${__dirname}/dist`,
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                loader: 'babel', 
                query: {
                    presets: ['es2015']
                }
            }
        ]
    }
}

Whoa! Let’s break it down. First we have the module property, this property will allow us to define the loaders we want to use in our script among other things. Next we have the loaders array, this is an array of objects that define the loaders.

The loader object has a few properties we want to look at, first is loader, this is the loader we want to use. We installed babel-loader so we are able to use babel here and it will know what we want. Another thing to look at is the test property, this is a Regular Expression used to define what files we want to look at. And finally, for us, we have the query property. Webpack loaders can be sent query parameters to define how they are configured, in this case we want to configure babel to use the es2015 preset. If we were working on a React project, we would have to install the babel-preset-react package and include that in our configuration.

Example with the babel-preset-react package installed.


{
    test: /\.js$/,
    loader: 'babel', 
    query: {
        presets: ['es2015','react']
    }
}

Now if we run webpack again we should see the file and it should work in the browser!

Webpack dev server

Running webpack over and over again is no fun, we can pass the --watch flag when we run Webpack, this will keep the script watching and waiting until we change the file!

But let’s take this one step further and use webpack-dev-server!


npm install webpack-dev-server -g

This is a special server that will watch our files, and create a local server to serve up our files. We need to install this globally so that we can run the webpack-dev-server command. Now instead of running webpack we can run webpack-dev-server, you should see an output that looks something like this.


$ webpack-dev-server
http://localhost:8080/webpack-dev-server/
webpack result is served from /
content is served from /Users/ryanchristiani/Sites/lets-learn/es6/webpack
Hash: fed08eba1d7744f347e7
Version: webpack 1.13.1
Time: 396ms
    Asset     Size  Chunks             Chunk Names
bundle.js  1.88 kB       0  [emitted]  main
chunk    {0} bundle.js (main) 409 bytes [rendered]
    [0] ./src/app.js 248 bytes {0} [built]
    [1] ./src/modules/header.js 161 bytes {0} [built]
webpack: bundle is now VALID.

Now we can go to http://localhost:8080/webpack-dev-server/ and see our app running. When we make a change to one of our files, we will see that reflected in the browser. Now you are ready to go! I hope this helps provide a better sense of how Webpack works, if you liked this walk through let me know!


Warning: count(): Parameter must be an array or an object that implements Countable in /home/ryanch6/public_html/wp-includes/class-wp-comment-query.php on line 405
  • Amardeep

    Hi Ryan, Thanks for this post. Its very helpful.
    However, I works on most of php projects, where there are some js files I load depends on page (purpose to just not load unnecessary files). So is there any solution. Can be there for page specific bundle loader or something? coz webpack ‘ll bundle all the js files.

    Again Thanks for this very helpful post and I finds your tutorials very helpful specially the “LetsLearnES6”

  • Jordan Masters

    Thanks very much for this post. As a beginner with React all the different tools and terminology is very confusing but this cleared it up for me!