This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-08-05
Channels
- # bangalore-clj (1)
- # beginners (99)
- # boot (108)
- # cider (15)
- # clara (4)
- # cljs-dev (12)
- # cljsjs (37)
- # cljsrn (4)
- # clojure (110)
- # clojure-italy (2)
- # clojure-spec (12)
- # clojurescript (168)
- # cursive (1)
- # datomic (24)
- # graphql (6)
- # hoplon (5)
- # jobs-discuss (2)
- # keechma (21)
- # mount (5)
- # off-topic (140)
- # om (2)
- # parinfer (37)
- # planck (6)
- # re-frame (4)
- # reagent (9)
- # rum (2)
- # spacemacs (4)
Is there a way to retrieve the cljs source of a function at runtime? It's for a development build, so happy to do some weird hacks.
conceptually, something like: (-> (fn [x] :foo) meta :source) ;;=> "(fn [x] :foo)"
Not trying to capture the actual execution context, closures, or otherwise re-eval on the other side of the wire. It's purely for instrumentation / debugging.
@kevin.lynagh possible with a macro. see https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/repl.cljc#L1232
Maybe I'll have to write my own macro to do this, using reader or some such to identify the fn forms and capture the source?
the debugger needs to run on a separate machine (e.g., an iPad) so that you can examine certain interactions within the app.
That is, you can't switch over to devtools because the interaction might do things on focus change, keyup, etc.
something like
(defmacro fn+ [& stuff] `(with-meta ~(cons 'fn ~stuff) {:source ~(str stuff)}))
?presumably I could remap "fn" in the development mode compilation to add source metadata
+user=> (defmacro fn+ [& stuff] `(with-meta ~(cons 'fn stuff) {:source ~(str stuff)}))
#'user/fn+
+user=> (def f (fn+ testing-it [_] 42))
#'user/f
+user=> (pprint (meta f))
{:source "(testing-it [_] 42)"}
nil
@anmonteiro Would it be possible to do on a per-namespace basis? Overriding every fn
seems like it could blow up the code size significantly.
@kevin.lynagh well you can override it and dispatch on some metadata marker that records the source
also you could emit the sources to some source map type file, and just keep an id for lookup on the fn
Here's another idea --- given that I'm invoking build
myself, would it be possible to just dynamically replace the inputs to cljs without having to do fancy alter-var-root stuff?
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/core.cljc#L97
also think about whathappens if that file gets loaded twice - it ends up wrapping the wrapper if you are not careful
by replacing the inputs, I mean replacing the symbols before feeding into cljs compiler. So I could replace (fn ...
with (fn-with-source ...
right but for that to really work you would want to transform things like defn that expand to fn
and you can do it conditionally of compiler options so you make sure it doesn’t bloat your prod build
I'm not very familiar w/ the internal workings of the analyzer --- is this something in cljs, or is this tools.analyzer?
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L1713
couldn't a user opt in by telling the tool to reload an ns with its version of fn?
@anmonteiro Reading that code, it seems like that all operates on code that has already been read and macroexpanded?
@noisesmith Right. The thing that looks at the var actually just looks back on disk to find the source: https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/repl.cljc#L1191
Well, in any case running str on the forms will be sufficient for my purposes. I think var-overriding is my best bet, so I'll look into that.
@kevin.lynagh are you aware that Chrome DevTools can be used remotely from a different machine? That should be enough to debug focus/keyboard/hover issues.
Yeah, I've used remote devtools for debugging before. I'm working on something that's more specialized than the built-in devtools
i had spacemacs, but that can't even comment the code by default and when i googled it i got lost
Can anyone explain to me how it’s possible to use, say, clojure.string inside Clojurescript/Lumo where no JVM is involved? I don’t get it.
I think there's a list of Clojure requires that get rewritten to CLJS requires in ClojureScript
@clojer It is the same reason you can use it in code emitted by JVM ClojureScript: That namespace is implemented in ClojureScript which compiles to JavaScript essentially implementing all the needed functionality.
@rgdelato You are referring to the fact that clojure.*
gets aliased to cljs.*
if the clojure.*
namespace doesn't exist.
More info on that: http://blog.fikesfarm.com/posts/2016-07-03-clojurescript-clojure-namespace-aliasing.html
oh, cool. I didn't know it was across the board, I thought it was only specific libs
@noisesmith yeah. Oftentimes a rename is done to avoid a collision of the ClojureScript macros namespace with the existing Clojure namespace
I have a line of cljs code like this:
(.addEventListener js/window "keydown" (fn [e] (println e)))
It works as expected when run in the browser, expect, when a key is pressed, it outputs this: #object[KeyboardEvent [object KeyboardEvent]]
Is there a way to get the js object printed to the console rather than the above?
@tkjone Yep! In this case, println is trying to print out a cljs value, but it was given the native JavaScript event.
You can still use console.log(e)
from JavaScript --- in ClojureScript that would look like (.log js/console e)
Thanks, @kevin.lynagh! So for instances like what I am trying to do, this is the preferred practice?
The p
can be used for things that I know are native JavaScript objects, and the pp
is used for cljs objects. The reason I'm using a macro is so that I get proper line numbers in the JavaScript console.
If you were to define a function that called console.log, then all of the line numbers would refer to that function definition rather than to the place you were actually trying to print.
Also note that, unlike console.log (in js) and pr-str (in Clojure/ClojureScript) these macros return the value, which means you can just throw it wherever you want in an existing expression
Maybe that was more info than you wanted --- in short, yes: it is totally idiomatic to use the platform stuff like console.log
to print things = )
I very rarely define macros. I have a 10k+ line clojurescript project and those are the only two macros. Only reason is to get 'dem line numbers.
yes, macros seem like something to add under careful consideration, but this sounds right
I also notice that it continues to print out the cljs value
of #object[KeyboardEvent [object KeyboardEvent]]
- this is expected behaviour, yes?
If you are working in a REPL then yes, your original event listener is still attached to js/window
.
Figwheel would also count as a REPL in this case, since the stateful window object is persisting between refreshes.
don't want to probe too much, but I am curious where you put those macros in your project?...from a files and folders perspective
Then in my cljs files: `(ns foo.bar.my-cljs-namespace (:require-macros [foo.bar.macros :refer [p pp]]))`
I cloned a repo to a VPS and after I lein deps
'd everying, my source takes minutes building, not even from scratch. Is there something I forgot to update?
@kevin.lynagh I added your macros directly in the same cljs
file as my main app. This actually caused, without warning or errors, the script to stop working. I moved them out of the cljs
file, moved them into their own clj
file and imported them into my cljs
- as you noted to do - and everything works again. Is this because the macros are, CLJ and not CLJS?
(The true answer is a bit more complicated as macros can be written using ClojureScript source, for self-hosting.)
and its expected that doing something like like this will not throw warnings of any kind, correct?
If you define a macro in a *.cljs
file it will essentially generate the macro function and if you try to call it you will find that it won't expand properly. I don't believe that there are currently any compiler diagnostics that get emitted if you do this, but there probably could be. At its root is, that for self-hosted ClojureScript you can define a macro in a file being compiled as ClojureScript.
I'm curious, for devs familiar with other transpile-to-JS languages (Elm, Scala.js, ReasonML): Do any of them sit atop Closure, or do they employ other mechanisms to achieve the same things ClojureScript does (namespace / module system, advanced minification)?
I think most either don’t have the notion of namespacing, or they emulate them with CommonJS modules
Scala.js uses Closure for optimization, not sure if they use Closure lib or modules
I’m running a ClojureScript script on AWS Lambda and my environment variables aren’t coming through; cljs.nodejs.process.env is just {:NODE_ENV “production”}. This seems to be set in the source: var process={env:{}};process.env.NODE_ENV="production";
— although I’m not sure where that’s coming from. Ring any bells to anyone?
(possibly via https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/closure.clj#L2035)
https://github.com/clojure/clojurescript/commit/537f60c975a29983c62647b4ea67b0bc08979366
debugging this was a little crazy because the observed behavior is that AWS Lambda env vars just… don’t work
IMO this is critical so I think it will be looked at soon and included in the next release
@tkjone in Lumo:
cljs.user=> (require '[goog.string :as gstr])
nil
cljs.user=> (require 'goog.string.format)
nil
cljs.user=> (gstr/format "%s" "foo")
"foo"
you can use the same functions in your ClojureScript namespace:
(ns my.ns
(:require [goog.string :as gstr]
goog.string.format)
Not that I am worried about performance at the moment, but do you know if this goog.string.format
would have similar performance considerations as clojures format
method. My knowledge of this is based on this article: http://blog.wjlr.org.uk/2015/01/15/string-interpolation-clojure.html
@tkjone here’s an article that demystifies goog
namespace requiring https://www.martinklepsch.org/posts/requiring-closure-namespaces.html