How I optimized Carousel for EditorJS 2x in size.
Tags: babel, webpack, esbuild, esm
Published: 2024-03-29 16:00:00

---
title: How I optimized Carousel for EditorJS 2x in size.
published: true
description: Described process of optimizing rather old open-source component, removing unneeded polyfills.
tags: babel, webpack, esbuild, esm
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h3zg36k6fr13nu0mata1.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-03-29 16:00 +0000
---

## 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](https://editorjs.io/) and during checking its [Awesome List](https://github.com/editor-js/awesome-editorjs) there were several carousel plugins and I stopped on [this](https://github.com/mr8bit/carousel-editorjs/).

![carousel look like this](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/74nebz2sub3pmsk6yrhc.png)

* _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 :grimacing:

In current version there were buttons to move order, but for some reason instead of "delete" :negative_squared_cross_mark: button as on screenshot it was blank, and also inside *toolbox* it was also blank.

![initial view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qadcsvhmyog5m3xe6z5u.png)

_No other way_: I need to _fork_, _clone_ it, :wrench: 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*.
```awk
    Asset      Size
bundle.js  35.4 KiB
```

After fixes size become even smaller:
```awk
    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/](https://beautifier.io/) you will see:

![strange stuff inside](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/633btzvuemqhohp9dipc.png)

What the hell `process.chdir` doing inside browser bundle?

## What bundle consists of?

So as always we add `webpack-bundle-analyzer`:
```json
"webpack": "^4.29.5",
"webpack-bundle-analyzer": "^4.10.1",
"webpack-cli": "^3.2.3"
```

Adding `--profile` flag to build command:
```json
"build": "webpack --mode production --profile",
```

Bundle inside looks like this:
![Initial build size 35.11k](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkhk7qlpva7qqhg2jxrc.jpg)

What we have here, lets show it in form of json:

```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 no `target` or `browserlist` left. Not sure if author wanted to support `IE11`. Even when this component was created in 2021, `es6` was on 97% adoption through browsers.
* `styles` is interesting, we have `index.css` of *3.64k* and delivery mechanism that costs *5.4k*, which more than css itself :smiley_cat:. 
* `ajax` is a blackbox for us for now, its another `UMD` bundle, need to build it separately, and check what inside.

## Remove babel and styles

Remove `babel` from `webpack.config.js`
![remove babel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/njgodz5c5acezhnmfrwu.png)

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:
```json
"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:
```js
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:
```awk
    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:

![ajax dist initially](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/po0g4jim3aqnjy0v6iwt.png)

What we really need is in red border.

```awk
  Asset      Size  
main.js  14.3 KiB  
```

```json
{
  "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 promise](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mel3m8yrgi39l3e287sh.png)

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`:

```awk
  Asset      Size 
main.js  7.09 KiB 
```

After removing `babel` for es6 classes emulation :alien:

```awk
  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:

```awk
    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_.

![(webpack)/buildin/global.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9io6j68azp09rfkk74jd.png)

Why use it, if we have such a great thing like `ESM` :smiley:.

## 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"` in `package.json`
* rewrite fully `webpack.config.js`

![initial vs module](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wt1t6pp42ofh921o5n5.png)

Result is nice :fire: and one more useless kilobyte gone.

```awk
  Asset      Size 
main.js  5.06 KiB 
```

Lets see final result :tada:: *16.9k* vs *35.1k*

```awk
    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 :books:, even when minified
* Can be formatted :straight_ruler: by vscode
* It is a pleasure to feel full control of it

Thanks for reading. :metal:
Open to collaboration. :wave:
If you have full-time or part-time projects. 
Usually work as full-stack: `.net` + `js`. 
Write me :mailbox:: [igor.golodnitsky@gmail.com](mailto:igor.golodnitsky@gmail.com)