Launcher Rework - Lessons learned


TL;DR: I reverted all the launcher changes I did. 2.6.0 now behaves as 2.4.33 and previous releases again.

As described in my previous post I intended to rewrite the shadow-cljs launcher to get rid of some long standing “issues” and gaining access to some new features such as updating :dependencies without restarting.

As it turns out however I traded one set of problems for another set of problems which were actually way worse and much harder to solve.

Turns out that dynamically loading dependencies is really hard when working with Java deps. It all worked fine when using pure ClojureScript deps with basically only .cljs files and maybe a .cljc or .clj macro file sprinkled in there. When you however add a Clojure library that had some Java dependencies things started breaking quickly with weird java.lang.NoClassDefFoundError although they were clearly on the classpath. Problem of course was my naive handling of ClassLoaders but when switching to a more sophisticated approach that isolated the ClassLoaders properly I basically lost all the benefits I was hoping to gain. Startup time got worse too.

I also tried switching to the tools.deps.alpha library over pomegranate. Both resolve maven dependencies but do so slightly differently so it sometimes broke builds that were working fine previously. Dealing with that while also dealing the classloader issues made things rather annoying.

CI also got way harder since it now just wasn’t just about npm install shadow-cljs but also properly caching the ~/.shadow-cljs folder so the launcher didn’t have to be downloaded for each CI run.

I will keep exploring the options but I decided to revert the changes for now since leaving a less reliable launcher online didn’t help anyone. For now things are back to the way they were before.