cljs-dev

ClojureScript compiler & std lib dev, https://clojurescript.org/community/dev
orestis 2020-04-10T15:40:12.202900Z

https://github.com/facebook/react/pull/18449 not sure if relevant, React seems to have switched to Closure compiler for compiling down to ES5

dnolen 2020-04-10T15:48:35.204500Z

relevant for people who are militant about their dependencies (which is generally a good idea)

dnolen 2020-04-10T15:49:21.205300Z

but not that meaningful for typical users prioritizing getting stuff done

lilactown 2020-04-10T16:00:49.206500Z

it doesn’t look like they ship closure-y source so it’s not like we can treat it as non-external, right?

dnolen 2020-04-10T16:07:57.207100Z

Not true, React is pretty Closure compatible

dnolen 2020-04-10T16:08:21.207400Z

really all JS that doesn't do string based programming is already compatible

dnolen 2020-04-10T16:08:39.207800Z

but lots of libraries do unnecessary dynamic stuff

dnolen 2020-04-10T16:09:38.208600Z

so as long as people grab libraries willy nilly - then you're stuck w/ Webpack or whatever build mudball de jour

dnolen 2020-04-10T16:12:26.209500Z

that said given how we've done things where we do have most of the stuff in place to DCE node_modules via Closure

dnolen 2020-04-10T16:12:42.210Z

so it doesn't matter if you use Webpack or whatever today

dnolen 2020-04-10T16:12:50.210400Z

tomorrow you can use Closure

juhoteperi 2020-04-10T16:55:22.213500Z

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).

dnolen 2020-04-10T16:58:21.214300Z

@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

dnolen 2020-04-10T16:58:50.214800Z

I don't know if that forced them to solve that annoyance

dnolen 2020-04-10T16:58:53.215Z

but I'd be surprised

juhoteperi 2020-04-10T16:59:15.215600Z

Yeah, the last related fixes to Cljsjs extern file where 3 and 2 years ago

juhoteperi 2020-04-10T17:01:05.216700Z

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.

2020-04-10T18:32:10.219500Z

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

dnolen 2020-04-10T18:36:25.220200Z

I think I addressed all the reported externs inference issues - let me know if I missed anything

dnolen 2020-04-10T18:36:41.220600Z

if you all some low hanging fruit issues you'd like to see added to the next release let me know

dnolen 2020-04-10T19:07:05.222Z

3195, not now - 3086 approved

dnolen 2020-04-10T19:07:59.222300Z

2863 ok

dnolen 2020-04-10T19:08:33.222500Z

the others are too minor for now

👍 1
dnolen 2020-04-10T20:47:48.223700Z

here are my current thoughts about the coming changes - https://gist.github.com/swannodette/919ef8fb51e7ee91b5f3ab643c4b3e55

dnolen 2020-04-10T20:48:23.224400Z

feedback welcome, it's pretty simple - and I have another project that more or less confirms that it works

lilactown 2020-04-10T22:09:39.225800Z

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?

Oliver George 2020-04-13T05:26:02.415700Z

I'd be interested to see a working example if you do find a way to use Storybook with CLJS code.

dnolen 2020-04-10T22:17:00.226700Z

@lilactown it removes nearly all the steps (some error prone) for people who want to use some random lib

dnolen 2020-04-10T22:17:27.227300Z

but more importantly it provides a portable way to create clojurescript libs that depend on node_modules

dnolen 2020-04-10T22:17:36.227600Z

that's not really possible today because there's no standard way to do it

dnolen 2020-04-10T22:18:17.228200Z

the state of the art for creating CLJS libs that use JS deps is CLJSJS

dnolen 2020-04-10T22:18:34.228700Z

and that's also error prone, requires maintenance

lilactown 2020-04-10T22:19:03.229100Z

I see. agreed about cljsjs

lilactown 2020-04-10T22:20:01.230500Z

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

dnolen 2020-04-10T22:20:05.230600Z

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

👍 2
dnolen 2020-04-10T22:20:48.231400Z

@lilactown because we don't need to talk about anything else other than :bundle

dnolen 2020-04-10T22:21:01.231600Z

:npm-deps already exists and works

dnolen 2020-04-10T22:21:11.232100Z

it was always a la carte

dnolen 2020-04-10T22:21:37.232700Z

i.e. doesn't directly imply Closure, :nodejs target avoids that

lilactown 2020-04-10T22:27:21.237600Z

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?

lilactown 2020-04-10T22:33:09.241300Z

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 requires to node_modules and have webpack emit our final bundle

dnolen 2020-04-10T22:34:20.241800Z

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

1
dnolen 2020-04-10T22:35:05.242300Z

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

dnolen 2020-04-10T22:35:49.242900Z

@lilactown right but nothing I said talks about webpack specifically - in fact not interested in automating that part at all

dnolen 2020-04-10T22:36:05.243300Z

users will start webpack, fastpack, metro or whatever

dnolen 2020-04-10T22:36:46.244300Z

this is a good area for people to extend ClojureScript to make a shadow-cljs like experience + Figwheel or custom build setup or whatever

lilactown 2020-04-10T22:37:41.245400Z

that makes sense!

dnolen 2020-04-10T22:37:53.245900Z

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

dnolen 2020-04-10T22:38:41.246700Z

if there were people wouldn't still be going to CLJSJS

lilactown 2020-04-10T22:40:11.248Z

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

dnolen 2020-04-10T22:42:08.249500Z

right that's basically the worse case scenario

lilactown 2020-04-10T22:42:16.250Z

yeah 😕

