Fork me on GitHub
#clojurescript
<
2020-09-28
>
javahippie06:09:37

I am walking my first babysteps with Clojurescript and have a little issue adapting. For a start, I wanted to write a small frontend for the Hackernews API. The API offers a method to retrieve the IDs of the latest posts, afterwards I can fetch each post with a separate API Call. My current solution looks like this:

javahippie06:09:07

This feels clunky for me, but I am not able to put my finger on it. I am using Rum for the components, so the list of posts reacts on the state change in the atom. The application works, but I am pretty sure that this could be done better.

p-himik07:09:24

I don't see anything wrong with the code. Just a few notes: - You're using the same name response for different things in different functions - post and id are mixed, which makes it a bit harder to understand (i.e. first-posts is actually first-posts-ids) - go uses a thread pool that's limited to 8 threads. Using it for IO may lead to unpleasant consequences in some cases

👍 3
p-himik07:09:23

Or I guess I might be wrong about it - after all, http/get is itself async. I'm not that proficient with clojure.core.async. :)

javahippie08:09:29

I believe http/get is using core.async, I was suprised by this, too, at first, but it makes sense. Thanks for your remarks, you are right about the namings!

javahippie08:09:10

And the linked blog is bookmarked for lunch, thx 😉

Stas Makarov09:09:40

