JavaScript Bundling ELI5
Let's see, so we know that we can include JavaScript scripts into a web page using the script
tag.
But what if we need to include a module script?
Wait, I think I need to explain first what a module script is!
Classic Script vs Module Script
Let's say we have a main.js
file containing the following code:
const squareArea = side => side * side;
const squarePerimeter = side => 4 * side;
const rectangleArea = (l, b) => l * b;
const rectanglePerimeter = (l, b) => 2 * (l + b);
const side = 2;
const len = 2, breadth = 2;
const shapes = ['square', 'rectangle'];
for (let shape of shapes) {
console.log(`${shape} Area and Perimeter`);
switch (shape) {
case 'square':
console.log(squareArea(side), squarePerimeter(side));
break;
case 'rectangle':
console.log(rectangleArea(len, breadth), rectanglePerimeter(len, breadth));
break;
}
}
This file can be called a classic script and can be added to our web page with script
tag.
But what if we decide to modularize and move each shape related logic into their corresponding files? Then we would have to import each file into the main file, like so:
// square.js
export const area = side => side * side;
export const perimeter = side => 4 * side;
// rectangle.js
export const area = (l,b) => l*b;
export const perimeter = (l,b) => 2*(l+b);
// main.js
import square from "./square";
import rectangle from "./rectangle";
// rest of the code in main...
Now we can call the files square.js
and rectangle.js
as modules.
Since the main file now imports modules, we can't add this file as a classic
script anymore, but rather only as a module script.
Including modules via <script>
We can include a module script via script
tag like so:
<script type="module" src="main.js"></script>
All module
scripts are defer
by default, which means
the script is fetched asynchronously while the HTML is parsed.
But the module is evaluated only right before the parsed HTML
is loaded as DOM content.
Limitation with <script type="module">
Although this is the modern browser age, it's quite possible that
there will be some backward compatibility issues with older browsers
which don't support the attribute value type="module"
, as it's relatively new.
Another known limitation is that unused code from the imported modules are not removed. They are imported, or let's say fetched as part of the module by the client over internet, even though they are useless.
When to bundle?
Ruby on Rails version 8 by default serves modules without any bundling or minification. DHH(creator of Rails) points out that even hey.com (opens in a new tab) doesn't use bundling, and thus it's unnecessary.
The limitation that we had previously mentioned, where even unused code is sent to the
browser on request, won't be an issue if let's say the number of modules is less than 100
.
Fetching these many number of modules in the browser would be fast enough that
the client doesn't notice any delay.
But, if the project is massive, where we are serving a lot of modules,
obviously greater than 100
, then we need to first
measure the performance of the web page and see how much of an impact this limitation has on it.
If it's significant, then bundling
is a very good option to consider!
Bundling in simple terms
What a bundler does is, it goes on a hunt for the dependencies,
which are modules required by the entry point JavaScript file.
It does this process in a depth-first-searching manner,
and then dumps all the required module functions/variables
into a single file(here it will the main.js
). This final product is the bundle
.
A bundler also bundles linked CSS and/or other objects necessary to make the web page run.
It makes use of loaders
to transform
the data into required JavaScript understandable
objects.
A bundler can also minify
the code, where it removes
unnecessary characters like whitespace, comments, semicolons etc.
Minification can help the webpage load faster.
It also does dead-code elimination where unused functions/variables etc are removed from the JavaScript delivered to client.
Bundling can be done by any of the available bundlers in the market, like say webpack, esbuild etc.
References
- https://v8.dev/features/modules (opens in a new tab)
- https://web.dev/articles/use-long-term-caching (opens in a new tab)
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules (opens in a new tab)
- https://hacks.mozilla.org/2015/08/es6-in-depth-modules/ (opens in a new tab)
- https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/ (opens in a new tab)
- https://youtu.be/iOYO2dKBYow?si=8FfsuFYP-OP0qgV3 (opens in a new tab)