This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-04
Channels
- # announcements (13)
- # beginners (51)
- # boot (3)
- # calva (10)
- # cider (20)
- # clj-kondo (55)
- # cljs-dev (60)
- # clojure (99)
- # clojure-europe (6)
- # clojure-gamedev (9)
- # clojure-italy (19)
- # clojure-nl (7)
- # clojure-spec (20)
- # clojure-uk (42)
- # clojurescript (96)
- # clojurex (37)
- # clojutre (1)
- # cursive (37)
- # data-science (2)
- # datomic (15)
- # defnpodcast (9)
- # duct (7)
- # emacs (6)
- # events (9)
- # fulcro (124)
- # jackdaw (4)
- # jobs (4)
- # leiningen (9)
- # malli (7)
- # mount (3)
- # off-topic (109)
- # other-languages (8)
- # re-frame (39)
- # reagent (4)
- # reitit (6)
- # remote-jobs (2)
- # rewrite-clj (36)
- # ring (4)
- # shadow-cljs (16)
- # spacemacs (16)
- # tools-deps (91)
- # vim (8)
- # yada (2)
I have an atom that can be set from the console via an ^:export
ed function and a when
clause using that atom:
(when @twilio-log-level
{:logLevel @twilio-log-level})
Now at compile time @twilio-log-level
is nil and so that branch is dead-code-eliminated. I could probably work around this somehow and just get on with it but I’m also curious how other people implement these kinds of debug toggles in production builds?are you sure that is actually DCE'd? last time I checked Closure didn't understand deref/atoms at all and just left them alone?
@martinklepsch I my experience, safest is to use an extra classpath entry which is included only in dev mode, and then call code from it dynamically from behind closure define test, e.g. goog/DEBUG
@martinklepsch as @thheller has said, I'm a bit skeptical
@darwin This is about runtime toggles not compile time so I think classpath/goog-define don’t help
I’m sorry, now I understand what is the problem. I didn’t read it properly. I also don’t believe the code was DCE’d.
I think you’re right and I diagnosed DCE poorly. What I tried before was this and it did behave somewhat unexpectedly:
(def ^:export twilio-log-level nil)
;; ... within a bigger form:
(when twilio-log-level
(js/console.log "asdf")
{:logLevel twilio-log-level})
What happened is that I get
$goog$exportSymbol$$("x.twilio_log_level", null);
but also the when call is compiled as:
$cljs$core$truth_$$(null)
probably a ^boolean
hint would then DCE this code. The intention here was that the var could be set from the JS console but because the externed var isn’t used that plan doesn’t work out.
I found this unexpected for a moment because I expected the compiled code to still use the externed variable.I guess I expected the compiler to emit
$cljs$core$truth_$$(x.twilio_log_level)
or something like thatwhat about exercising setting and restoring the value from your own code? for example as a side-effect of your ns, this would keep it and not DCE’d it
yeah, that’s the workaround. Or using js/x.twilio_log_level
to explicitly get the externed reference
But I thought this was interesting and maybe something that could be discussed, i.e. “Should externed vars always be referenced through their externed name in emitted code?”
1) Exporting only sets up a pointer to the real var, which is subject to the usual minification. (Let’s say you externed a function that is heavily used in your code, you’d usually still want all of those references to be minified)
2) I think the GCC compiler is seeing that nothing changes the value of twilio-log-level
between the time it is established in the code and then used farther down in the text. (Assuming your when
is inside a top-level thing that is evaluated, as opposed to being inside a function definition.) (This is independent of exporting.)
@U04VDQDDY on 2: the when
is inside a multimethod
Ahh, right. It wouldn’t matter if it is top-level or in a fn, or multimethod. Nothing is changing its value, so it gets inlined.
Maybe to get what you want @martinklepsch you would do as before (define an atom, and dereference it in your code), but instead export a special function that can change the value of that atom from JavaScript.
Yeah, that’s what I’m doing now. Still thought it was kind of interesting that the “intuitive way” (by whatever definition) didn’t work
Yeah, the gotcha seems to surround the notion that exported vars are really just pointers, and if you set them, you are making them point at something else. (I don’t think Google’s docs are really clear on this subject.)
is this future-proof? GCC might get smarter over time and understand cljs atoms, and you could end up in the same situation, no?
Maybe they are better phrased as unminified names that are intialized with copies of the minimized name value.
With the atom approach:
(def my-atom (atom nil))
(defn ^:export setit [x] (reset! my-atom x))
(,,, @my-atom)
is this legal clojurescript syntax?
(form.props.stripe.handleCardSetup client_secret)
vs e.g.
(-> (.. form -props -stripe)
(.handleCardSetup client_secret))
(.. form -props -stripe handleCardSetup client_secret)
should work as well I think?
yep
in: (.. form -props -stripe handleCardSetup client_secret)
out: cljs.user.form.props.stripe.handleCardSetup().client_secret();
I have this bookmarked: http://app.klipse.tech/
note that the code it shows will change substantially after optimizations, but it gives you an idea of what the code emitted by the CLJS compiler will be before it goes into the Closure compiler to be optimized and bundled together
Hi. I am getting this error when using cljs on node.js. I guess i need to add XMLHttpRequest as a dependency, but how?
ReferenceError: XMLHttpRequest is not defined
at goog.net.DefaultXmlHttpFactory.createInstance
I there are better suited http/s client libraries to use with nodejs, please let me know
there's probably a CLJS library that abstracts over browser/Node.js but I'm not aware of a specific one
I'm making a small lib that tests for the absence of test assertions. I'm trying to hook into the report
multi-method but somehow nothing happens. I've tried sticking printlns in there, but it didn't work
https://github.com/borkdude/naw/blob/8a4129905fae1b4c51002a28a1706496fc437d35/src/naw/core.cljc#L18
small repro:
ClojureScript 1.10.520
cljs.user=> (require '[clojure.test :as t])
nil
cljs.user=> (defmethod t/report [::default :begin-test-var] [_] (println "hello"))
#object[cljs.core.MultiFn]
cljs.user=> (t/deftest foo)
#'cljs.user/foo
cljs.user=> (t/run-tests)
Testing cljs.user
Ran 1 tests containing 0 assertions.
0 failures, 0 errors.
@borkdude also possible there's a bug? I don't remember if we have tons of tests around the reporting aspect
could be! if anyone wants to help: https://github.com/borkdude/naw
If I want to write a macro just for CLJS that uses a cljs.core
fn, how would I do that?
macros.clj
(ns myapp.backend.macros
(:require [clojure.tools.macro :as macro]))
(defmacro deflambda
[name & body]
(let [[name [bindings & body]] (macro/name-with-attributes name body)]
`(def ~(vary-meta name assoc :export true)
(fn ~bindings
(p-resolve (clj->js ~@body))))))
since the stuff is living in clojure it'll try to resolve clj->js
and won't find it in clojure.core
. so it'll turn it into myapp.backend.macros/clj->js
not quite. the ns-form controls this basically. all the names from clojure.core are just automatically added
But since it’s a macro, it defers execution and uses the full qualified name, so as long as it’s used in cljs, it should be good
now I'm confused. we are using the CLJS compiler which is written in CLJ. but we are not using the CLJ compiler
haha, I just mean, could we not write our macros in pure CLJS if the CLJS compiler (java or self-hosted) did a compilation step?
the self-hosted compiler can do that yes but the minimum size of your build is somewhere around 5mb or so
no :advanced
optimizations for one. also need to keep all the analyzer metadata for compilation