Fork me on GitHub
#clojurescript
<
2019-05-28
>
Ahmed Hassan07:05:33

How do I hook up ClojureScript script in browser without using inline evaluation?

john13:05:07

@ahmed1hsn What do you mean by "inline evaluation" in this case?

Ahmed Hassan15:05:32

Like adding [:script app.client.init();] script in index.html file which is served initially and init function defined in app/client.cljs as entry point to whole application on client side.

Ahmed Hassan15:05:48

What are the ways to avoid this? Because this is far from best as per Content-Security-Policy.

john15:05:11

Well, in the actual html source, you'll find folks use two different options: 1) including the script source and then calling some main or init function within another script tag, or 2) include the script source and have some function call main or init in that source, such that when it is loaded, it runs

john15:05:25

How would you prefer to include the cljs artifact?

Ahmed Hassan00:05:54

I think second one is better. Init function can be run on initial DOMContentLoaded event. Right? What I'm trying to avoid is first, because you have to allow unsafe-inline directive of Content-Security-Policy. Which makes site vulnerable to XSS attacks as hackers can inject inline scripts in other script tags.

john02:05:45

You'd normally handle that as a separate concern, in the header of the page you're serving.

john02:05:27

That's just one possible example

john02:05:59

If you already have that set and you're getting errors because you're using inline scripts, yeah, you can switch it up to fire main/init on script load.

Ahmed Hassan05:05:14

If we use inline scripts we have to enable unsafe-inline.

Ahmed Hassan05:05:26

Which does not seem safe.

Ahmed Hassan05:05:34

If we evaluate inline script without enabling unsafe-inline option in header it gives error.

john14:05:08

Yeah, Just try calling init from within the script

๐Ÿ‘ 4
RafaMedina13:05:08

Hi all, I'm trying to use a NPM library which return JS/Promises, I've tried many things, Promesa, core.async but always I get: [object Object] is not ISeqable, some clue?

john13:05:44

You may have some fn trying to call seq on the promise

john13:05:12

Many sequence operations call seq on their args

Aaron Fortune13:05:15

Hey I am having a lot of trouble getting the example code from the om.next quickstart working. I keep getting a No protocol method IMapEntry.-key defined for type number: 0 error once I get too the "Changing Queries Over Time" section of the guide. Does anyone have any ideas?

RafaMedina13:05:51

Umh I think no John, well, at least in an explicit way hahha

john13:05:26

@1aaronfortune If I had to guess, there was a change to MapEntries a year or two ago. That quickstart may be affected by that and not updated yet. It looks like it is trying to call key on a number, 0. Are the keys in the map being passed in numbers?

john13:05:04

