Ain’t it strange how all those processes that were supposed to make us more “agile” are doing exactly the opposite? It is quite obvious that contraining workers in creative fields is hindering innovation.
That’s why developers that are always sprinting in the never-ending marathon might fail to grab even the low hanging fruits, let alone truly innovate. On this note, it took me a vacation to later notice an improvement which required an npm package and a single line of code changed, that ended up speeding our CI/CD by 50-75%.
Do yourself a favour and use a fast bundler (if you decide to use one in the first place)
This project I was working on was a so called cloud native solution with all the bells and whistles, that I held in high regard (in the first few months at least, before realizing it was my first big ball of mud). My team was responsible for several Lambda microservices, all written in NodeJs with the infrastructure and deployment handled by the serverless framework.
Now, unsurprisingly, every time a new service was being created, we were copy pasting the same random “template” written by some colleague 1 or 2 years ago, instead on relying on the init CLI’s. And that’s how every squad that was doing services using NodeJs lambdas ended up with the serverless-webpack plugin.
Since we had the classic three environments setup and our services were reasonable in size we were testing our changes by constantly deploying to dev (also, the coupling made local testing too challenging to be worthwhile at the time). This took some time, as
serverless deploy
was bundling our code with webpack every single time. It was even worse in CI. Our services grew, and my 5 years old Dell started fainting and eventually crashing as it was running out of RAM.
One such crash occured just a few days after returning from vacation, and that’s when I started looking for a solution. Got into the serverless.yml file and saw the webpack plugin right away. Just a few months back, Bun was released, and that’s when I learned about the existence of performant tooling for JS, such as esbuild (written in Go, btw).
Intuitively, if there was a serverless-webpack plugin, there had to be a serverless-esbuild one, right? And there was. Uninstall that, install this, change this line:
plugins:
- - serverless-webpack
+ - serverless-esbuild
And boom: local deployment times halved, negligible RAM consumption (fan’s not even spinning, baby) and less time in CI by 50-75%. Some rough numbers:
action | serverless-webpack | serverless-esbuild |
---|---|---|
local serverless package on our biggest project | 60s | 1s |
our biggest microservice in CI (full CI) | 8min | 4min |
biggest microservice from fellow squads (70-80 Lambdas +) (full CI) | 30min | 10min |
And another one, feat vite
My next target was the web app. This was a pretty hefty React app with some unreasonable CI/CD times and npm start times. I simply couldn’t stand having to wait for npm start to show something in the browser for 3m46s! (on my machine). Vite was arguably the easiest way to speed this up as it uses esbuild and Rollup behind the curtains (I tried raw dogging esbuild in the beginning but it felt too complicated).
Switching react-scripts start and react-scripts build with their vite counterparts is quite easy and I’m not going to get through it here, as there’s plenty of good tutorials out there to get you started. To my surprise, half of those insane 3m46s were because of scss compilation (we were using kendo for our tables and were importing some default scss styles). The relatively fast pace at which css advancements are made to bring new features to the browser makes me even happier knowing how slow sass compilation can be. Luck stroke me again though, as there was an esbuild plugin to handle sass compilation. Results after 3-4 hours of work:
action | react-scripts | vite |
---|---|---|
npm start | 3m46s | 14s |
npm run build | 5m | 30s |
Not too shabby.
Switching the test script from using Jest to vitest is another story though. This was much more painful as it required more work, fine tuning of the vitest config file, and banging my head against the wall. I didn’t really know the testing infrastructure on this project as I rarely do frontend, but I sure as hell do now. This took way more time than replacing the other scripts and in the end it wasn’t even faster than Jest, while having ocasional OOM CI runner deaths. Well, at least I learned a lot about vitest, having to read their docs almost in entirety and several of their github issues.
Final thoughts
Unless going the no build way, which I must admit I’m itching to try out, you are pretty much always going to use tooling to build your JS projects. Make sure to use tools written in really fast languages (looking at Go, Rust and lately Zig) to save CI money, time and most importantly, ensure developers don’t lose their joy. And yeah, take it easy sprinting, as this was and always will be a marathon.