I’m reworking the “Launcher” for
shadow-cljs and would be interested to hear what people think about my plans. I’m undecided on which way to go since there are several options each with their own pros/cons.
The launcher is used to download maven
:dependencies and starting the JVM with the proper classpath.
shadow-cljs basically consists of 3 separate parts:
- Clojure Library doing all the work
- The Standalone Launcher
npmpackage providing the
shadow-cljs supports 3 different launchers currently:
:deps+deps.edn and its standalone version.
tools.deps are not affected by this work and will stay exactly the same as they are now. You can even skip 2,3 entirely and just use the Clojure Library directly.
Previously the launcher was distributed via the shadow-cljs-jar npm package which the
shadow-cljs npm package just depended on. This meant that the standalone launcher was always downloaded even when actually using the other launchers.
Due to the way
npm operates the launcher would be downloaded for each project separately although it rarely changes and each project could use a shared version instead. 5 projects currently means 5 copies which is not the end of the world but could be improved.
The launcher was very limited: download dependencies and build a classpath. This is exactly the same way
lein operate. A standalone “uberjar” is used to complete that job and then a secondary JVM is launched to run the actual application. This works well but means that sometimes 2 JVMs are started. I also want to get to the point where
:dependencies can be added dynamically without restart which would require duplicated work in the Clojure Library + Launcher.
Keep everything the way it is.
shadow-cljs JS script to download the launcher independently from
npm. The launcher could be distributed via Github or so and shared between projects. It would only be downloaded when required, meaning
tools.deps users wouldn’t. This is also how
lein work basically.
Plan B + make the launcher a bit smarter to enable dynamic classpath additions and such.
shadow-cljs with the launcher. Saves the first initial download step, can do more optimizations for startup. Could investigate GraalVM native-image for nearly instant startup. Downside is that
shadow-cljs has far more frequent releases than the launcher. So “upgrading” would mean a larger download.
Actually create a completely standalone executable. One that you could double-click to launch and even get an actual GUI application at some point. Terminal is so 20 years ago. I think we can do better and I personally want that. CLI version will stay for CI and such but developer experience would be much improved if you could click a thing instead of running 3 separate terminals or so. IMHO,YMMV. For those that remember there used to be cuttle for CLJS and the Vue world has a pretty badass UI too. There is also guppy which is fairly new but looks interesting too.
The final Question
I’m currently undecided whether to go with C or D and want the Bonus Level
Which would you prefer: A more frequent larger download (~40MB) or a less frequent ~20MB download plus a separate more frequent ~20MB download? Am I overthinking this?
If you use
deps nothing changes for you but you’ll miss out on some of the AOT optimizations (4sec startup vs 9sec startup).
shadow-cljs will stay a Clojure Library primarily and this is just about finding the most optimal way to launch it.
- I use
leinand don’t care
- I use
tools.depsand don’t care
- Plan A - screw lein/tools.deps users
- Plan B - do what is known to work
- Plan C - optimize my bandwidth
- Plan D - I got the bandwidth
- Gimme the GUI already!