@comparalf You usually just call (.then p (fn [result] ...

john13:05:09

Have you tried that?

Aaron Fortune13:05:24

@john It looks like it is passing in numbers. I figure I could probably troubleshoot it if I had any idea of what I was doing. Do you know of another place other than the quickstart that I could go to learn om.next.

(defmethod read :animals/list
  [{:keys [state] :as env} key {:keys [start end]}]
  {:value (subvec (:animals/list @state) start end)})

(defui AnimalsList
  static om/IQueryParams
  (params [this]
    {:start 0 :end 10})
  static om/IQuery
  (query [this]
         '[:app/title (:animals/list {:start ?start :end ?end})
           ])
  Object
  (render [this]
    (let [{:keys [app/title animals/list]} (om/props this)]
      (dom/div nil
        (dom/h2 nil title)
        (apply dom/ul nil
          (map
            (fn [[i name]]
              (dom/li nil (str i ". " name)))
            list))))))

Aaron Fortune13:05:26

Thats the offending code. Feel free not to read it. Don't want to force you to take to much time for me. @john

john13:05:59

For starters, I'd recommend passing om.next and going straight to Fulcro. It carries on a lot of the same spirit of om.next, but has a lot of current dev work behind it

Aaron Fortune13:05:01

@john Thanks for the tip I will check it out !

RafaMedina13:05:27

@john Yes, (.then (.login api email pass) (fn [result] (println result))) and the result is the same >Error: [object Promise] is not ISeqable Maybe the JS lib is doing something peculiar inside... in JS, I invoke it with await without problem

john14:05:37

@1aaronfortune Yeah, I don't see anything off the top of my head, just looking at it. It might be the destructuring happening on the return of (om/props this) is calling key but isn't getting a map... but again, I think you'll find more support and action around Fulcro these days.

john14:05:16

@comparalf There is a certain difficulty I've had with trying to interoperate with js written in async/await. Folks say that any async/await code should be translatable into pure promise/then syntax, but I've had a hard time there.

john14:05:52

Not sure if that's your issue

john14:05:39

hmm, not sure what's calling seq in the above code :thinking_face: Hang around a bit though... there's some promise rangers in here every once in a while

Jimmy Miller14:05:32

@comparalf What does (.login api email pass) return?

Jimmy Miller14:05:29

Running (.then (js/Promise.resolve 2) (fn [result] (println result))) does exactly what you'd expect. So it seems to me the problem lies in (.login api email pass). Maybe email or pass are promises accidentally?

RafaMedina14:05:39

@jimmy literally, Promise { <state>: "pending" }, I think no because I can see the request in firefox/console and the response 200 with right user/pass and 400 when they are wrong

Jimmy Miller14:05:01

Okay, replace (.login api email pass) with (js/Promise.resolve {:login-response-here true}). Does the error still occur?

RafaMedina14:05:29

@john Yes, I found many example in internet without success hehehe, and I don't want rewrite that library, I have enough understanding of the clojure syntax / semantic

Roman Liutikov14:05:59

are you sure the promise is not being passed somewhere else? is that the whole code?

๐Ÿ‘ 4
RafaMedina14:05:59

I got lost Jimmy, in JS is api.login(email, pass).. but how will I replace the func call in that? I'm sorry, I have only a week in this world..

RafaMedina14:05:13

@roman01la certainly, it's an impure call inside a re-frame event

RafaMedina14:05:50

`(reg-event-fx :login (fn [{db :db} [_ email pass]] (if (or (string/blank? email) (string/blank? pass)) {:dispatch [:set-error "Required"]} (.then (.login api email pass) (fn [result] (println result))))))`

Roman Liutikov14:05:18

and so the cause is in there

lilactown14:05:57

reg-event-fx is expected to return a map

lilactown14:05:29

(The function you pass in I mean.) So re-frame is trying to access the promise value as a map after it does the request

lilactown14:05:40

Your promise should still println fine

Roman Liutikov14:05:50

sometimes good description of a problem can save lots of time to everyone ๐Ÿ™‚

john14:05:30

@comparalf So what @lilactown is saying is that the return type of your if branch is a promise in the second condition and a map in the first. You could wrap it in a do and pass a map back.

RafaMedina14:05:16

Aahhh oooh hahahaha well.. I tried without reframe and it worked!

lilactown14:05:52

the โ€œproperโ€ way to do this in re-frame is to register an effect and from your event, return that effect key in the map

lilactown14:05:08

(reg-fx :api/login
  (fn [[email pass]]
    (-> (.login api email pass) (.then (fn [result] (println result))))))

(reg-event-fx
 :login
 (fn [{db :db} [_ email pass]]
   (if (or (string/blank? email) (string/blank? pass))
     {:dispatch [:set-error "Required"]}
     {:api/login [email pass]})))

RafaMedina14:05:20

I think I understand the issue, thank you @john

RafaMedina14:05:56

@lilactown in this case, is the proper way because the event causes a "side effect"?

lilactown14:05:01

exactly right

lilactown14:05:48

the reg-event-fx handler has to by synchronous. in order to do the async effect, we use a reg-fx handler

john14:05:49

Though side effecting print lines inline is usually okay in development. Just don't return the results of the side effect.

lilactown14:05:37

inside of the reg-fx handler, in the .then we will usually dispatch another event like :login/success or :login/failure

lilactown14:05:08

(that dispatch would go where you have the println right now)

RafaMedina14:05:56

Great, I understand, I'll modify the code

wonko715:05:15

this is a stupid question but I'm wasting so much time on this: I've got a js object that looks like this in a console.log : [Object: null prototype] {thing: ...} how do I get to what's in thing?

wonko715:05:23

I've tried multiple things with oops' oget, but I keep getting Cannot read property 'prototype' of undefined

wonko715:05:23

(aget obj "thing") works, is there a way of making this work with oget? I'd like to use the soft :?thing ?

thheller15:05:04

don't use aget. just use either (.-thing obj) or (goog.object/get obj "thing")

wonko715:05:00

ok, thanks

Ahmed Hassan17:05:31

On server side Lacinia is great library for GraphQL and similarly Pathom for general Graph query parsing. What is the way to parse Graph queries in client side?

souenzzo18:05:09

@ahmed1hsn I don't know any "cljs graphql framework" But you can use pathom (on client) as a bridge between graphql and EQL https://wilkerlucio.github.io/pathom/#_fulcro_integration

Ahmed Hassan23:05:50

It is both Clojure/ClojureScript library. So, I should also be able to use it on server too??

Ahmed Hassan23:05:47

I have worked with REST APIs, now I'm trying to understand GraphQL and EDN. I tried to work with Fulcro too. I understand fundamentals in it. But I'm struggling with Graph Query Parsing.

Eric Scott23:05:56

Hi - I have a library that I've refactored from a clj file to a cljc (newbie to cljs). I have 3 cljsbuild profiles: dev, test, and min, the last of which uses advanced compilation. My tests all pass, and I'm ready to require this library downstream in a larger project. If I've executed 'lein clean/lein cljsbuild once min/lein install', will that be sufficient for the 'min' build to be the cljs version selected when it's included downstream?