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 js-obj somehow not there anymore?
new clojurescript gives me lots of undeclared var gobject/set
@leongrapenthin just a regression, fixed in maser
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.
I'd like to get the source as a string so I can send it over the wire.
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
@anmonteiro Thanks! It looks like that goes through vars, and I need anon fns.
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?
pretty sure there’s no way currently that supports that
so short answer is you have to write your own macro
even then seems challenging
may I ask what’s the use case you have in mind?
I'm developing a debugger for complex UI interactions
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)}))
?I think he wants to keep using fn
and I'd like to view the fn source on that debugger
I think that's the only choice though
the only general one at least
wouldn’t work for third-party libraries
I could work with that
is it possible to replace a var in cljs compilation settings somehow?
I'm building via cljs.build.api/build
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
@kevin.lynagh pretty hacky, but I think you can
if you’re using cljs.build.api/build
you can override the fn
macro 🙂
@noisesmith that looks perfect, thanks!
but I think this needs to be before you even load any cljs
namespaces
@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
(fn ^:record-source foo [] ...
also you could emit the sources to some source map type file, and just keep an id for lookup on the fn
that might even make tooling easier actually
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?
@noisesmith I'd like to avoid trying to send source maps over the wire on this
what do you mean by replacing the inputs?
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/core.cljc#L97
(cljs/inputs "src/")
what I’m saying is CLJS imports the fn
macro from Clojure
you can just make a copy of that
(in-ns 'clojure.core)
(defmacro fn ...)
(in-ns 'user)
bashing vars like that makes me nervous
me too 🙂
that it'll end up sneaking into the production build somehow
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
another alternative
and that's what macros are good at
is overriding the analyzer method that analyzes fn*
@noisesmith Good point.
and you can do it conditionally of compiler options so you make sure it doesn’t bloat your prod build
but that’s going to take some work
I'm not very familiar w/ the internal workings of the analyzer --- is this something in cljs, or is this tools.analyzer?
cljs.analyzer
this would be overriding a multimethod?
https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L1713
That's about the same comfort level zone for me as var-bashing.
I didn’t tell you it was going to be easy
I’m just enumerating alternatives
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?
It's not obvious to me how to get a handle on the original source
form
is the source
[_ & args :as form]
by "source" I mean the original string
isn't form
a seq of symbols and stuff?
yeah, now you are probably talking about replacing the reader...
@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
right
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.
Thanks for the help @anmonteiro and @noisesmith!
@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
Thanks for cljs-devtools, by the way!
if we are taking a poll, vim
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
the pattern is probably "does this ns need to define macros?"
clojure.string isn't a namespace that defines macros, so it doesn't need a rename
@noisesmith yeah. Oftentimes a rename is done to avoid a collision of the ClojureScript macros namespace with the existing Clojure namespace
if you read Chinese, help me with this book: https://github.com/clojure-china/cljs-book
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?
In all of my projects, I define two macros for printing:
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 = )
haha that was excellent, Kevin.
I was just going to ask why a macro over a function, but you beat me to it!
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
@tkjone Something like: src/foo/bar/macros.clj
Then in my cljs files: `(ns foo.bar.my-cljs-namespace (:require-macros [foo.bar.macros :refer [p pp]]))`
uh, I don't know how to slack. but you get the idea.
yep, I see what is happening.
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?
(the repo has been dormant for about six months)
@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?
or maybe I just did something weird in general
(The true answer is a bit more complicated as macros can be written using ClojureScript source, for self-hosting.)
cheers!
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)
oooops
@lvh set :process-shim false
in your compiler options
this is the relevant commit
https://github.com/clojure/clojurescript/commit/537f60c975a29983c62647b4ea67b0bc08979366
it’s a new feature and we’re setting the wrong default under Node.js
debugging this was a little crazy because the observed behavior is that AWS Lambda env vars just… don’t work
just attached a patch to that issue
IMO this is critical so I think it will be looked at soon and included in the next release
Does format
exist in clojurescript?
(format "audio[data-key=\"%s\"]" key-code)
@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"
what is Lumo?
a ClojureScript REPL
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
dunno about perf
Any known downside, aside from readability?
not that I’m aware
@tkjone here’s an article that demystifies goog
namespace requiring https://www.martinklepsch.org/posts/requiring-closure-namespaces.html
What is a good way to go about checking if a value is null
in clojurescript?