dnolen 2020-04-10T22:43:22.251300Z

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

dnolen 2020-04-10T22:43:52.252200Z

libraries authors shouldn't have to care which thing is going to build their thing

lilactown 2020-04-10T22:44:38.253200Z

yeah, my case isn’t exactly related to node_modules but it’s a sort of second-order effect

lilactown 2020-04-10T22:45:34.254200Z

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.

lilactown 2020-04-10T22:46:24.255300Z

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

dnolen 2020-04-10T22:46:37.255600Z

looking at your project, I would say that's directly related to the node_modules problem 🙂

dnolen 2020-04-10T22:46:56.256100Z

because you can't do it w/o shadow you have to describe a whole bunch of other steps

dnolen 2020-04-10T22:49:04.257Z

@lilactown w/ my proposal above the caveats about non-shadow tools just go away

dnolen 2020-04-10T22:50:18.257700Z

the npm step is also not necessary

dnolen 2020-04-10T22:50:50.258500Z

you can add src/deps.cljs - the root of your classpath with those deps declared

dnolen 2020-04-10T22:51:05.258900Z

then anyone can install the required npm deps, it doesn't matter what tool they finally end up using

lilactown 2020-04-10T22:52:34.259100Z

I’ll do that now!

lilactown 2020-04-10T22:55:21.260400Z

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.

lilactown 2020-04-10T22:55:37.260800Z

don’t need to get into that now, not relevant and I don’t completely understand it myself

dnolen 2020-04-10T23:06:07.261200Z

huh, like Closure style JS in the project?

lilactown 2020-04-10T23:07:54.261400Z

yeah

lilactown 2020-04-10T23:11:15.263Z

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

dnolen 2020-04-10T23:16:21.265Z

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

lilactown 2020-04-10T23:18:28.265400Z

thanks, I’ll try and take another look at it soon

lilactown 2020-04-10T23:19:08.266200Z

yeah it’s very minimal - the only reason I did it was to try and get better interop with native classes

lilactown 2020-04-10T23:21:26.268700Z

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

lilactown 2020-04-10T23:23:24.270500Z

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)

dnolen 2020-04-10T23:25:52.272400Z

@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

lilactown 2020-04-10T23:26:40.272700Z

gotcha. I’ll try and play with it over the weekend.

lilactown 2020-04-10T23:28:34.273900Z

while I have your attention about this, would you ever consider a patch that added a form that emitted a class ? 😅

dnolen 2020-04-10T23:31:54.275500Z

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

dnolen 2020-04-10T23:32:41.276100Z

people keep talking about generating higher level JS but I really see only tradeoffs and most of them not in favor

dnolen 2020-04-10T23:33:40.276700Z

@lilactown https://clojurescript.org/guides/javascript-modules, the beginning of this explains what you need to do

👍 1
dnolen 2020-04-10T23:34:20.277700Z

:foreign-libs [{:file "helix/impl/class.js" :module-type :es6}] should theoretically work for you in your deps.cljs

niwinz 2020-04-13T22:08:53.049400Z

I have reported issue for this some time ago https://clojure.atlassian.net/browse/CLJS-2399 and seems not resolved

dnolen 2020-04-10T23:34:23.277900Z

if it doesn't - bug

lilactown 2020-04-10T23:36:37.279200Z

yeah, a lot of higher level features have a relatively minimal impact on applications, but a considerable impact on project maintenance

lilactown 2020-04-10T23:37:29.281Z

from the perspective of a maintainer of CLJS, I mean

dnolen 2020-04-10T23:37:57.281800Z

right, higher level features mean a more complicated pipeline, worse perf, etc.

dnolen 2020-04-10T23:38:25.282600Z

(compiler perf, possibly runtime perf - ES3 is fast)

lilactown 2020-04-10T23:40:15.284200Z

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

lilactown 2020-04-10T23:41:24.285800Z

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

dnolen 2020-04-10T23:41:38.286100Z

people keep talking about async/await perf but honestly I find such talk meh esp. in browser context

dnolen 2020-04-10T23:42:12.286900Z

Node.js really isn't that interesting for server IMO if you're already doing Clojure anyway

dnolen 2020-04-10T23:42:43.287500Z

so that's why not much has happened here - I just don't see much value

dnolen 2020-04-10T23:43:26.288300Z

I think some work on codegen for core.async is all that it really needs - it's not that slow

lilactown 2020-04-10T23:44:01.288900Z

absolutely

dnolen 2020-04-10T23:44:11.289200Z

@lilactown re: class I'm not against this if it's selective

dnolen 2020-04-10T23:44:34.289700Z

i.e. if you use defclass we'll generate ES6 and do a second pass w/ Closure on that file

dnolen 2020-04-10T23:45:04.290300Z

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

dnolen 2020-04-10T23:45:16.290600Z

it's definitely an interop gaping hole

lilactown 2020-04-10T23:45:38.291Z

I’ll create a ticket and try and find time to take a look

dnolen 2020-04-10T23:46:24.292100Z

in the ticket mention we need 2 parts - defclass macro and compiler support

👍 1
lilactown 2020-04-10T23:46:37.292400Z

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

dnolen 2020-04-10T23:47:10.293100Z

sure, but is something people have asked for years

dnolen 2020-04-10T23:47:41.293800Z

now that we have easy single file transpile support I don't really see any issues

dnolen 2020-04-10T23:48:13.294300Z

it does affect source mapping but that can be done as separate enhancement ticket

lilactown 2020-04-10T23:59:14.294500Z

how does this look? https://clojure.atlassian.net/browse/CLJS-3226