If you're in the JS ecosystem, at some point you'll face this duo: esm
& cjs
...
are umd
& amd
still a thing?
and you'll be like «what is exactly es
referencing here?» «do i need es2020
or esnext
?»
and if you have an internal library —especially if it’s frontend related–someone on the team will eventually ask:
«Wait, how are the assets/CSS being bundled exactly?»
that's The JS Bundle Wars.
It's a war.
isn't pretty.
isn't easy.
BUT it's interesting as f*
this topic could lead to a complete book (Have I mentioned I dream about writing a dev book and selling it on Amazon?)
Today, I’m just kicking things off...as every complex topic should, with a simple hello world.
I’m not even using React yet, let’s start with a plain Vanilla JS hello world page.
This is the repo im playing with: js-bundle-war
the code is super simple.
We just need an import
, an index.html
and the <script type="module">
tag.
index.html
is importing a ES module: main.js
Which in turn imports other ES modules: app.js
so far, so good.
I'm using Vite as bundler. I don't want to get back to webpack.
so , if we create a package.json and define how to build this:
"devDependencies": {
"vite": "6.3.5"
},
...
"scripts": {
"build": "vite build "
}
leaving the default vite.config
(no config file at all), its' going to bundle this:
dist
├── assets
│  ├── index-16Psp_lK.js
│  └── index-CrYBktwj.css
├── index.html
└── vite.svg
which is the real thing. I mean, this is the actual code read/rendered by the browser.
let's open the bundled js shall we?
I highlight:
An initial IIFE to polyfill
modulepreload
: this is a Vite-specific detail. Vite usesmodulepreload
links in the HTML to prefetch JS modules for better performance.
BUT some browsers might not supportmodulepreload
, so Vite includes a polyfill to make sure the assets are still fetched properly.-
SOME SVGs are inlined in the build, while others are referenced as external modules.
(The screenshot was tweaked in this part — let’s take a clearer one to explain it better.)
The key difference is where we did place the asset:- if it’s under /public, it’s served as-is;
- if it’s inside src/, it gets bundled as part of the code.
Our components, minified.
And finally, the last lines: our
main.js
file.
So, we're building modern ES modules, the bundling process takes our clean, modular code (what we wrote) and outputs the real .js
file... which isn't meant to be read by humans but is executed by browsers.
This bundling process handles dependencies, minification, and assets.
...but
why are we even doing this? I mean, ok this is how we bundle , this is the output that is consumed by the browser... why? 🤔
That’s it for today — but this is just the intro, see you in the next article of the series.
Thanks for reading.
Top comments (0)