You are probably going to bump into Webpack at some point if you are doing React development, and if you do it’s good to be armed with an idea of what it’s about, what it does, why it is needed and where it fits in (with Node, NPM etc.)
This guide is to explain all that!
(This article was originally publish on my JavaScript Website, and I thought it would be very useful for React developers too.)
One of Javascript’s best features is you can start out really simple and learn it with just a text editor and a web browser. You can write a simple piece of HTML, add some Javascript, such as alert('hello')
, and open that in your browser. You get immediate feedback about what you are doing. From there you could write code to do something when you click a button, submit a form and much more.
If you want to use other people’s scripts to help build your application, you can include them via the src
attribute of the script
tag. You can use the script tag to pull in great libraries, like React, JQuery and many others to make your life easier developing certain kinds of UI. There are also tools for making Excel-like tables, or code editors and much more. You can reuse so much technology that you can quickly get an impressive app made in minutes.
However there at some point, when you make a complex enough app you might hit a few problems:
- The app gets really big, and your Javascript takes too long to download, especially on mobile devices with slow connections.
- You need libraries that depend on each other, and might use different versions of the same thing. For example you need to use something that itself requires JQuery or React.
- Different libraries use different ways of referring to other libraries. Some will expect there to be a property on the window object set by another script, while others expect a module system, like RequireJS to be used.
- The order of your
<script>
tags becomes important and needs to be maintained as you use lots of libraries. - You need to either copy the libraries to your computer and keep them up to date, or reference libraries on different website URLs, but you may not trust their load speed or even their content.
Many of these problems are addressed by using a couple of tools:
- NodeJS – is a tool for running Javascript on a computer rather than in the browser. It can be used as either a “Server” that can be accessed via http or a tool that runs commands from the command line.
- NPM – this is the package management system that comes with NodeJS for installing both tools to run via Node, and also it is used for install Javascript packages that will run on the client – more about that in a moment!
- Webpack – a tool for taking Javascript dependencies that you need and bundling them with your Javascript so that you can be sure that everything will load correctly.
It is hard to cover all of this in depth in just one article, so what I’ll do is give you a feel for how it all works, then you can decide whether to persue it further for your projects.
NodeJS
Before we move on to webpack, we need to look at NodeJS
Node can be installed on Windows, Mac or Linux and you can download from https://nodejs.org/
Once downloaded and installed you can open a command prompt or terminal and type in
node
and you will see a welcome like this:
Welcome to Node.js v12.8.0.
Type ".help" for more information.
>
This is in interactive mode. You can now type in Javascript, for example x = 3
and it will evaluate that and return the result.
You can type .exit
to quit.
Node can also run a Javascript file in your computer, for example you can create a file index.js
and enter the line:
console.log('hello')
Then from the command line run
node index.js
and see what you’d expect:
hello
The file index.js can contain a complicated program, and do many cool things. Javascript in Node, unlike the browser has access to the local file system and many other resources. That means it is possible to make complete development tools in Node. And indeed Webpack is one of those tools.
But how would you get the Webpack file to run locally?
Installing things into a NodeJS project
NodeJS has an installation and package managment tool called NPM. This is simlar to package managers in other programming languages, like pip in Python or even apt-get in Debian and Ubuntu.
With node installed you can use npm right away. Typing npm at the command line shows something like this:
Usage: npm <command>
where <command> is one of:
access, adduser, audit, bin, bugs, c, cache, ci, cit,
clean-install, clean-install-test, completion, config,
create, ddp, dedupe, deprecate, dist-tag, docs, doctor,
edit, explore, get, help, help-search, hook, i, init,
install, install-ci-test, install-test, it, link, list, ln,
login, logout, ls, org, outdated, owner, pack, ping, prefix,
profile, prune, publish, rb, rebuild, repo, restart, root,
run, run-script, s, se, search, set, shrinkwrap, star,
stars, start, stop, t, team, test, token, tst, un,
uninstall, unpublish, unstar, up, update, v, version, view,
whoami
npm <command> -h quick help on <command>
npm -l display full usage info
npm help <term> search for help on <term>
npm help npm involved overview
You can use this to install node packages. You can either install them globally for your machine, or locally for a project. I recommend for now always installing things locally, so that you ‘start fresh’ with each new project and know exactly what is installed. Installing locally is the default.
To get started with npm, you first create a project. Just create a folder and run a command to initalise it as follows:
mkdir test
cd test
npm init --yes
The --yes
means it will say yes to all of the questions, which gives good enough defaults about the name of the project etc.
Now if you look in the folder there is a package.json
which is a file that describes your project, and it keeps track of what other projects you depend on.
Now let’s install something. How about webpack!
npm install -save-dev webpack
The -save-dev
means it will consider the thing you are installing a ‘developer’ dependencie, i.e. a tool that you will use to help you do development, but isn’t part of your main program.
What happens when you install
The install will take a few seconds (depending on you connection to the internet). Once this is done, some things happen in your project folder:
- A
node_modules
folder is generated which contains the source files for what you installed. - In
package.json
adevDependencies
section has been added which contains information about the package you installed. - A
package-lock.json
file is created which details the actual versions of dependencies installed.
Take a look at all of these now, but don’t worry if you don’t understand them for now.
Now webpack is installed, how do you run it? This is a bit non-obvious, but not too hard.
Webpack has been installed into the node_modules
folder. You could go and hunt for it’s script in there and run it with the node
command. That would totally work. However this is the hard way because every node module has it’s files arranged in different ways.
The easier way is to edit package.json
and add an entry to specify a script that you can run that in turn will run webpack. This seems convulted, and it is, but it means NPM takes care of finding the entry point of the package for you. If you edit the package.json file and add a value under scripts as follows for webpack:
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "webpack"
},
...
Running Webpack
You can now run webpack from npm itself:
npm run webpack
And it figures out where to find it.
Run that command now and let’s see what happens.
After a moment of consideration, it will ask you if you want to install webpack-cli
which is needed to use webpack from the command line as opposed from a node program. Say yes. It will download and install that for you, as if you typed npm install --save-dev webpack-cli
.
You will get an error because there is nothing for webpack to process. Yes errors suck, sorry!
It will look for a source Javascipt file src/index.js
(we can configure it to look elsewhere if we wish). So let’s create a folder called src
within the project folder test
, and a file called index.js
inside that, and add the following Javascipt code:
console.log('hello')
Now type npm run webpack
again, and it will be succesful.
Once run, it will create a folder called dist (for distribution or distributable) and inside there is an main.js
. What do you think will be in there? Have a guess then open it up.
Spoiler alert;
It’s a long line of weird funny Javascript, with your console.log("hello")
somewhere near the end. If you didn’t guess that, it’s fine, neither did I the first time I used it.
That funny JS is code that deals with module loading, something necessary for piecing together many different packages into one bundle. It helps with modularisation, something that Javascipt on it’s own traditionally couldn’t achieve.
This code happens to be code that works both in the browser and on NodeJS. That’s not usually the case, but with a simple console.log it does work in both places. Let’s run it:
node dist/main.js
And you get the expected ‘hello’!
You can also put run it in a web page, by creating a file index.html
with the following content:
<html>
<head>
<script src="dist/main.js"></script>
</head>
</html>
When you open this file in a browser, and open the dev tools by pressing F12, and click the “console” tab you will see that it outputs hello there too.
Using a depedency
Webpack supports the require
statment for using dependencies in your project. There are two main types:
- Other files in your project
- Other projects available via the NPM ecosystem.
Let’s try using both, and see what webpack does with these.
Local files
To reference another javascript file from your index.js
you just use:
var imported = require('./otherfile.js')
To give you an idea, index.js
could contain:
var imported = require('./otherfile.js')
console.log(imported.hello)
and the otherfile.js
contains:
exports.hello = 'hello'
and when you run webpack, and run the generated main.js
it will do as it did before and print hello.
This works because in otherfile.js
the object exports
becomes the return value of the require
call in the other file. It’s how you teleport an object across! More accurately, the strange code we saw earlier in main.js
modularises each file, then runs the module for the otherfile.js
first, and get’s its return value and provides it to the module for index.js
.
Although we have used a simple string here, of course you can export anything – a function, an object or a class or value, and you can export multiple things by using different properties of the export
object, allowing you to export a whole suite of utilities if you need to.
NPM packages
Earlier we used npm to install webpack, a tool that we are using to package our javascript files into a single file. We can also use npm to install dependencies that we need for our source javascript to run. For example we might want to use the popular jQuery library to manipulate the browser DOM and add or remove elements from the page.
Let’s do that now.
Remember earlier we added webpack as a developer dependency. We will now add jQuery but as a regular dependency. jQuery is hosted on npm under the package named ‘jquery’. To install it we run:
npm install jquery
If we now open our package.json
we can see the dependency now inside the "dependencies"
section rather than "devDependencies"
.
"dependencies": {
"jquery": "^3.4.1"
},
"devDependencies": {
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10"
}
}
With this installed we can now use require in our Javascript to use JQuery. This is how we would do it inde index.js
:
var $ = require('jquery')
$(document).ready(function() {
$("<p>Hello</p>").appendTo("body");
});
In this example we use require to get the jQuery reference and assign it to a variable called $
as is customary with jQuery. We then go ahead and use $
in 2 jQuery calls, one to wait for the document to be ready, and once it is, we use it to append “Hello” to the document.
If you are following along you can now reload the index.html
and see the word Hello appear in the document. Previously it appeared in the console log.
I am going to leave it here for now talking about Webpack. What we have seen is it’s default behaviour. It is very configurable though, and you can change where it gets files from, where it writes to, whether it ‘minifies’ the Javascript (make’s it smaller) or not, and even use plugins and loaders to extend it to deal with other features like converting css files or compiling files written in other programming languages, like Typescript. It’s an amazing powerful tool.
I hope to write a second article going into those options soon.