Fork me on GitHub
#tools-deps
<
2020-08-06
>
dharrigan19:08:03

I have a question, related to this . Say I have a deps.edn that has an alias that pulls in a few other sources, via extra-deps, using a couple of :local/root declarations, i.e., one that loads in rebel readline (with little customisation) and another which launches a nrepl (with some middleware injected). Can I still benefit from what the guide says? Can I compile the extra-deps includes, so that my clj startup is reduced?

Alex Miller (Clojure team)19:08:14

it's all on the same classpath

dharrigan19:08:02

Okay, but where would the classes directory live, i.e., if I have something like this...

dharrigan19:08:05

:rebel {:extra-deps {local-rebel {:local/root "/home/david/.clojure/libs/local.rebel" :deps/manifest :deps}
                       local-nrepl {:local/root "/home/david/.clojure/libs/local.nrepl" :deps/manifest :deps}}
          :main-opts ["-m" "local.rebel.main"]}

Alex Miller (Clojure team)19:08:23

I'd put it in its own alias and then use multiple aliases

Alex Miller (Clojure team)19:08:50

ie, it's actually the same as what's in the doc, you just might have extra tool aliases in play

dharrigan19:08:18

okay, let me have a play around. My clj startup at the moment is taking about 8 seconds to launch...

souenzzo19:08:50

Oh.... Mine is ~2min on good machines and we really don't care about that

dharrigan19:08:23

:shocked_face_with_exploding_head:

souenzzo19:08:45

I open the repl less then once a day. (it remains open)

Alex Miller (Clojure team)19:08:21

so clj -A:dev:rebel or whatever

Alex Miller (Clojure team)19:08:38

or actually you've got main args in there

Alex Miller (Clojure team)19:08:54

so you might want to do clj -R:dev:rebel when doing the compilation

Alex Miller (Clojure team)19:08:03

so you get just the deps but not the main stuff

dharrigan19:08:16

okay, will have a play 🙂 Thank you Alex! 🙂

dharrigan19:08:39

I'd love one thanks 🙂

seancorfield19:08:43

I only restart my REPL about once a week so even a few minutes startup wouldn't really bother me. I'm curious about workflows where startup times of eight seconds is problematic @dharrigan?

👍 3
dharrigan19:08:10

I have a need, a need for speed 🙂 I guess I'm just learning about if by applying some of the recommendations in that web page I can shave off some time! No harm in trying to optimise if I can 🙂

😆 3
dharrigan19:08:25

Interesting, got it down to 3 seconds 🙂

👍 3
Alex Miller (Clojure team)19:08:10

I'll send you my bill

😂 3
dharrigan19:08:45

Errrr....would an I.O.U suffice?

dharrigan20:08:22

I.O.U one beer, fresh from the tap, if when you get to Ireland/UK 🙂

Alex Miller (Clojure team)20:08:34

I hope I can leave my house again someday

lread20:08:47

@dharrigan’s avatar is a duck… he already has a bill!

dharrigan20:08:31

He's the Egyptian Household God of Frustration.

dharrigan20:08:07

Best Show Evar!

simple_smile 3
seancorfield20:08:17

@alexmiller So I went and tried that dev startup time stuff (for the first time). I compiled a bunch of big libraries that my code relies on that rarely change, but did not compile my own code, then a ran a "load file" on my app's main file and it threw an exception about a clojure.core.cache.CacheProtocol not found... so I'm guessing there's a possibility for this pre-compile step to mess up in some way?

Alex Miller (Clojure team)20:08:03

depends how you compiled everything

Alex Miller (Clojure team)20:08:46

if you're trying to compile independent libs then you might not be compiling in the same order you actually load them in via your app

Alex Miller (Clojure team)20:08:52

and then you can get into the case of recompiling a protocol, which can definitely go wrong

seancorfield20:08:57

When I tried to repro with a (require 'api.main) instead of the load-file that the editor does, that seemed to work, so maybe it's something specific to load-file?

Alex Miller (Clojure team)20:08:39

require will load too under the hood, but maybe

seancorfield20:08:49

Ah, no difference. I started a fresh REPL, with those libraries precompiled and require failed this time, just as load-file had before.

seancorfield20:08:31

So, you have to transitively compile "everything" to make this work, so that compile order doesn't matter?

Alex Miller (Clojure team)20:08:55

transitively compiling everything should work (b/c it's exactly what your app does when it loads)

seancorfield20:08:59

What about a project where you have multiple entry point nses, that represent separate applications?

Alex Miller (Clojure team)20:08:01

other things might work :)

Alex Miller (Clojure team)20:08:28

you could use more than one alias/classes dir if you find that to be a problem

Alex Miller (Clojure team)20:08:11

or you could still use just compile with one and use from the other entry point. you might miss some stuff but presumably it's mostly the same in deps.

seancorfield20:08:28

Currently, I start a REPL once a week (roughly) and just load code into it as needed so I usually end up with our entire code base loaded into the REPL eventually.

Alex Miller (Clojure team)20:08:08

you are a bit outside the target user of this page :)

