Why are we doing this?
I am supporting a project where lawyers, advisors can publish articles or news, to get more attention and clients. Initially it was made through TinyMCE, but they wanted not just HTML, but also a way of showing many pictures with interactions.
I was seeking UI editor like Medium, and I guess best what I found was EditorJS and during checking its Awesome List there were several carousel plugins and I stopped on this.
- The pros: it had already generated bundle with it, which I could easily add to my project
- The cons: there were no demo page with it, it was only a screenshot, which later happens already outdated 😬
In current version there were buttons to move order, but for some reason instead of "delete" ❎ button as on screenshot it was blank, and also inside toolbox it was also blank.
No other way: I need to fork, clone it, 🔧 bugs, build myself. About fixing part maybe will write separate post, but I would like to share process of optimizing bundle, because it looked a bit heavy for such kind of code.
What with bundle size?
Let's see initial size of build we have 35.4k.
Asset Size
bundle.js 35.4 KiB
After fixes size become even smaller:
Asset Size
bundle.js 35.1 KiB
Even without tools it looked a bit weird, all files in source without minification costs us 27k, its something not needed inside, and if you unpack it with something like https://beautifier.io/ you will see:
What the hell process.chdir
doing inside browser bundle?
What bundle consists of?
So as always we add webpack-bundle-analyzer
:
"webpack": "^4.29.5",
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^3.2.3"
Adding --profile
flag to build command:
"build": "webpack --mode production --profile",
Bundle inside looks like this:
What we have here, lets show it in form of json:
{
"src": {
"index.js + uploader.js": "8.64k",
"index.css": "3.64k",
"button-icon.svg": "439b",
"all": "13kb",
},
"styles": {
"style-loader": "4.67k",
"css-loader": "808b"
},
"babel": "1.42k",
"ajax": "14kb"
}
-
src
is fine, its meat we need to deliver. -
babel
hard to say, why it was used. There is notarget
orbrowserlist
left. Not sure if author wanted to supportIE11
. Even when this component was created in 2021,es6
was on 97% adoption through browsers. -
styles
is interesting, we haveindex.css
of 3.64k and delivery mechanism that costs 5.4k, which more than css itself 😺. -
ajax
is a blackbox for us for now, its anotherUMD
bundle, need to build it separately, and check what inside.
Remove babel and styles
Remove babel
from webpack.config.js
Remove styles
is trickier. In fact what we could do, is just remove it from bundle, to separate file. We could put it as it is, but author decided to use a bit of scss-stuff, and we might want to leave it. For webpack4 I didn't find a solution for this, so I updated it to webpack5.
Packages now looks like this:
"mini-css-extract-plugin": "^2.8.1",
"svg-inline-loader": "^0.8.0",
"webpack": "^5.91.0",
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^3.2.3"
Adding MiniCssExtractPlugin:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
module.exports = {
plugins: [
...
new MiniCssExtractPlugin({
filename: 'bundle.css',
})
],
...
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
require('postcss-nested-ancestors'),
require('postcss-nested')
]
}
}
]
},
Let's build it, and see what we get:
Asset Size
bundle.js 22.8 KiB
bundle.css 3.1 KiB
As you see bundle.css
is even smaller than css inside bundle, this is because to be in js, css need a bit of escaping and module instantiation. After we remove utils for loading, now instead of 9k we have 3.1k.
Intermediate result: 25.9k vs 35.1k
Checking ajax library
Library used here: https://github.com/codex-team/ajax. As stated in readme it is Just another AJAX requests helper
. Main reason why it was used, I guess a simple helper for submitFiles(). Lets see what dist
have inside:
What we really need is in red border.
Asset Size
main.js 14.3 KiB
{
"src": {
"index.js": "3.74kb",
"utils.js": "1.74kb",
"all": "5.5kb",
},
"http-build-query": "569b",
"promise-polyfill": "7kb"
}
Again this library is from 2020.
Support of Promise in major browsers goes from 2014. Yes we supported IE11
for many years, and I guess in 2018 many companies let it go. Problem here that polyfill always here, npm distribute this bundle, and no way to tell, if you need it for your build or not.
After removing promise-polyfill
:
Asset Size
main.js 7.09 KiB
After removing babel
for es6 classes emulation 👽
Asset Size
main.js 6.09 KiB
If we copy this main.js
to our carousel project as ajax.js
, and build it, we will get:
Asset Size
bundle.js 14.7 KiB
bundle.css 3.1 KiB
It's already much better, but what I don't like about this, is that ajax.js
is still UMD
style webpack bundle, that means array of modules inside connected by something called (webpack)/buildin/global.js
which takes 472b.
Why use it, if we have such a great thing like ESM
😃.
Enabling ESM for ajax project
I didn't follow long story of dealing with ESM inside webpack during last 5 years, but looks like now it works good, and in fact my build from webpack was even more compact, than I could make from esbuild
.
To enable it you just need to:
- upgrade webpack to latest 5, for me its
^5.91.0
- change
"type": "module"
inpackage.json
- rewrite fully
webpack.config.js
Result is nice 🔥 and one more useless kilobyte gone.
Asset Size
main.js 5.06 KiB
Lets see final result 🎉: 16.9k vs 35.1k
Asset Size
bundle.js 13.8 KiB
bundle.css 3.1 KiB
Resume
- Don't treat bundles as binary, it is JavaScript
- JavaScript is a high-level language
- It is easily readable 📚, even when minified
- Can be formatted 📏 by vscode
- It is a pleasure to feel full control of it
Thanks for reading. 🤘
Open to collaboration. 👋
If you have full-time or part-time projects.
Usually work as full-stack: .net
+ js
.
Write me 📫: igor.golodnitsky@gmail.com
Top comments (0)