Fork me on GitHub
#clojurescript
<
2017-12-10
>
sova-soars-the-sora00:12:18

How do I access session data from the clientside?

sova-soars-the-sora00:12:41

Is it possible to access ring response map parameters from Clojurescript?

sova-soars-the-sora03:12:08

My solution is to pass ring-level params on the :body key of the response map. Oh yeah. Include it in the body. das rite. can't believe i didn't land on this solution earlier. i feel like i knew it but just kept assuming there was a different way. javascript can access dom elements and therefore including data in the body actually makes sense.

sova-soars-the-sora03:12:58

I just verified this solution. I am extremely happy with the results. My clojurescript application can have immediate access to session variables via :body embedding and I can have SEO without the need to serverside render much.

hagmonk05:12:44

what's the easiest way to inject a CLJS REPL into an existing webpage? I'm trying to debug some JS interop stuff and it would be way quicker to explore with the REPL ...

voltecrus11:12:35

Hello! I have a generic clojure question in regards to building a clojurescipt project - take a look at this function:

(defmethod start-cljs-repl :nrepl
  [_ figwheel-env]
  (try
    (require 'cemerick.piggieback)
    (let [cljs-repl (resolve 'cemerick.piggieback/cljs-repl)
          opts' (:repl-opts figwheel-env)]
      (try
        ;; Piggieback version 0.2+
        (apply cljs-repl figwheel-env (apply concat opts'))
        (catch Exception e
          ;; Piggieback version 0.1.5
          (apply cljs-repl
                 (apply concat
                        (assoc opts'
                               :repl-env figwheel-env))))))
    (catch Exception e
      (let [message "Failed to launch Figwheel CLJS REPL: nREPL connection found but unable to load piggieback.\nPlease install 
        (println message)
        (throw (Exception. message))))))
I have com.cemerick/piggieback specified in my leiningen dependencies. My Java's rusty, but wouldnt that catch any exception? Meaning that even if it is not related to piggieback existing on the load path, it would still report and print that error message?

vemv13:12:57

@voltecrus I'd say yes. catch Throwable e is a bit more generic but in practice it rarely matters

vemv13:12:17

is there anything not working like you'd expect?

voltecrus14:12:18

@vemv that's the thing. I'm trying to setup chromex with figwheel/cider but it seems that i cant get the figwheel properly setup through nrepl because whatever error gets caught there and I became stuck. Decided to look into inferior-clj because everything seem to work if you drop the nrepl/cider combo

Bravi15:12:00

if anyone’s using emacs, how do you connect re-frame app to CIDER? I’m getting loads of errors in cljs 😞 in a freshly generated re-frame template

Bravi15:12:54

it can’t find namespaces whenever I evaluate some piece of code

New To Clojure15:12:27

@bravilogy Too vague to troubleshoot, see response in #cider

zignd18:12:03

i'm using secretary for routing and it's not changing the browser url whenever i use the secretary.core/dispatch! function to change the route

zignd18:12:03

is this how is it supposed to work? in case it is, do you guys have any recommendation on how to change the url whenever i change the route? is it something simply not supported by secretary?

zignd18:12:10

i thought it would be using window.history.pushState internally for that, but it doesn't seem to be

zignd18:12:59

thanks @joelsanchez, it seems to be solution!

joelsanchez18:12:17

glad I could help, I'm using it with bidi and it works flawlessly so far

defndaines18:12:50

(cljs-noob question) I'm trying to get SQLite working with an Electron app, but I cannot seem to figure out how to use it properly. I'm not seeing any successful examples online, so I thought I'd ping here to see if folks can help. I'm using loom as my REPL to test things. Here is a gist of what I'm doing right now: https://gist.github.com/defndaines/58277fb975475ac2f522a2b1f1b849c8 I cannot seem to get past the SQLITE_RANGE: bind or column index out of range error. I'm comfortable with Clojure, but new to CLJS, node, electron, et al.

joelsanchez18:12:50

(clj->js [id]), probably

joelsanchez18:12:51

most likely it's interpreting your [id] as a cljs collection, which is an object in JS land, hence trying to treat it as named parameters (as per the documentation https://github.com/mapbox/node-sqlite3/wiki/API#databaserunsql-param--callback )

noisesmith19:12:02

I think #js[id] would likely be better, but yes

defndaines19:12:09

Thanks, @joelsanchez That does the trick. Is there a reason to favor clj->js over #js, other than bevity?

noisesmith19:12:33

clj->js is fairly complex and tries to do a recursive transform

joelsanchez19:12:36

I favor clj->js because #js only transforms one level

noisesmith19:12:57

see - I prefer #js because I always want the weaker tool

zignd19:12:35

is there a function named #js? i couldn't invoke it

joelsanchez19:12:40

it's a reader macro

noisesmith19:12:17

tl;dr thepeople that wrote clj->js are skeptical of it and think you should avoid using it whenever possible

noisesmith19:12:02

dnolen 16:08:12
clj-&gt;js is just convenience - it performs terribly and has many corner cases

joelsanchez19:12:54

interesting! thanks

hagmonk20:12:14

is it possible take a cljs form and, from the repl, emit the unoptimized js it will compile to?

mfikes21:12:52

@hagmonk There are at least 3 ways to do this. • You can enable :repl-verbose See https://clojurescript.org/reference/repl-options#repl-verbose More on that option here http://blog.fikesfarm.com/posts/2015-06-15-see-js-in-cljs-repl.html For quick tests, lumo -v or planck -v is probably the quickest way to achieve this. • If you don't want to restart your REPL, (set! *print-fn-bodies* true) and then evaluate the form you want in a function literal like (fn [] (+ 2 3)) • Use the self-hosted compiler at the REPL and compile the string form: (require 'cljs.js) and then (cljs.js/compile-str (cljs.js/empty-state) "(+ 1 2)" nil {:eval cljs.js/js-eval :context :expr} identity)

mfikes21:12:28

The 2nd way is the way you want to go if your form depends on your REPL environment.

mfikes21:12:35

@defndaines In addition to the inherent function call, (clj->js [1]) compiles to fairly verbose (unoptimized) JavaScript:

cljs.core.clj__GT_js.call(null,new cljs.core.PersistentVector(null, 1, 5, cljs.core.PersistentVector.EMPTY_NODE, [(1)], null))
while #js [1] compiles directly to a JavaScript array:
[(1)]

mfikes21:12:02

If, at runtime, you have a persistent data structure you'd like to convert to JavaScript, clj->js is cool, but if you essentially have a compile-time literal, #js is arguably better.

mfikes21:12:33

If performance is critical at the point you are doing the interop, here is a relevant post, covering both directions: http://blog.fikesfarm.com/posts/2017-11-09-avoid-converting-javascript-objects.html

hlolli21:12:16

Bit struggling with equality checks on deftypes

(deftype AudioSignal [val])
(let [a AudioSignal
      b (AudioSignal. 1)]
  (case a
    AudioSignal (prn "yo")
    (prn "no"))
  (case (type b)
    AudioSignal (prn "yo")
    (prn "no")))
This prints "no" "no", I'd expect here "yo" "yo". I guess IEquiv (-equiv [b] ... needs to be in the implementation, or ?

hlolli21:12:20

On the other hand, this returns true (= AudioSignal AudioSignal) => true

mfikes21:12:31

@hlolli Consider the behavior of this: (let [a 'AudioSignal] (case a AudioSignal :y :n))

hlolli21:12:09

hmm ok, this succeeds

mfikes21:12:35

The case test constant for that example is a symbol.

hlolli21:12:14

I wonder how that quote tesest against when the compiler adds the namespace in front of the typename.

mfikes21:12:26

(See the last paragraph of the docstring for case.)

hlolli21:12:24

`The test-constants are not evaluated. They must be compile-time literals, and need not be quoted.` lol ok

mfikes21:12:26

In fact @hlolli (let [a 'AudioSignal] (case a AudioSignal :y :n)) has nothing to do with your deftype. It is just testing symbol equality

hlolli21:12:26

yes I see, the errors I was getting at one point were

No matching clause: function (val){
this.val = val;
}

hlolli21:12:54

so ok, I didn't know this about case, never tripped on this before

mfikes22:12:05

@hlolli There is a quirk in ClojureScript, related to ^:consst, to be aware of, which was probably a mistake and doesn't work in Clojure. More about that here: http://blog.fikesfarm.com/posts/2015-06-15-clojurescript-case-constants.html

mfikes22:12:01

@hlolli Knowing this, perhaps this is what you want:

(deftype AudioSignal [val])
(let [a AudioSignal
      b (AudioSignal. 1)]
  (condp = a
    AudioSignal (prn "yo")
    (prn "no"))
  (condp = (type b)
    AudioSignal (prn "yo")
    (prn "no")))

mfikes22:12:57

(In short condp = for "runtime", case for "compile-time" might be the best way to look at that.)

hlolli22:12:33

hmm, yes, I guess I'll go trought the booleans again a bit. But case seems more "extreme" macro than cond family.

hlolli22:12:13

knowing it becomes js switch then it makes sense.

joelsanchez22:12:31

another possibility, other than condp =, is to simply use a map

mfikes22:12:01

case is awesome for two reasons, IMHO: 1) It is very easy to read when the tests are compile-time constants. 2) You get constant-time dispatch. In other words O (1) instead of O (n)

hlolli22:12:43

yup, in my case I'd go for symbol quoting, have many types I made for a transpiler. But I'm on new terretory, experimenting with stuff I didn't test before..

mfikes22:12:30

Wow, assuming these benchmarks are valid, if you want to do a mapping in code where the mapping is known at compile-time, it looks like case is a lot faster than using a map literal, with these speedups V8: 30, SpiderMonkey: 18, JavaScriptCore: 42. (This means 18 to 42 times faster, under :advanced)

(defn lookup-using-map-literal [k]
  ({:a 1 :b 2} k 3))

(defn lookup-using-case [k]
  (case k :a 1 :b 2 3))

(simple-benchmark [f lookup-using-map-literal] (f :a) 1e8)
(simple-benchmark [f lookup-using-case] (f :a) 1e8)

hagmonk23:12:19

@mfikes thanks for that! just catching up on your comments now