seancorfield20:08:31

Compiling two different entry points that overlap might fall into the "recompiling a protocol" area?

Alex Miller (Clojure team)20:08:37

I am shorthanding the actual problem (recompilation itself is not the actual problem)

seancorfield20:08:39

So the problematic piece (that surprises me a bit) is that (compile 'clojure.core.memoize) does not seem to transitively compile clojure.core.cache which I would have expected... I think that's the root of my earlier problem perhaps?

Alex Miller (Clojure team)20:08:41

it should transitively compile anything loaded by clojure.core.memoize

Alex Miller (Clojure team)20:08:52

but not everything in core.cache is used by memoize

seancorfield20:08:19

When I look in the classes tree after (compile 'clojure.core.memoize) there are no core.cache classes at all.

hiredman20:08:06

what about if you compile clojure.core.cache? my kind of guess would be it is already compiled/loaded somewhere else in your repl

Alex Miller (Clojure team)20:08:07

any chance you've already loaded something that has loaded core.cache prior?

Alex Miller (Clojure team)20:08:27

compile piggybacks load so if it's not being loaded (b/c it already is), it won't be compiled

seancorfield20:08:43

Ah, that is a possibility, because something in my dev tooling might well be using that... If I explicitly (compile 'clojure.core.cache) I do see the .class files produced for it which would suggest it isn't loaded previously?

seancorfield20:08:56

(or am I misunderstanding your point?)

hiredman20:08:37

that is interesting, I wouldn't expect to see those if clojure.core.cache was previously loaded

Alex Miller (Clojure team)20:08:32

I suspect you're getting the equivalent of :reload at the top level namespace you compile

Alex Miller (Clojure team)20:08:38

but not on the ones below

seancorfield20:08:55

Yup, confirmed. A "bare" REPL with just my dev tooling loaded has clojure.core.cache clojure.core.protocols clojure.core.server clojure.core.specs.alpha clojure.data.priority-map ... (non-`clojure.*` stuff omitted).

hiredman20:08:39

ah, right, compile calls load-one directly, bypassing the already loaded check

seancorfield20:08:02

So, yeah, I'd need to explicitly (compile 'clojure.core.cache) to make all this work, right?

Alex Miller (Clojure team)20:08:17

you can do what's in the bottom of that guide (kind of), which is to address a similar problem (when user.clj has already loaded stuff)

Alex Miller (Clojure team)20:08:42

(binding [*compile-files* true] (require 'clojure.core.memoize :reload-all))

Alex Miller (Clojure team)20:08:05

the only thing that makes load do compile is that dynvar

Alex Miller (Clojure team)20:08:13

and the :reload-all will force a reload

seancorfield20:08:11

I'm going to stick a list of (compile 'x.y.z) forms in a compile.clj file so I can do load-file on it to compile "everything" that I want pre-compiled and I'll add to it as/when I run into problems. FWIW, just with the set of libs I've put in that list so far, a cold (require 'api.main) has dropped from 18 seconds to 10 seconds. Like I say, since I only restart my REPL occasionally, that's really not a concern but now I'm curious about this idea of pre-compiling dependencies that rarely change...

seancorfield20:08:53

...and if a dependency does change, presumably you'd have to force a recompile of the newer version (and everything that depended on it) in order to pick those changes up?

Alex Miller (Clojure team)20:08:17

a newer dependency should have newer .clj files and be preferred

Alex Miller (Clojure team)20:08:25

it will just be slower till you recompile

Alex Miller (Clojure team)20:08:58

clojure takes the newer .class or .clj

Alex Miller (Clojure team)20:08:32

I guess if you changed deps to a newer version of a lib that was still older than your local .class files that wouldn't have that effect

Alex Miller (Clojure team)20:08:29

I spent a half day trying to build this into clj so it could do it automatically (since it knows when your deps go stale). it was tricky for a bunch of reasons but maybe a future feature

Alex Miller (Clojure team)21:08:10

the point where your .cpcache is stale is also the point when you want to recompile

Alex Miller (Clojure team)21:08:20

so was trying to hook that

seancorfield21:08:35

Yeah, discussions about it being a possible future feature of clj was what made me even curious to try it, once it was brought up here.

Alex Miller (Clojure team)21:08:14

relevant for tools that replace the classpath too