short version: Where should I add namespaces to keywords in API response maps in cljs SPA? And should I do that in the first place or just use unnaspaced keywords (and forget about clojure spec on frontend)? longer version: I'm trying out spec in my small cljs reagent app. I stumbled on a problem that API responses gotten via cljs-ajax doesn't namespace keywords in maps ( https://github.com/JulianBirch/cljs-ajax/blob/master/src/ajax/json.cljc#L33 ) As I understand there's no elegant way to redefine behavior of read-json-native in cljs-ajax (cljs-http too). And the only way to do this is to add namespaces in my app code with something like that:

(map->nsmap {:a 1 :b 2} (create-ns 'my.new.ns))
=> #:my.new.ns{:a 1, :b 2}
;;    
Also I'm considering switch to httpurr, as it gives more control on decoding function. But maybe I'm missing something here? What's your experience of namespaced keywords's usage in cljs apps?

alpox09:09:29

@jehaby I am using cljs-ajax through http-xhrio from re-frame and namespaced keywords worked almost out of the box with these options:

{:http-xhrio {:method :get
                 :response-format (http/json-response-format {:keywords? true})
                 :uri <uri>
                 :on-failure [:common/set-error]}})

Stas Makarov09:09:17

thanks! I'll take a look.

p-himik10:09:26

The solution above doesn't add namespaces by itself. It creates namespaced keywords iff the response has keys like "a/b". I.e. keys that would create namespaced keywords if passed to keyword.

p-himik10:09:44

{:keywords? true} just translates every key with keyword, that's it.

p-himik10:09:38

@jehaby If you want to add your own namespaces, you will have to either transform the received data in your code directly or write your own response handler - just like read-json-native, only with an extra :namespace option or something like that.

vncz15:09:02

Is there a quick and dirty way to see how ClojureScript would compile to JavaScript a regular function without having to set up a full project?

vncz15:09:41

Oh fantastic!

vncz15:09:51

@U2FRKM4TW cljs.core.PersistentVector do you know where are these structures defined in JavaScript?

vncz16:09:06

but that ain't javascript; where are the collections effectively implemented in JavaScript @UEJ5FMR6K?

p-himik16:09:54

Impossible to tell, depends on many factors. You will have to compile a small CLJS file that uses PersistentVector and see what the code is.

vncz16:09:01

That's what I did, and I can't find it. Example:

p-himik16:09:04

What's the example? :)

Cameron16:09:23

I may be misunderstanding you, but I don't believe PersistentVector is defined directly in the source in Javascript, even if the CLJS its defined with will eventually be converted into Javascript -- that's the thing with Clojurescript, it appears to bootstrap as soon as possible, defining what feels like everything in CLJS itself, a lot earlier than Clojure JVM. So unlike Clojure, which defines the PersistentVector while still in Java land, by the time you're defining primitive data types like PersistentVector, CLJS is using CLJS primitives like deftype to define the PersistentVector, and then just requires that deftype and what not are implemented. In fact, as I look at it now, it appears deftype itself may be defined in CLJS (I've spent most of my time with the Clojure compiler, not CLJS, so I want to be careful making any assertions as I look at it without testing it a bit). I'm finding this code here, which appears to be generating the Javascript definition of a particular deftype from CLJS itself:

(defmethod emit* :deftype
  [{:keys [t fields pmasks body protocols]}]
  (let [fields (map munge fields)]
    (emitln "")
    (emitln "/**")
    (emitln "* @constructor")
    (doseq [protocol protocols]
      (emitln " * @implements {" (munge (str protocol)) "}"))
    (emitln "*/")
    (emitln (munge t) " = (function (" (comma-sep fields) "){")
    (doseq [fld fields]
      (emitln "this." fld " = " fld ";"))
    (doseq [[pno pmask] pmasks]
      (emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
    (emitln "});")
    (emit body)))
Based on this, I'd guess the Javascript representing the definition for PersistentVector is going to match what ^ looks like when you start plugging in the definition sent earlier.

vncz21:09:49

Hmm ok understood. I was wondering how these data structures were implemented in JavaScript. All right, thanks!

Cameron16:09:23

I may be misunderstanding you, but I don't believe PersistentVector is defined directly in the source in Javascript, even if the CLJS its defined with will eventually be converted into Javascript -- that's the thing with Clojurescript, it appears to bootstrap as soon as possible, defining what feels like everything in CLJS itself, a lot earlier than Clojure JVM. So unlike Clojure, which defines the PersistentVector while still in Java land, by the time you're defining primitive data types like PersistentVector, CLJS is using CLJS primitives like deftype to define the PersistentVector, and then just requires that deftype and what not are implemented. In fact, as I look at it now, it appears deftype itself may be defined in CLJS (I've spent most of my time with the Clojure compiler, not CLJS, so I want to be careful making any assertions as I look at it without testing it a bit). I'm finding this code here, which appears to be generating the Javascript definition of a particular deftype from CLJS itself:

(defmethod emit* :deftype
  [{:keys [t fields pmasks body protocols]}]
  (let [fields (map munge fields)]
    (emitln "")
    (emitln "/**")
    (emitln "* @constructor")
    (doseq [protocol protocols]
      (emitln " * @implements {" (munge (str protocol)) "}"))
    (emitln "*/")
    (emitln (munge t) " = (function (" (comma-sep fields) "){")
    (doseq [fld fields]
      (emitln "this." fld " = " fld ";"))
    (doseq [[pno pmask] pmasks]
      (emitln "this.cljs$lang$protocol_mask$partition" pno "$ = " pmask ";"))
    (emitln "});")
    (emit body)))
Based on this, I'd guess the Javascript representing the definition for PersistentVector is going to match what ^ looks like when you start plugging in the definition sent earlier.

oliver20:09:18

Hey guys, I'm having a weird problem here and lacking the Node.js-knowledge to solve it, When revisiting a project after a pause of about 3 weeks I was surprised that suddenly shadow-cljs tells me a dependency is missing: The required JS dependency "querystring" is not available, it was required by "node_modules/url/url.js". The module is installed under node_modules however, and npm install --save url succeeds but doesn't change a anything. I might also mention that at first shadow-cljs complained about a missing dependency needed for nodemailer (which is not even used by the frontend part of my app that I'm trying to compile here, but only by the backend which worked just fine) Any ideas on what to do next?

thheller20:09:22

@services npm install shadow-cljs in your project.

✔️ 3
oliver20:09:55

Thank you so much… this probably saved me a lot of time!

oliver20:09:15

Also: Thanks for creating and maintaining shadow-cljs!

🙏 3