Webpack

Professional JS Bundling for the Web

The Problem

There are tons of cool new language features with JavaScript, but unfortunately it can take some time for web browsers to get caught up. That's compounded by the fact that even once all the major browsers have support, not all of their users will immediately upgrade.

For a long time web development was stuck taking a lowest-common denominator approach. Adopting new functionality almost always meant breaking the app for some percentage of your users.

What are we to do? Continue writing 10 year old jQuery?

pls no...


The Solution: Compiled JavaScript

Babel is a tool that compiles JavaScript. Our source code goes into the compiler, and build artifacts come out the other side.

We can take advantage of the latest language features as we write our code, because Babel will do the hard work of compiling our shiny new code down to an older and more widely supported version of JavaScript.

We'll distribute that compiled version of our code, so we get the best of both worlds!

We get to write modern JavaScript without losing support for lots of users.


So, what's a bundler then?

Bundlers usually compile JavaScript with Babel and add some additional functionality into the mix that makes it easy to create build assets from your source JS.

Features might include:

  • Bundling: Concatenating many source files into a single one.
  • Minification: Stripping unnecessary whitespace and renaming things to reduce file sizes.
  • Uglification: Obfuscates your code, so that it's tougher for someone to steal JS from your site and modify it for their own use.
  • Compiling: Transforms code so that it can be run in different (usually older) environments.
  • Tree-Shaking: Identifies unused or dead code and strips it out of the build output.

Popular Bundlers

There are lots of choices out here, but here's a short list of some of the more popular ones:

  • WebPack - Incredibly flexible, with a huge community around it. It's flexibility can come with some added complexity when setting up and configuring (altho it's made great strides to become easier to use lately).
  • Parcel - Simplicity rules the day with Parcel. It's a great introduction to bundlers with enough functionality to keep you satisfied for most tasks.
  • Rollup.js - Makes extensive use of tree-shaking to try and produce tiny builds. It's a bit easier to start with than WebPack.
  • Microbundle - Built on top of Rollup.js and is specifically targeted at npm package creation.

Why Webpack?

Webpack is the most frequently used tool for JS bundling and has actually become the industry standard for enterprise applications. It has a ton of configuration options. But, what makes it amazing is the fact that it now has a zero config option. Which means you can just install it into your project and get going without having to write any sort of configuration information.


The Project

We're going to create a tiny webpage that will use ES2015 import/export functionality and a package to create a web page with some animated fireworks.

We'll use this node package to do the heavy-lifting with the html canvas.


Boilerplate

Open up a git bash prompt wherever you keep your code, and we'll do some initial setup:

mkdir webpack-fireworks && cd webpack-fireworks
mkdir -p src/js docs/css
touch docs/index.html docs/css/main.css src/index.js src/js/main.js
echo -e "/node_modules/" > .gitignore
git init && git add . && git commit -m "Initial commit"
npm init -y
code .

Turning on the Lights

In VS Code, open up the docs/index.html file.

At the top of the file, type ! and then hit Tab. That's a snippet that will set up a basic HTML document for us:

docs/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body></body>
</html>

Connecting the HTML to the JS file

Modify the body of the HTML document so that it imports main.js script (This doesn't exist yet but Webpack will create it for us). We'll also need to create a div that we can show our fireworks inside.

docs/index.html

<body>
  <div id="app"></div>
  <script src="main.js"></script>
</body>

The index.js file is really just an entry point. It's responsibility is to bootstrap our application.

src/index.js

import fireworks from "./js/fireworks"

fireworks()

For now, lets create fireworks.js and toss an alert inside the exported function so we will know if that code is being executed or not.

src/js/fireworks.js

export default () => {
  alert("it (fire)works!")
}

Connecting CSS

All we need to do here is include a link to our CSS in our HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Fireworks!</title>
    <link rel="stylesheet" href="./css/main.css" />
  </head>
  <body>
    <div id="app"></div>
    <script src="main.js"></script>
  </body>
</html>

Let's add some CSS so our page renders properly as well:

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

#app {
  background-color: #000;
  height: 100vh;
}

Adding Webpack

First, we'll need to add a dev dependency on Webpack. We'll also need a couple other pieces to run a development server.

npm install webpack webpack-dev-server webpack-cli --save-dev

Next, we'll add some scripts to package.json:

{
  "scripts": {
    "start": "webpack-cli serve --mode development --content-base docs/ --open Chrome"
  }
}

Finally, run a dev server with your bundle by running npm start. Open chrome and navigate to localhost:8080 and you should see your alert!


What. Was. That?!

Ok that was a ton of extra stuff in that start command aside from just webpack-dev-server. But just because it's a lot doesn't mean it's complicated. Let's step through:

  • --mode development: All this does is tell our development server that it should be operating with the development version of our code. Since we aren't going to ever be running a production environment (especially while developing) this is perfect. If we switched this to production, the only thing that would change is that we would get minified, optimized versions of our code bundles. Since we want to be able to actually dig through and debug, we don't want that right now.
  • --content-base docs/: This flag tells the server to use the docs directory as the root of our application. This is appropriate as we'll be serving our production application from this directory.
  • --open: This one very simply tells the server to actually open a Chrome browser window to our server location once it's running. This is why a page automatically opens for you when you run npm start.

See! Not so bad.


Commit your work!

git add . && git commit -m "Webpack configured"


Fireworks, here we come!

Install the fireworks-canvas node module with npm: npm install --save fireworks-canvas.

Take a peek at the documentation to see how we use this module.

Try to get the fireworks going on your own.


Wrapping up

Here's a minimal implementation:

src/js/fireworks.js

import Fireworks from "fireworks-canvas"

export default () => {
  const app = document.getElementById("app")
  const fireworks = new Fireworks(app)
  fireworks.start()
}

Don't forget to commit everything!

git add . && git commit -m "MVP"

Why not host it on GitHub Pages?

GitHub offers a really simple way to host static websites directly from your Git repos. We only need to make a few changes to get this working.

Update your package.jsons scripts to:

{
  // ...
  "scripts": {
    "build": "webpack --mode production --content-base docs/ --output-path docs/",
    "start": "webpack-cli serve --mode development --content-base docs/ --open Chrome"
  }
  // ...
}

GitHub Pages will expect to see our static assets inside a docs folder, so we updated these scripts so that Webpack will put it's build output there instead.

Create a production build and commit it:

npm run build && git add . && git commit -m "Production build." && git push

Navigate to your remote repo on GitHub and open the Repository's settings. Towards the bottom of the page you'll see a GitHub Pages section.

Set the Source to master-branch/docs Folder.

Save, scroll back down and find the URL. It can take a couple minutes for your page to publish, so be patient, but after that your site should be available at the specified URL.

Stretch Goals:

  • Add the ability to Start and Stop the show.
  • Add the ability to Fire One.
  • Make it so that you can resize the browser and the fireworks update.

Resources

Webpack is a super powerful bundler that actually comes with a lot more capability. It's entry point is low though since we can make a project without having to include any external dependencies. I would encourage you to look more into what Webpack is capable of with the following material: