Woke up and UltimateExpress got some more attention while I was asleep. Someone asked me to add a table with comparison to other frameworks, and gave me link to bun-http-framework-benchmark.
I started setting it up to add UExpress, and noticed that in pull requests there was already PR to add it! But… it had ETag enabled and needlessly set middleware to all routes… With that awful code config, UExpress was performing absolutely terrible, so I made a comment telling what to change.
But performance was still quite bad even with these changes, so I started to look what could be improved. Benchmark itself consists of 3 tests:
- ping (just a simple response)
- params + query
- post with json body
I’ve decided to check Elysia.js codefor possible speed improvements I could do, and apparently they use fast-queryparser library. Unfortunately, it doesn’t support array queries like qs
does, but I could work around that by checking if string includes [
or .
characters, and speed increased by a considerable amount.
Then I started to look at what could be done with params, and I realized that routes with params can actually be optimized the same way other routes are! But ofc the problem here wasn’t in routing itself, but in parsing of params. At the moment it was using regex for that. I implemented optimization of param routes, and with that I could use uWS native param parser, so I could skip parsing routes with params. Another quite large speed improvement.
After these changes, params+query test basically matched speed of ping test, meaning there’s barely any work being done anymore. But JSON test was considerably slower than other ones, and I realized that I’m using Express’s body-parser library for that, which uses Stream to read content of body. Instead of doing that, I implemented my own JSON parsing middleware that reads directly from uWS (unless reading already started, which can happen with async middlewares). And that increased speed from 30k to 40k req/sec for JSON test!
I had to make these optimizations quickly, before PR was merged. Other body parsing middlewares can be improved the same way too, so I’ll work on that.
Tomorrow, university session starts. They became quite lazy this year, with no classes at all scheduled for this session… Dean just told me to email professors myself.
… Now it’s 3 AM and I finished coding other middlewares, and all benefitted from the rewrite. There has been a bug ever since I switched Nekoweb to uExpress that made assets not update. For some reason they got cached in Cloudflare. I finally figured out why it was happening, apparently Express does support If-Modified-Since, while I didn’t support it properly. My version was not sending headers, including ETag and more importantly Cache-Control, which made Cloudflare default to normal cache time. Also that bad version got merged, so I quickly made a PR fixing their code and it got merged too, phew!
Now it’s all fixed, and everything is more performant. I’m satisfied.