Closed olivergeorge closed 6 years ago
Hi, yes ClojureScript support is definitely part of the intentions of this library (this release included). However, I confess I didn't try it on each one of the many CLJS REPLs out there...
I'm going on vacation for a week and won't really be able to help, but if you want to be unblocked right away I suggest you register a 'silent' cs logger for spy - see the Tutorial for how to register custom loggers. It should still be pretty usable, you will just get less feedback during compilation
Thanks. I'll checkout the tutorial and give it a try.
Enjoy your vacation.
Quick update to confirm this got me the reported error.
(ns can-i-debug.dev
(:require [sc.api] [sc.impl] [sc.api.logging]))
(sc.api.logging/register-cs-logger ::dummy-logger (fn [_]))
(defmacro my-spy [form]
`(sc.api/spy {:sc/spy-cs-logger-id ::dummy-logger} ~form))
Alright, back from vacation.
So it seems the issue here is that both the logs from macro-expansion and the emission of JavaScript output get mingled in the same writer. I took the liberty of changing the title of the issue so that people don't think ClojureScript is not yet supported - (it is, in general).
@olivergeorge, can you describe the ClojureScript setup that led you to this situation please?
Hope you had a good break.
I used lein new mies xxx
to create the simplest test case possible. As mentioned the logger output appeared in the generated js files. Once that was silenced my-spy
seemed to capture data but I couldn't get sc.api/letsc
to work. It wasn't able to resolve the numbers in the atom.
I gave up after a while, if you think the basic case should work I'll try again.
Thanks! I'll try to reproduce then get back to you.
So first, not that it's critical to your issue, but the recommended way to define your own spy macro is to have it call spy-emit (so that it can pass to it the original &env
and &form
), like so:
(sc.api.logging/register-cs-logger
::dummy-logger
(fn [_]))
(def my-spy-opts
`{:sc/spy-cs-logger-id ::dummy-logger})
(defmacro my-spy
([] (sc.api/spy-emit my-spy-opts nil &env &form))
([expr] (sc.api/spy-emit my-spy-opts expr &env &form))
([opts expr] (sc.api/spy-emit (merge my-spy-opts opts) expr &env &form)))
This is detailed in the Customization section of the Tutorial.
I was able to use scope-capture successfully in the browser REPL, as available in the mies template:
$ lein trampoline run -m clojure.main scripts/brepl.clj
Reading analysis cache for jar:file:/Users/val/.m2/repository/org/clojure/clojurescript/1.9.671/clojurescript-1.9.671.jar!/cljs/core.cljs
Compiling src/sccljs/core.cljs
[...]
Copying file:/Users/val/projects/sccljs/src/sccljs/core.cljs to out/sccljs/core.cljs
Compiling client js ...
Waiting for browser to connect ...
To quit, type: :cljs/quit
cljs.user=> (ns sccljs.core
(:require [clojure.browser.repl :as repl]
[sccljs.dev :refer-macros [my-spy]]
[sc.api :refer-macros [spy brk letsc defsc]]))
sccljs.core=> (defn bar
[x y]
(+ x (spy (* 2 y))))
SPY <-1> /Users/val/projects/sccljs/scripts/brepl.clj:3
At Code Site -1, will save scope with locals [x y]
#'sccljs.core/bar
sccljs.core=> (bar 12 13)
SPY [1 -1] /Users/val/projects/sccljs/scripts/brepl.clj:3
At Execution Point 1 of Code Site -1, saved scope with locals [x y]
SPY [1 -1] /Users/val/projects/sccljs/scripts/brepl.clj:3
(* 2 y)
=>
26
38
sccljs.core=> (defsc [1 -1])
[#'sccljs.core/x #'sccljs.core/y]
sccljs.core=> (+ x y)
25
sccljs.core=> (letsc [1 -1] [x y])
WARNING: Use of undeclared Var sccljs.core/yy at line 1 <cljs repl>
[12 nil]
sccljs.core=> (letsc [1 -1] [x y])
[12 13]
sccljs.core=> (bar 2 3)
SPY [2 -1] /Users/val/projects/sccljs/scripts/brepl.clj:3
At Execution Point 2 of Code Site -1, saved scope with locals [x y]
SPY [2 -1] /Users/val/projects/sccljs/scripts/brepl.clj:3
(* 2 y)
=>
6
8
sccljs.core=> (letsc [2 -1] [x y])
[2 3]
sccljs.core=>
@olivergeorge I also reproduced your first issue (logs in the emitted JS), which happens when you cljs.api.build/build
or cljs.api.build/watch
some CLJS code with an sc.api/spy
call in it. The issue is that, for some reason, in these cases, the ClojureScript compiler emits JavaScript by binding *out*
to some writer then calling print
, which is why our scope-capture logs end up in the JS output.
You can get by these limitations by either using a silent logger (see above), or one that always prints to standard output or some defined file, e.g:
(sc.api.logging/register-cs-logger
::dummy-logger
(fn [cs-data]
(binding [*out* (java.io.OutputStreamWriter. System/out)]
(println (:sc.cs/id cs-data) (:sc.cs/local-names cs-data)))))
Having said that, you typically don't want to use scope-capture at all outside of the context of a REPL!
@olivergeorge Another issue you may have encountered is that, when several processes (e.g a REPL process and a watcher process) compile to the same runtime, they won't share their compile-time scope-capture database, leading to some Code Site Ids (e.g -3) not being identified. I'm currently thinking of ways to mitigate this issue. This was made worse by a bad error message in this case, which I'll be improving in the next minor release.
Thanks @vvvvalvalval I'll give it another go. Thanks for all the details.
Having said that, you typically don't want to use scope-capture at all outside of the context of a REPL!
I agree that the REPL is the first and most important use case.
The two other use cases I see as important would be
@olivergeorge Alright, I got a browser REPL + file watcher mostly working with the following script added to the mies
template:
(require
'[cljs.build.api :as b]
'[cljs.repl :as repl]
'[cljs.repl.browser :as browser])
(def opts
{:main 'sccljs.core
:output-to "out/sccljs.js"
:output-dir "out"})
(println "Building...")
(b/build "src" opts)
(future
(println "Watching in another thread...")
(b/watch "src" opts))
(repl/repl (browser/repl-env)
:output-dir "out")
Be careful, it interacts badly with compilation caching, which assumes that the compilation is stateless. Best to do a lein clean
before you run the script.
@olivergeorge I got it to run with Figwheel as well, it was actually easier as figwheel runs the REPL and file watcher in the same process by default. Be careful of what browser window your code is executing in though, or you may be missing some Execution Points (you can find out which window it is using (js/alert "where am I?")
)
I'm looking forward to putting it through it's paces. I wonder how I got into trouble. I'll keep an eye on the compilation cache and repl processes next time around.
@olivergeorge:
Closing this issue.
@olivergeorge Your initial problem with logs mixed with emmitted JS should be fixed by 0.1.3, can you try again? https://github.com/vvvvalvalval/scope-capture/releases/tag/v0.1.3
Seems like scope-capture would allow more convenient repl based development for my CLJS web apps. Can't see technical reasons it can't be made to work. (That would be exciting)
I gave it a try, there's currently a problem with how the repl output is generated. Print statements end up on the JS code which is compiled causing errors.
For example:
Perhaps this can be avoided with a new
register-cs-logger
?