Intro to Webpack

Webpack is essentially a code bundler. It takes your code, transforms and bundles it, then returns a new ‘compiled’ version. If you’re thinking why do I need to do this, maybe learning Webpack isn’t for you just yet. If however, you want to write ES6 JavaScript or React, then this is for you so continue reading.

Webpack is a very complex tool, and most people do not need to know how every part of it works. I have been using it for 9 months and still haven’t used it to its full potential. This run through is only going to cover the very basics but will get you up and running with a little project.

So let’s start!

There are three key parts to a basic Webpack configuration.

  1. entry — the starting point of your application
  2. loaders — the transformations you want to make on your code
  3. output — where you want your compiled code to go

Now the code part!

Let’s start by creating a package.json file in the root of your project by running npm init, keep pressing enter and fill out the information asked if you want, otherwise just keep pressing enter till it’s done. Look in the root of your project and you will see a package.json file has been created with the information you gave.

Now let’s install Webpack as a dev dependency in this project:

npm install webpack --save-dev

Take another look at your package.json file and you’ll see a new devDependencies property has been added. Magic right!

Next create a webpack.config.js file in the root of your project, this will contain all of our Webpack configurations. If you pick up a project and see 2 webpack.config.js files that is because as your project gets ready for production you may want to do slightly different things, but for this we’ll only be working with one file.

At the top of your file let’s write :

module.exports = {
entry: [
'./app/index.js'
]
}

Here we have given our object a property of entry and a value which is an array, with a string that points to the index.js file in our app directory. This could just be a string instead of an array like I’ve done, but Webpack does allow you to have several entry points so I always default to an array just in case I add another.

Now that we have told Webpack where to start we need to tell it which transforms to make on the code. We add a module property to the object we’re exporting, then that module property will have another property of loaders which is an array. Now your webpack.config.js file should look like this.

module.exports = {
entry: [
'./app/index.js'
],
module: {
loaders: []
}
}

Let’s say we want to install the babel-loader module into our project so that the browser can understand the latest and most awesome JavaScript we are writing. You run:

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

I am not going to go into too much details about what to write here as this can vary between projects plus the purpose of this tutorials is to show you what you’ll need in your webpack.config.js file. And these settings can vary between projects. For this loader we’ll do the following:

module.exports = {
entry: [
'./app/index.js'
],
module: {
loaders: [
{
test: /\.js$/,
include: __dirname + '/app',
loader: 'babel?presets[]=es2015'
}
]
}
}

You can find the recommended loaders config in the README of the project you want to install. I will not go into too much detail about all of the above parts but I will however explain what each part does.

So let’s step through what we’ve done. The first part is test, it may look a little scary if you’ve not seen a regular expression before but all this is doing is telling Webpack to only run this loader on files with the .js extension. Next is include, this tells Webpack to only run the loader on files in the webpack-tutorial/app directory. We only want to transform code we have written not code from other npm modules added to the project. The last part is loader, this tells Webpack which transformation to run on all paths that match test and are in the include.

Now the third and final part to Webpack, the part where we want our transformed code to go. We add another property called output, with a filename and path. Like so:

module.exports = {
entry: [
'./app/index.js'
],
module: {
loaders: [
{
test: /\.js$/,
include: __dirname + '/app',
loader: 'babel?presets[]=es2015'
}
]
},
output: {
filename: 'index_bundle.js',
path: __dirname + '/dist'
}
}

Here we can see filename is the name of the file that Webpack is going to create which contains our new transformed code. And path is the specific directory where the new filename is going to be placed.

So now when Webpack runs, our code will be transformed and will be referenced at dist/index_bundle.js. Well that’s ok, but we need our HTML to reference this specific file too.

There’s more!!

Now we need to come up with a plan to get our HTML to reference the compiled file. At the moment the code we’re developing with is in the app directory and our transformed code is in the dist directory. We want to only ever edit the index.html located in the app folder.

There are several ways of doing this in Webpack. We could copy and paste the file into the dist folder but you would need to do this every time you made a change which is not an effective workflow.

So the next part of the tutorial is not essential for Webpack as it can be done in several ways, this way is just one way simple way for a static structure like we have in this tutorial.

We are going to use a Webpack tool that will essentially do the copy and pasting for us, called HTML Webpack Plugin. Let’s install this npm module to our project in our Terminal with the command:

npm install html-webpack-plugin --save-dev

Now we need to tell Webpack what we want to do with it. Firstly, we need to import this plugin at the top of your webpack.config.js file, then create a new instance of HTMLWebpackPlugin and specify two things.

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html'
});

The template is the app/index.html file that you will be editing. filename is what we want the name of the new compiled file to be. In this example we are going to keep the the name index.html.

Lastly we need to add the HTMLWebpackPluginConfig variable we created as an item in the array of plugins in our webpack config file. Your file should now look like this:

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html'
});
module.exports = {
entry: [
'./app/index.js'
],
module: {
loaders: [
{
test: /\.js$/,
include: __dirname + '/app',
loader: 'babel?presets[]=es2015'
}
]
},
output: {
filename: 'index_bundle.js',
path: __dirname + '/dist'
},
plugins: [HTMLWebpackPluginConfig]
};

Now that we’ve configured Webpack you’ll want to run it. The package.json has a section called scripts where we can put commands we want to run. Let’s add “start”: “webpack --watch”, under the scripts property. This finds Webpack in the node modules directory and runs it with the watch flag which automatically recompiles your files every time you make a change. Now your scripts property should look like this:

"scripts": {
"start": "webpack --watch",
"test": "echo \"Error: no test specified\" && exit 1"
},

Now open up your terminal and run the command npm start , you will see something that looks like this.

Wooo 🎉 your code is now compiling. Let’s test this out by writing some ES6 JavaScript in our index.js file to see if Babel compiles it. I added the following but you may want to add something else.

const appDiv = document.getElementById('app');
const name = 'Kimberley';
appDiv.innerHTML = `Welcome to ${name}'s webpack tutorial!`;

Save and open the compiled dist/index.html file in your browser and you should see some text. Wooo 🙌 ! Let’s take a look at the bottom of your dist/index_bundle.js file, you should see the browser compatible JavaScript that you wrote.

And there you have it, a very basic project set up using Webpack. Now go make yourself a cup of tea you deserve it :)

If at any point something didn’t work, all of the files for the tutorial can be found here. Or if you have any questions just ask.

You can find me online here: Twitter, GitHub