Webpack for Beginners — Part 2

Williams Adu
4 min readAug 16, 2017

--

Wow. Now we are here! In the previous article of this series, we introduced ourselves to Webpack and what kind of problems it solves. If you missed that one, just check it here.

In this series, we will be setting up Webpack and all the configuration that come with it. So stay tight! Let’s begin by creating a directory for the project that we will be working with.

mkdir learning_webpack
cd learning_webpack

Good. Then let’s bring in webpack as a dev dependency in our package.json whiles creating an index.html and index.js file.

// Execute these in learning_webpack directorynpm init -y 
npm install webpack@3.3.0 --save-dev
touch index.html
touch index.js
// index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>Learning Webpack</title>
</head>
<body>
<div id="app"></div>
<script src="index.js"></script>
</body>
</html>

We have just set up a basic html and referenced an index.js file in it. That’s great work so far. Well done so far!!

In the previous article, we said webpack introduces what is called a Dependency Graph. It does that by making use of the magic require keyword in pulling in dependencies. This can be explained with a simple example as shown below:

// index.jsfunction HelloComponent(message) {
this.message = message;
}
HelloComponent.prototype.appendMessage = function() {
var p = document.createElement('p');
p.innerText = this.message;
var main = document.getElementById('app');
main.appendChild(p);
}
var component = new HelloComponent('Hello world!');
component.appendMessage();

This is pretty basic and simple. There’s not much of a dependency issue here. But let’s assume that we had all messages in another file and we wanted to create other components that depended on this message file. See code below:

cd [/path/to/learning/webpack]$touch messages.js// messages.jsconst messages = {
hello: 'Hello world!',
hi: 'Hi everyone!'
}
module.exports = messages;

We have just created a messages file in the same directory as index.js and exported a message object using commonJS syntax (this accounts for the presence of module.exports). Without module.exports, we would get 2 scripts in index.html ie index.js and messages.js. That’s pretty simple. Yay!!

Next, let’s change the HelloComponent a bit to now depend on the messages:

// index.jsvar messages = require('./messages');function HelloComponent() {
this.message = message;
}
HelloComponent.prototype.appendMessage = function() {
var p = document.createElement('p');
p.innerText = this.message;
var main = document.getElementById('app');
main.appendChild(p);
}
var component = new HelloComponent(messages.hello);
component.appendMessage();

Note the use of require:

var messages = require('./messages');

Webpack understands the presence of require and is able to pull in the necessary dependency ie messages from messages.js.

Now how does Webpack comes in to play here? To better verify, let’s now execute the following commands.

./node_modules/.bin/webpack index.js dist/index.js

If you followed along, you would see the chunks emitted by Webpack and how the processing went. So webpack as an executable command takes 2 arguments ie entry file and output file (don’t worry if it doesn’t exist). Well, if you installed Webpack globally, you could also execute the above command as: webpack index.js dis/index.js. From executing the command, a new folder called dist is created with a file index.js. Try to inspect that file. It’s fun. Well, for a tip, Webpack inserts some boilerplate code before packing your code below it.

At this point, we need to tweak our script in index.html a little. It now looks like this:

<script src="dist/index.js"></script>

The conclusion at this point is that, no matter the dependent scripts, Webpack will resolve them into a simple, single script with everything managed for you. You only then focus on managing your code and Webpack then handles any dependencies. Isn’t that cool?

Now what about other images? In today’s fast-paced computing, Single Page Applications are really raging out there. Raaaaarrr!! HTML now seems to placed within JavaScript. And that includes CSS too. So what about the images that become dependencies in these files? Hmm…wondering.

Ok, now let’s talk about loaders. But, what about the question on images? I know. Understanding loaders will help answer that question. Anything that isn’t JavaScriptish but becomes a dependency in a JavaScript file can be processed by Webpack with the presence of a loader. So just find style-loader or css-loader if you are depending on some CSS. With images, perhaps find file-loader. So whatever isn’t a JavaScript but is a dependency in your module, find the its loader and shoot it! But how do we use a loader in Webpack?

Our work is getting messier. Let’s put everything Webpack needs to know into a configuration file — webpack.config.js (Well, that’s the default name for the configuration file).

// webpack.config.jsvar path = require('path');module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
}
}

Still using the commonJS module, we export the config object. Well, does any component look confusing? I guess you are wondering where the path module came from? It’s path of the default modules that ships with Node.js. I’m just require(ing) it and making good use of it. Now we can just run one command:

webpack

Just that? Yes. Webpack will read instructions from webpack.config.js file and build the output file. Cool! So now, let’s add the loader for image. But first let’s append an img in the index.js file.

// index.js (a portion of it gets updated)var image = require('./img.png') // Make sure that file existsHelloComponent.prototype.appendImage = function() {
var div = document.createElement('div');
div.innerHTML = '<img src="' + image + '" />';
var app = document.getElementById('app')
app.appendChild(div);
}

Then we add a loader in webpack.config.js file as follows:

// Execute the following commandsnpm install file-loader -D// webpack.config.jsvar path = require('path');module.exports = {
entry: 'index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
},
module: {
rules: [{
test: /\.png/,
use: 'file-loader'
}]
}
}

modules accept a single rule or an array of rules. Each rule accepts one or more loaders. Go here to learn more about loaders.

Ok, so we end Part 2 of this series. We discussed how to setup Webpack. We also discussed how to handle JavaScript dependencies and non-JavaScript dependencies. There’s more amazing things Webpack can do. Stay tuned for more in the coming articles.

--

--