Yeah I need to specify that, you need 2.7.2-SNAPSHOT
to do that, create and/or edit boot.properties
in the project folder and set:
#<http://boot-clj.com>
#Sat Dec 31 19:36:01 PST 2016
BOOT_CLOJURE_NAME=org.clojure/clojure
BOOT_CLOJURE_VERSION=1.8.0
BOOT_VERSION=2.7.2-SNAPSHOT
actually version 2.7.1
should be good
so yeah still some work to do
there should also be a working demo here: https://github.com/arichiardi/figreload-demo
@richiardiandrea just tried your figreload-demo and and got https://gist.github.com/darwin/3f3bdbdf0cb946abed76aeba6215e06e, so it seems that figwheel sidecar and nREPL server do not share same JVM
otherwise figwheel compiler state(s) would be listed in (dirac :ls)
btw. I don’t even see any mention of figwheel connection at localhost:3000, in console messages
I just briefly looked at boot-figreload and it does not look like you are using fighwheel sidecar on server side, you just grabbed a few utility functions to communicate with figwheel client, but the core logic of the sidecar is replaced by your own implementation
this is not going to work I’m afraid
also I don’t see the specific point where you actually recompile modified cljs files
looking at deftask reload
but was unable to find the place where the build actually occurs, is it done behind the scenes by some other task? maybe watch task?
ah, here it is: https://github.com/boot-clj/boot-cljs/blob/master/src/adzerk/boot_cljs.clj#L256
so dirac would need access to compiler states of this cljs task, to work seamlessly with this setup. By seamlessly I mean “But there is a subtle problem. As you probably know traditionally you had to make effort to keep your REPL environment in-sync with your runtime environment being evolved by hot-reloading. Figwheel REPL has an advantage that it is using the same compiler environment as was used for last incremental compilation. That means that Figwheel REPL is always in sync and you don’t have to ‘load-file’ or somehow reload/refresh namespaces in your REPL.” as described here https://github.com/binaryage/dirac/blob/master/docs/about-repls.md#dirac--figwheel
btw. compiler management in dirac is implemented here: https://github.com/binaryage/dirac/blob/master/src/nrepl/dirac/nrepl/compilers.clj#L89-L94 when scanning for available compiler states, it first lists compilers for current nREPL session, then lists all compilers for other nREPL sessions (e.g. you have connected multiple dirac REPLs to your nREPL server each using a distinct nREPL session) and then it scans for figwheel presence and grabs compiler states from figwheel sidecar (again there may be multiple ones because figwheel sidecar keeps one compiler per build-id)
you would have to implement additional scanning for boot’s compilers managed by boot-cljs, I guess
and this might not be easily possible because boot task are isolated in pods and don’t share same JVM
Thanks, yes I started to suspect I was missing a piece. You are right I emulate figwheel's server side. I guess that when one executes a command in the nRepl with figwheel the same command is evaluated in the browser, otherwise I don't see how you can keep two compiler envs in sync...but I will investigate more... don't take my words now I have just woken up 😀
there are two independent operations, 1. compilation cljs->js 2. eval of js
both operations are stateful, #1 needs some compiler state (or empty one) #2 needs js runtime env (browser’s js context)
Compilation is handled by boot-cljs and the state is there, you are right it is in a pod...but that is rarely a problem with file reloading going on
ideally we would like to keep compiler’s state in nREPL server in sync with compilations happening because we want to hot-reload some code3
Yeah so in nrepl server I probably need to file reload as well 😀
Nobody has done it... Maybe it is not doable
well, ideally you want nREPL server to share compiler state with boot-cljs
in other words, you want all parts seeing and using the same compiler state
Yeah this at the moment as you were saying this is not possible in boot...
trying to reload files in nREPL could work for basic workflows, but I can imagine it would be pretty fragile
I’m not sure if it is not possible
I don’t know how pod isolation works and if boot-cljs coudn’t be run in the same JVM context as nREPL server
or maybe some comm channel could be estabilished
cljs from dirac’s nrepl middleware would be sent to boot-cljs process to be compiled and returned back as js
sounds as quite simple interop to me
or maybe vice-versa, nREPL server would manage compilers and expose some api and boot-cljs would use it for compilations
Yeah seems like a good compromise..will explore as this is something that I have not seen anywhere in boot and probably the normal repl does not do
yes, hot-reloading is not a common practice in Clojure world
so that is why nobody cares in clj REPL tooling
but with figwheel it is completely different game, I use hot-reloading to do live coding much more often than interacting with REPL
clojure people have only REPL so they cannot get out-of-sync
So given what you say above we are still good, folks don't expect state to be in sync when using boot-cljs-repl either but they can now use dirac
Problem is when a file changes it will be hot reloaded
Potentially overriding stuff
simplest problematic case is that you def some new thing like a function, save file, it hot-reloads, updates js context, then go to Dirac REPL and expect that function to be known to compiler, but when you enter some cljs expression using that symbol name, cljs compiler in nREPL won’t be aware of it
you would first have to load-file
it to refresh nREPL’s compiler state to match boot-cljs’s compiler state
but the general case is much more complicated, e.g. touching a macro which triggers a cascade of recompilations for dependent cljs code
at least figwheel deals with these cases well
Yeah it has been a good digging exercise to read Bruce's code
Compiler state is data, I wonder whether simple diffing would work
not sure, I’m afraid there might be some hard-to-serialize java stuff in there
btw. I wanted to switch to boot at least twice in the past, it has very nice functional design and vibrant community, but figwheel was always the show stopper
for me
Yeah I can understand that is why I have started porting it. I remember sitting with Fransisco Avila and Bruce at the Conj 2016 trying to untangle the thread
why you couldn’t reuse figwheel components directly?
Because Boot's filesystem is immutable
There is a task that uses it directly
But you cannot stay in the task world
You need to use an external tmp folder only for figwheel
awfully many hours were poured into figwheel’s impl I think, I would imagine that tmp folder isolation and some bridge in and out for interop with other boot tasks
Yes that was my idea, try to reuse as much as I can
nREPL server is also a side-effecting thing with its own direct file access and nobody reimplemented it completely in boot, I guess 🙂
In the meantime solving bugs and improving the HUD (Boot's HUD is not the same and it would evolve to copy figwheel's anyways)
Yeah no, the nRepl server is untouched. The folks in #unrepl are thinking about a rewrite though
ok, boot ecosystem is heathy, you will get to figwheel parity at some point I believe
but for now I’m sticking with lein, I guess
😀 btw this is what I discovered about the compiler state, and I did not notice anything unreadable, but I will ask: https://github.com/Lambda-X/replumb/blob/master/src/cljs/replumb/ast.cljs
not sure how replumb it related to this, but I would look here: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/env.cljc#L25-L44
if I knew you were serializing the state to send it over some wire, I could be malicious and simply pass a custom compiler option which would be some unserializable thing, and you would be done
Yeah replumb is cljs-in-cljs layer I wrote
Ah ah ok, but this is only in dev mode
hmm, I don’t think so, this is compiler state for whatever mode
also read this: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/env.cljc#L42-L43
anytime in the future they might decide to put something unserializable there
I am not that sure, or cljs-in-cljs will break
And you don't want to break Lumo, Planck, ...
there could be two code paths, normal and bootstrapped
in theory, didn’t review it
if I remember correctly it is one
but you are correct that with bootstrapped it is unlikely to contain some wild stuff
I might be wrong though
but I gave you an example of breaking code already, with foreign :options