This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-12-02
Channels
- # adventofcode (97)
- # announcements (11)
- # babashka (18)
- # beginners (34)
- # biff (5)
- # cljfx (5)
- # clojure-europe (4)
- # clojure-uk (2)
- # clojurescript (7)
- # community-development (2)
- # hyperfiddle (8)
- # introduce-yourself (1)
- # music (2)
- # off-topic (2)
- # polylith (3)
- # practicalli (1)
- # releases (1)
- # shadow-cljs (28)
- # squint (1)
Hi, @thheller. I was playing with running Babel in macro-expansion time (more info here: https://clojurians.slack.com/archives/C06MAR553/p1701480380276509) and while things worked, I wanted to try a different approach - so I tried to use Shadow-CLJS hooks (specifically, the {:shadow.build/stage :compile-finish}
hook) to capture what Shadow compiled, run Babel on it, then emit the already transformed JS. My test case was to emit JSX with (js* "<div>Hello</div>")
and send it to Babel using the Solid.JS preset.
So... it worked - kinda. When I opened the browser (I was using the ESM target) I could see the div, and the files were correct and everything; the problem was when I saved the file again- it tried to send the JSX, before Babel, version to the browser, so I could not hot-reload stuff. So I've been thinking if it's possible to send to the browser, in the hot-reload workflow, the version I emitted on my hook - either by adding another hook on the line, or by some other trick. Any ideas, or even, is this desirable in any way?
whats the potential gain here? I mean solid is never gonna map quite right to CLJS, so you are just going to fight one footgun after the other?
Sure - the hook code is this one:
(defn babel-compile
{:shadow.build/stage :compile-finish}
[build-state]
(update build-state :output
(fn [output]
(->> output
(map (fn [[k v]]
(if-let [babel (-> v :ns-info :meta :babble/config)]
[k (update v :js transform* babel)]
[k v])))
(into {})))))
Basically, I get the ns
metadata to see if I should run babel on it, then I run transform*
to transform the source - transform changed a lot, but in a nutshell is a node runtime (provided by Javet) that calls Babel with the shadow compile source code and returns a string with the transformed code
> whats the potential gain here? To explore if there's a way to run Babel in the "middle" of the process - basically, to compile ClojureScript to Javascript+JSX and run Babel to transform that to JS, and that be the final result. Maybe even give some support for this ticket: https://github.com/thheller/shadow-cljs/issues/190
And I'm sure I'll have other footguns, just thinking if there's a way around this - I really wish there was a better way for CLJS to integrate better in the JS world, even though I am well aware how crazy things are with bundlers and compilers and everything else.
BTW, the code that the hook was being applied to is:
(ns babble.core-test
{:babble/config {:presets ["babel-preset-solid"]}})
(js* "<div>Hello, world</div>")
here I'm trying to get away from the JS world as much as possible and you want to get right back in 😛
hook seems like it should be fine, although you'd probably want to maintain some flag to not run babel when it already ran
:compile-finish
is compiled every cycle, so :js
will contain the already converted code unless the file itself was recompiled
btw I have no interest in adding babel support in shadow-cljs itself, so don't plan on working on any PRs or so on that front
happy to add stuff so you can do it in hooks, but no chance of direct integration. babel is an absolute nightmare to work with and maintain
I also don't quite see the point. I mean the transformations done by the JSX translation things are probably not rocket science and could easily be done in a macro, without any babel. just pure CLJ.
Ok, I imagined you didn't want to add Babel support - I'm completely fine with it, and I'm glad you consider adding stuff on hooks so that I can try something 👍. I'll try to do stuff in hooks, make a branch, and if things don't work out I'll update here
BTW, the point is that some tools transform JSX in a different way. Solid claims that it detects "static things" and "dynamic things" in JSX and compile everything to optimize the end Javascript code. These claims seems to be backed by third-part benchmarks too, so I'm curious if I can, let's say, have my (solid) cake and eat it too...
FWIW these benchmark numbers are with extremely basic optimizations https://github.com/thheller/js-framework-shadow-grove#light
I'm sure with some time invested it is possible to be even more on par with solid, with just pure CLJS
so I never saw the draw to adopt the JS-framework-of-the-day if we can do things just as well in CLJS ourselves 😛