I spoke about how #JavaScript module bundlers (those things like #Webpack) work under the hood yesterday at @coderful!
πHere's a short-ish summary:
1/
TLDR: Module bundlers like Webpack are not "complicated" or "magic" per se, the practice of module bundling is a complicated matter and you need to understand it before you can fully understand what a module bundler does and how to configure it correctly! π¦
2/
Why do we need module bundlers? Several reasons:
- Today we rely a lot on third-party software (e.g. modules from #npm)
- There are many different standards for JavaScript modules
- We want to write code in a way that is convenient and just "compile" it for the browser
3/
IIFE (Immediately Invoked Function Expression) is at the heart of many JavaScript module systems and module bundlers. To truly understand module bundlers, make sure you are comfortable with this concept
4/
Again, there are many module formats in JavaScript. Just to name a few:
A module bundler takes your code (generally written using Common.js or ESM) and converts it into one or more "static" assets that can be fully understood and executed in the browser environment.
6/
In order to do that, A module bundler generally performs 2 steps:
1. Dependency Resolution 2. Packing
7/
In the dependency resolution step, the bundler analyses the source code starting from your main file (the "entrypoint") and walks through all the require/import statements to build a representation of the application dependency graph
8/
Internally the dependency graph can be represented using a Map containing the normalized module path as key and a factory function to bootstrap the module as value. This data structure is generally called "Modules map"
9/
The packing operation (second step) takes the modules map as input and produces one or more JavaScript files that can be understood and executed by the browser.
10/
This step is the "magic" π§ββοΈ behind module bundlers!
The gist of it is that all the application code is already available in the modules map. We just need to wrap it in such a way that we can bootstrap all the modules in the right order.
11/
The first thing you should notice is that we are using an IIFE statement to pass the modules map into our "packed" application scope.
12/
Then we define a custom `require` function that allows us to require any module available in the modules map.
13/
Our custom `require` function does a few simple things:
1. It creates an empty `module` object that will be populated by the actual module factory function 2. Then the module factory function is invoked
πββοΈThis is an application of the service locator pattern
14/
Finally, the entire application is bootstrapped by requiring the entrypoint module, which in turn will require and initialize all the submodules in the right order (recursively).
β¨ THIS IS THE MAGIC OF MODULE BUNDLERS! β¨
15/
If you want to check out the slides (which contain a lot of material including a super quick intro to Webpack)...
How many times did you have to store settings (creds & other preferences)? Where do you save the conf file? Which format do you use? How do you load and update the file?
Conf takes care of all of this (and more!) with an extremely simple API
"Yo, why are #JavaScript and its ecosystem so messy?!" π‘
Well, I am glad you asked... Let me tell you a story! π€
π§΅π
For starting... #JavaScript was not designed to be the language that it is today!
JS was created in 1995 by @BrendanEich for Netscape, a web browser that was trying to come up with a language to make the web more interactive
@BrendanEich#JS wasn't related w/ #Java, so why did they call it Java-Script?! Duh! π³
Java was trendy! it was possible to build interactive sites by embedding Java apps in pages (applets). So it was mostly a #mktg move: "JS: the lightweight Java alternative" or something like that I guess
This is easy and it works! But the implementation is very specific to our struct.
The rest of the codebase doesn't really know that this type can be converted to a String and therefore you cannot build abstractions on top of this... π€¨
1οΈβ£Β You can't tell where a program is going to spend its time. Bottlenecks occur in surprising places, so don't try to second guess and put in a speed hack until you've proven that's where the bottleneck is.
2οΈβ£ Measure. Don't tune for speed until you've measured, and even then don't unless one part of the code overwhelms the rest.