https://github.com/facebook/react/pull/18449 not sure if relevant, React seems to have switched to Closure compiler for compiling down to ES5
relevant for people who are militant about their dependencies (which is generally a good idea)
but not that meaningful for typical users prioritizing getting stuff done
it doesn’t look like they ship closure-y source so it’s not like we can treat it as non-external, right?
Not true, React is pretty Closure compatible
really all JS that doesn't do string based programming is already compatible
but lots of libraries do unnecessary dynamic stuff
so as long as people grab libraries willy nilly - then you're stuck w/ Webpack or whatever build mudball de jour
that said given how we've done things where we do have most of the stuff in place to DCE node_modules via Closure
so it doesn't matter if you use Webpack or whatever today
tomorrow you can use Closure
I haven't looked at the most recent React releases, but at some point React created bunch of methods and properties dynamically. Even if you don't use the methods from your own code, React uses ["foo"]
when declaring them dynamically and .foo
to refer to the same methods in other places, so externs are required to optimize React code. (Not sure if this is relevent for this discussion, just note about React being Closure compatible).
@juhoteperi yeah that was years ago at this point - I know that FB has been using Closure to optimize their own React usage for a couple of years now
I don't know if that forced them to solve that annoyance
but I'd be surprised
Yeah, the last related fixes to Cljsjs extern file where 3 and 2 years ago
But these problems weren't also very obvious to see, like 95% of Reagent tests passed and then a few test cases where broken due to these problems.
iirc, React team reached to Closure people at some point to get a couple of switches in the compiler that makes advanced mode less aggressive specifically for React
I think I addressed all the reported externs inference issues - let me know if I missed anything
if you all some low hanging fruit issues you'd like to see added to the next release let me know
Maybe these - https://clojure.atlassian.net/browse/CLJS-3195 - https://clojure.atlassian.net/browse/CLJS-3086 - https://clojure.atlassian.net/browse/CLJS-2863 These are small - https://clojure.atlassian.net/browse/CLJS-3106 - https://clojure.atlassian.net/browse/CLJS-3105 - https://clojure.atlassian.net/browse/CLJS-3102
3195, not now - 3086 approved
2863 ok
the others are too minor for now
here are my current thoughts about the coming changes - https://gist.github.com/swannodette/919ef8fb51e7ee91b5f3ab643c4b3e55
feedback welcome, it's pretty simple - and I have another project that more or less confirms that it works
I can’t quite tell exactly what the motivation is yet. it sounds like it would be really useful for people who want to consume their CLJS code in storybook, or use with react-native. is that close to the mark?
I'd be interested to see a working example if you do find a way to use Storybook with CLJS code.
@lilactown it removes nearly all the steps (some error prone) for people who want to use some random lib
but more importantly it provides a portable way to create clojurescript libs that depend on node_modules
that's not really possible today because there's no standard way to do it
the state of the art for creating CLJS libs that use JS deps is CLJSJS
and that's also error prone, requires maintenance
I see. agreed about cljsjs
I didn’t understand anything in that gist to be about clojurescript libraries. the bulk of the content seems to be about a :bundle
target? I’m not sure yet how that rolls into libs
I suspect this already works for shadow-cljs but shadow-cljs isn't the standard tool chain so it's not really much of a win - not portable
@lilactown because we don't need to talk about anything else other than :bundle
:npm-deps
already exists and works
it was always a la carte
i.e. doesn't directly imply Closure, :nodejs
target avoids that
hmm. I guess maybe I’m out of my depth? I don’t understand yet the link between a :bundle
target that (by the gist)
> any tool that handles Node.js `require` can build ClojureScript - webpack, metro, etc.
to the problem of libs that depend on node_modules or using some random lib.
I’m looking at this from several perspectives:
• I’m a ClojureScript library author whose most popular libs depend on node_modules
. How does this effect my libraries?
• I’m an application developer who uses many node_modules
libs and uses many ClojureScript libraries that wrap node_modules
. How does this effect my toolchain and dev experience?
perhaps, if I’m inferring right, it means that instead of: webpack creates a big ball of JS that then GCC needs a bunch of externs / must export to the global context…
it would go the other way: we would emit a bundle of CLJS code with holes, that expects the node_modules
deps to be require(…)
able and then feed that into webpack so that it can resolve the require
s to node_modules
and have webpack emit our final bundle
I'm a ClojureScript library author whose most popular libs depend on node_modules. How does this effect my libraries?
this category does not exist
I'm an application developer who uses many node_modules libs and uses many ClojureScript libraries that wrap node_modules. How does this effect my toolchain and dev experience?
fewer steps, less boilerplate when working the standard compiler
@lilactown right but nothing I said talks about webpack specifically - in fact not interested in automating that part at all
users will start webpack, fastpack, metro or whatever
this is a good area for people to extend ClojureScript to make a shadow-cljs like experience + Figwheel or custom build setup or whatever
that makes sense!
there are aren't any portable ClojureScript libraries that depend on node_modules
today that don't require a lot of manual project-specific non-reproducible steps
if there were people wouldn't still be going to CLJSJS
that’s very true. I’ve had to maintain a separate branch of https://github.com/Lokeh/helix for cljs/figwheel-main, since the main branch implicitly relies on some behavior in shadow-cljs. it makes me feel bad, but it’s what I use both at work and for hobbies so it makes sense to spend most of my time with that
right that's basically the worse case scenario
yeah 😕
so this is about establishing a normal way to do this - shadow-cljs supporting the standard way along w/ it's own way shouldn't be hard
libraries authors shouldn't have to care which thing is going to build their thing
yeah, my case isn’t exactly related to node_modules
but it’s a sort of second-order effect
I also think that paving the pathway for consuming CLJS code from any JS bundler is a really good idea when it comes to incremental adoption. I was lucky with the projects I’ve been on the last few years, because we were able to start greenfield with CLJS.
trying a bottom-up incremental adoption of CLJS is a harder sell, since there’s so much boiler plate and additional stuff outside the happy path to get it running in an existing project using webpack or rollup or whatever the bundler du jour is
looking at your project, I would say that's directly related to the node_modules
problem 🙂
because you can't do it w/o shadow you have to describe a whole bunch of other steps
@lilactown w/ my proposal above the caveats about non-shadow tools just go away
the npm step is also not necessary
you can add src/deps.cljs
- the root of your classpath with those deps declared
then anyone can install the required npm deps, it doesn't matter what tool they finally end up using
I’ll do that now!
I still need to maintain a separate branch, unfortunately, due to some differences between how shadow and vanilla cljs handle JS in-project. that’s what I meant by second-order effects.
don’t need to get into that now, not relevant and I don’t completely understand it myself
huh, like Closure style JS in the project?
yeah
with shadow-cljs, I can use ES6 import/export but it doesn’t work as well with Closure-style JS (for some reason I haven’t spent the time to diagnose). with cljs, I couldn’t get the same ES6 import/export and require syntax to work, so I used goog.provide
huh - ok - honestly if you need some JS and you want it to always work for ClojureScript writing plain old Google Closure JS is probably wise - https://github.com/cognitect/transit-js/blob/master/src/com/cognitect/transit.js, is worth studying if you want to make it slightly less tedious. especially if you're not writing a lot JS it's not worth it to complicate the build for people by writing higher level JS
thanks, I’ll try and take another look at it soon
yeah it’s very minimal - the only reason I did it was to try and get better interop with native classes
https://github.com/Lokeh/helix/blob/master/src/helix/impl/class.js
trying to create classes the ES5 way doesn’t quite have the same behavior when the browser actually has native classes, so my hope was that I could rely on GCC to compile down the helper fn to either ES5 or actually use real classes depending on what the user wants to emit
this way from my cljs code I can just spew:
(helix.impl.class/createComponent
React.Component
#js {:constructor (fn [this] (set! (.-state this) #js {:foo "bar"}))
:render (fn [this] ,,,)}
nil)
@lilactown deps.cljs
should be able to help you here too, but this feature is not under heavy usage - I haven't had a need myself - so I can't say more than we test basic stuff and that appears to work
gotcha. I’ll try and play with it over the weekend.
while I have your attention about this, would you ever consider a patch that added a form that emitted a class
? 😅
it's worth thinking about since that is a well known pain point - the problem is that you would need to transpile the generated JS again with Closure if we're going to maintain the nice fact that ClojureScript only generates ES3
people keep talking about generating higher level JS but I really see only tradeoffs and most of them not in favor
@lilactown https://clojurescript.org/guides/javascript-modules, the beginning of this explains what you need to do
:foreign-libs [{:file "helix/impl/class.js" :module-type :es6}]
should theoretically work for you in your deps.cljs
I have reported issue for this some time ago https://clojure.atlassian.net/browse/CLJS-2399 and seems not resolved
if it doesn't - bug
yeah, a lot of higher level features have a relatively minimal impact on applications, but a considerable impact on project maintenance
from the perspective of a maintainer of CLJS, I mean
right, higher level features mean a more complicated pipeline, worse perf, etc.
(compiler perf, possibly runtime perf - ES3 is fast)
yep. tho it was interesting to see what people were talking about re: future async/await perf benefits
but that’s even a whole other level of effort, since AFAICT it would require so much work to make the way that CLJS handles things like do
work with the function-boundary behavior of async/await
class
is one that really bites me since more and more browsers are supporting it natively, and so interoping with them becomes more of a pain point.
it’s minimal in most application code, but the places you need it you need it and you can’t get away with an ES5 mock of a class
people keep talking about async/await perf but honestly I find such talk meh esp. in browser context
Node.js really isn't that interesting for server IMO if you're already doing Clojure anyway
so that's why not much has happened here - I just don't see much value
I think some work on codegen for core.async is all that it really needs - it's not that slow
absolutely
@lilactown re: class
I'm not against this if it's selective
i.e. if you use defclass
we'll generate ES6 and do a second pass w/ Closure on that file
it doesn't sound like a particularly hard project (I already have a Closure transpile in ClojureScript) - if you want to take a look at this be my guest
it's definitely an interop gaping hole
I’ll create a ticket and try and find time to take a look
in the ticket mention we need 2 parts - defclass
macro and compiler support
it’s not an immediate need - my Closure JS workaround seems to work OK - but it would be really nice to delete that code from my projects
sure, but is something people have asked for years
now that we have easy single file transpile support I don't really see any issues
it does affect source mapping but that can be done as separate enhancement ticket
how does this look? https://clojure.atlassian.net/browse/CLJS-3226