Fork me on GitHub
#cljs-dev
<
2022-04-23
>
dnolen02:04:19

I'm very skeptical about the loading of AOT twice being slower, so not convinced unless you have measurements - otherwise what is the problem

dnolen02:04:43

Google Closure did this and it seems mostly a net benefit

thheller03:04:21

what benefit? closure constantly breaks when people use it together with datomic on the classpath due to guava for example? it is also a different story since that is all java based you can just replace one .class with another. with Clojure AOT once it starts loading one AOT class it'll load only AOT classes. so just putting a newer tools.json version on the classpath (that does not contain any .class) does nothing, just confuse the user why they don't see the new version being used although it should be

1
thheller03:04:16

"AOT twice being slower" I mean that the code will load the mranderson-styled renamed tools.reader AOT variant and then the non-AOT require clojure.tools.reader variant requested by shadow-cljs. yes, loading the AOT variant is much faster but still not free. so give it a 20% overhead.

thheller03:04:03

right now it is just loading the regular cljs-bundled AOT variant, so that is fast which is great. at the downside that you cannot easily replace it with a newer version. which is not that big of a deal but does end up confusing people sometimes.

thheller03:04:45

but since we are talking about milliseconds here that is not a big deal performance wise. I'm more concerned with the possible dependency confusion.

thheller03:04:56

these are minor concerns but I still believe that AOT by default is not what any CLJ/CLJS libraries should be doing. it does create confusing errors that aren't hard to fix but very hard to identify properly (eg. https://github.com/thheller/shadow-cljs/issues/983, note this is an example of the closure "problem" mentioned above. not related to AOT cljs)

1
borkdude05:04:28

I think no library should contain AOT-es classes from its transitive dependencies

dnolen12:04:59

@borkdude i do not believe that is even possible if you AOT

arohner14:04:34

This is definitely does work. Clojure loads code per-class, and source files can load AOT and vice versa. The only factors are: • whether both versions are on the classpath • the file modification time of the .classfile rules_clojure (https://github.com/griffinbank/rules_clojure) implements non-transitive AOT

dnolen12:04:39

@thheller we have used the shaded Closure dep for a long time to avoid those issues so I'm not sure what you are referring to

borkdude12:04:47

@dnolen The transitive dependencies will be AOT-ed too, but that doesn't mean you have to include those in your artifact

borkdude12:04:21

I believe tools.build has a filter feature for that

dnolen12:04:34

But will that work @alexmiller didn't suggest that route?

dnolen12:04:59

If it does work and doesn't create other issues that seems simpler

borkdude13:04:12

As long as clojure/data/json.clj is also on the classpath for library users due to being a dependency, why wouldn't it?

dnolen13:04:38

AOT is not without corner cases far as I remember

borkdude13:04:19

ok, Alex probably knows more about this than I do, so I'll be looking forward to his opinion on this

borkdude13:04:53

A way around the AOT-ed CLJS artifact is to just use it as a git dep

borkdude13:04:39

For me personally it's not a huge problem as I usually use CLJS more as a tool rather than an application dependency

borkdude13:04:00

And it does make startup time faster when it's AOT-ed

thheller14:04:59

I was fairly certain that AOT classes directly refer to other AOT classes and thus can't go back to loading clj files

thheller14:04:12

but looking at the generated class file that doesn't seem to be the case

thheller14:04:35

so just excluding the not-cljs-related AOT classes should be fine

thheller14:04:10

@dnolen the problem with closure I'm referring to is this: closure doesn't declare its dependency on guava. yet you end up with a guava version in the closure compiler jar. eg.

Clojure 1.11.1
(require ')
nil
( "com/google/common/collect/ImmutableMap.class")
#object[java.net.URL 0x315df4bb "jar:file:/home/thheller/.m2/repository/com/google/javascript/closure-compiler-unshaded/v20210808/closure-compiler-unshaded-v20210808.jar!/com/google/common/collect/ImmutableMap.class"]
user=>
with just deps.edn
{:paths ["src"]
 :deps {org.clojure/clojure {:mvn/version "1.11.1"}
        org.clojure/clojurescript {:mvn/version "1.11.4"}}}
so tools.deps (or maven in general) won't know guava exists and not resolve conflicts accordingly. then depending on other dependencies that may bring in other guava and which was ends up first on the classpath you end up with possibly conflicting guava versions.

thheller14:04:23

this is a problem I have to constantly help people debug and fix. at least once a month would be my guess and most commonly happens for people integrating their frontend build with the regular deps.edn or project.clj backend deps

thheller14:04:23

this also didn't always use to be like this. closure used to declare the dependency properly and all was fine. some time ago they changed and basically distribute an uberjar instead. https://github.com/google/closure-compiler/issues/3896

thheller14:04:29

its kinda hard to reproduce the closure dep issues since it comes down to undefined dependency ordering. if the dependency properly declaring guava gets loaded after the closure compiler everything may work if that lib is also happy with the guava version from the closure compiler. if not it breaks. if the declared guava gets loaded first the closure compiler itself may or may not break, depending on which version it is

thheller14:04:52

but given how common guava is as a backend dependency this happens often enough to be annoying

thheller14:04:27

enough side tracking though, that really has very little to do with the CLJS being AOT or not and is an entirely separate issue that really needs to be fixed on the closure side of things

thheller14:04:55

with CLJS AOT the only actual problem I have helped people though is trying different tools.reader or data.json versions and wondering why they weren't seeing those versions being used

thheller14:04:15

given that clojure will load AOT classes before .clj files by default

thheller14:04:26

$ clj
Clojure 1.11.1
(require ')
nil
( "clojure/tools/reader__init.class")
#object[java.net.URL 0x315df4bb "jar:file:/home/thheller/.m2/repository/org/clojure/clojurescript/1.11.4/clojurescript-1.11.4.jar!/clojure/tools/reader__init.class"]

thheller14:04:47

so even if you have a local version of tools.reader that you are trying to modify or something it will not be used

arohner14:04:34

This is definitely does work. Clojure loads code per-class, and source files can load AOT and vice versa. The only factors are: • whether both versions are on the classpath • the file modification time of the .classfile rules_clojure (https://github.com/griffinbank/rules_clojure) implements non-transitive AOT