What’s the advantage with webpack?

Webpack feels like this huge and unnecessary thing that you just must learn and use if you wanna build a modern web app.

But why? why does even webpack exist? 

Why can we no longer just use script tags? 

<script src="/js/jquery.min.js"></script>
<script src="/js/someLib.min.js"></script>
<script src="/js/app.js"></script>

It’s simple and it works.

With webpack, it’s hours or even days of configuration before you are up and running with a new app. What’s the advantage with webpack and is it even worth it?

Webpack gives JavaScript a module system

A module system is essential to any programming language that is built for scale. All major languages have module systems built-in. Java has it. .NET has it. Even C++ has it.

JavaScript doesn’t have a module system built-in. 

But what is a module system and why do you need it?

To really understand how important a module system is, let’s look at how JavaScript works without webpack.

JavaScript before webpack

As I said, JavaScript doesn’t have a module system built-in. So how did we write large-scale apps before webpack? It was possible by using the global scope as a workaround for a module system.

All JavaScript you write ends up either in local scope or global scope

Any variable or function that you declare inside a function ends up in the local scope. Any variable or function that you declare outside of a function ends up in the global scope. 

You can think of the global scope as a regular Javascript object that every part of your whole JavaScript app has access to at any point at any time. In the browser, the global scope is the window variable.

Every time you define a variable it’s put on window.

<script>
var hello; //this is actually window.hello
</script>

And every time you define a function it’s put on window.

<script>
function myFunction() { // this is actually window.myFunction
}
</script>

Before webpack, this global scope acted as a module management system. There was no built-in syntax for writing modules so devs found their own way. A common way was to create a closure.

var Module = (function() {
 // some code for your module
}());

All of the modules that you had in your app was put on the global scope. Also, all libraries you included from script tags was also put on the global scope. jQuery puts itself as a global variable called $ , lodash in _ , etc. 

The global scope would look something like this for a trivial app:

window = {
  $: /* implementation */,
  _: /* implementation */,
  Module: /* implementation */,
  AnotherModule: /* implementation */
}

The problem with the global scope as a module management system

When the app grows, you quickly start to lose control over what is on the global scope. The risk for overwriting is just getting bigger and bigger.

Especially when you start using more and more dependencies. 

Let’s say you want to start using a slideshow library, and that library requires underscore.js as a dependency. Now you have to import underscore.js too. When using script tags as dependency management you have to manually add script tags for each dependency that your dependency has, like this:

<script src="/js/slideshow.min.js"></script>
<script src="/js/underscore.min.js"></script>

Now underscore is automatically put on window._

For your next feature, you need a date picker and you find an awesome datepicker library. This date picker has a dependency to lodash. But lodash ALSO is put on window._, just like underscore.js. 

<script src="/js/datepicker.min.js"></script>
<script src="/js/lodash.min.js"></script> // OVERWRITE UNDERSCORE

Now lodash would overwrite the window._ that previously was used by underscore.js  You cannot use both the datepicker and the slideshow library at the same time. That’s a major limitation. 

This might sound like an edge case but I can assure you it is not. If you are writing any apps that are bigger than 40hours of work then you will definitely run into problems like this.

Webpack gives you a module system

Webpack solves this problem by supporting a modern module system that is based on the ES6 standard (it actually support many module systems standards, but the most modern is ES6). 

With this module system, every file you create is automatically its own module with its own scope.

MyModule.js:

var test=”hello world”; // this is module scope. NOT on window.

All variables you declare in a module is put in module scope by default, NOT global scope. The problem with overwriting global variables disappear automagically. You never have to worry about it again. If you for some specific reason want to put something on the global scope, you still can by accessing it explicitly, like this: window.myVariable.

You can easily export functions that should be public for that module with export keyword:

export function helloWorld() { return “hi there”; } // this is how you can export a function 

The variables you export are not put on the global scope either. They are handled in some smart way by webpack that doesn’t give a risk for overwrites.

And you can import functions from your own modules and external dependencies with the import keyword. 

import { helloWorld } from "MyModule"
import slideshow from “slidshow”
import underscore from “underscore”

The problem that we described earlier with dependencies having different transient dependencies (lodash and underscore) is solved automatically. You never have to worry about what dependencies your dependencies have again.

This is a module system you expect of a modern language.