This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-10
Channels
- # beginners (50)
- # cider (112)
- # cljs-dev (7)
- # clojure (34)
- # clojure-brasil (1)
- # clojure-greece (4)
- # clojure-italy (8)
- # clojure-nl (14)
- # clojure-russia (4)
- # clojure-uk (94)
- # clojurescript (96)
- # clojutre (5)
- # cloverage (1)
- # cursive (5)
- # datomic (59)
- # docs (53)
- # figwheel (4)
- # fulcro (1)
- # hoplon (1)
- # hyperfiddle (3)
- # jobs (3)
- # luminus (6)
- # nyc (3)
- # off-topic (9)
- # onyx (3)
- # overtone (4)
- # re-frame (2)
- # reagent (16)
- # reitit (9)
- # ring (2)
- # ring-swagger (1)
- # rum (1)
- # shadow-cljs (81)
- # spacemacs (14)
- # specter (12)
- # sql (1)
- # tools-deps (2)
- # vim (110)
Is :require-macros no longer the 'correct' way to get macros, but rather in a require for a name space add :refer-macros [....] to the require??
@jsa-aerial everything desugars to :require-macros
if you want to use it, use it - but there’s little need nowadays
OK - I just was having some issues (probably cockpit errors...) trying to get it to work with Specter, while the :refer-macros just worked
@akond patch for https://dev.clojure.org/jira/browse/CLJS-2812 has landed on master
This effectively lets you extend IPrintWithWriter
to native types
What are peoples thoughts on core.async vs promises? I feel that I like core.async but as soon as you need to handle errors/exceptions it becomes difficult to manage. Promises seem to deal with exceptions in a much nicer way than core.async.
I don’t really follow the “difficult” to manage bit, since you have be very careful with promises to in real programs when it comes to exception handling
Channels would require us to catch the exception in the thread, pass it into the channel and then another check when taking from the channel to see if there was an error. In comparison a promise will need a single check in the thread to catch and invoke the reject callback and expect errors in the .catch
. The .catch
acts like out second check. Plus they bubble up which is handy. I’ve only used core.async a couple times on some simple stuff so there may be a better way to deal with errors
I would say this analysis is not really accurate at least in my own experience wrt. core.async or promises
as far as channels go, yes you have to write a couple of more lines - something like <!?
which throws on errors
in practice I would say this isn’t a big deal - if you have some long async chain or some long promise chain - you have bigger design problems in your program
can someone help me interpret this v1.10.339 compiler error, please? I'm getting java.io.NotSerializableException: cljs.tagged_literals.JSValue
https://paste.ee/p/f1fY3
(my project compiles under v1.10.238 but not 339... I'll try another compiler release...)
I did a git bisect and the first bad commit is https://github.com/clojure/clojurescript/commit/0cdbb23abeeabb36c1ce0a6010890aa97da0fad1 ...but it still makes no sense to me
why is the JSValue not serializable and what is the JSValue?
I realise that the exception is coming out of adzerk.boot-cljs.util/serialize-object... should I take it to the boot channel?
hmmm, I think this may be related: https://github.com/boot-clj/boot-cljs/pull/181 ...but I'm not using spec...
using flyboarder's patch on boot-cljs seems reveal this error "failed compiling constant: cljs.tagged_literals.JSValue@498ba0c9; class cljs.tagged_literals.JSValue is not a valid ClojureScript constant. failed compiling file:/home/corin/.boot/cache/tmp/home/corin/src/b2r/-ghcvds/reagent/debug.cljs" ...I'm still clueless...
@dnolen thanks for the advice. Ill continue to play around with core.async and see how I go.
@caleb.macdonaldblack I'm on the Promises side:
- no library need: works out of the box from figwheel/node repl/lumo
- only does one thing — reifying async computations — and does it well (core.async also handles async rewriting)
- tiny API surface (only constructor, .then, catch)
- easy interop with platforms APIs like fetch, react-native, ...
- Promise.all covers 80% of slightly-more-complicated concurrency needs, at least in the browser
- hits a sweet spot for error handling with .catch
- (-> promise (.then (fn [])))
notation makes it easy to follow the data flow
- macros optional. You can use async/await-like alet macro form the Promesa library (but you may not need it in many caes)
By contrast, core.async strikes me as a power tool for complex async logic and comes with additional cognitive overhead (and usually you're better avoiding async complexity as much as possible). It's also an amazing technical achievement but that doesn't mean it's right for most browser-based apps.
@pesterhazy you don't need to reify an async computation to make it composable
@leonoel maybe? I didn't argue that promises are the only abstraction that makes async computations composable
you didn't, it was just a reminder that asynchronous programming is more complex than "promises or core.async, choose one" 🙂
@leonoel "choose one of these two" is a pretty good practical description of your practical situation in CLJS today
promises support callbacks, with callbacks you can interop with anything you want, I don't really see why we should be in such a status quo
all I'm saying is that if you're dissatisfied with straight callbacks it makes sense to pick an abstraction on top of callbacks, and in that space the salient alternatives are core.async and promises
and this is a recurring problem, a fair amount of traffic on this channel is related to this
sorry, I don't understand your point
my point is just that the two most popular solutions have pros and cons, so both sides should listen to each other and maybe look at alternatives
I think we're on the same page then 🙂
Hello fellow Clojurians, I try to get js routing with secretary working, but it just won’t do. Is someone available who may be able to help out? Don’t want to flood the channel with code samples.
I've been useing react-router lately with great success, throwing ideas if secretary fails. I used secretary in the past, so I guess you'd need to ask a specific question, post pastebin link if it's huge block maybe?
@hlolli Thank you for the response. I’ve created a gist here: https://gist.github.com/MarPenc/bb2311bf534f68c9f785bf5acc3aaff7 — it is from the picture_gallery example out of the book @yogthos has written on web development in Clojure I am through the whole thing, just cannot get this piece to actually react to anything.
Yes, I guess it's a case of react not recognizing the change. The components react to props change or local state change, and I can't see that being changed in your example.
with re-frame it would be easy, but with re-agent, I'd pass in the state or cursor to the router state as parameter, and mutate some ratom on router change.
secratary is good, but this was exacly the problem I had with it, as well as bidy, it's not a react component, so you need to find a way for these two worlds to react to each other.
so yeh, just make the component which are in render, read from a state (ratom), that is being changed by secretary and I think you'll be fine
@hlolli I have to follow up on this, because it turned out, I don’t get it. What do you mean by an ratom that is changed by secretary? I know ratom and I get how to change it. But how do I get secretary to change it?
in your defroutes, do you swap!
any ratoms. Are your defroutes body being called (check with println) when the routing changes? Maybe it's only on initial load, then it would mean the goog.history isn't sending events.
yup, that's actually best practice. I've been useing re-agent longer than the session namespace, so I have different practice 🙂 but let's break it down, does (session/get :page)
change?
you could
(defn page []
[:div
[modal]
[:h1 (str (session/get :page)) ]
[pages (session/get :page)]])
often I do something like this to help me see if it's changeing or not.[:h1 (str "Session: " (session/get :page))]
results in Session:
- so I guess there’s no session here.
;; Quick and dirty history configuration.
(let [h (History.)]
(goog.events/listen h EventType/NAVIGATE #(secretary/dispatch! (.-token %)))
(doto h (.setEnabled true)))
add this to the bottom of your page?from the example, you would need maybe some different require's imports
(ns example
(:require [secretary.core :as secretary :refer-macros [defroute]]
[goog.events :as events]
[goog.history.EventType :as EventType])
(:import goog.History))
just add what gets complained aboutI think, there is something missing in the book. At some point it states that the init!
function shoult look like this:
(defn init! []
(load-interceptors!)
(hook-browser-navigation!)
(mount-components))
But the function (hook-browser-navigation!)
is nowhere to be found so I have it commented out. Maybe that is exactly the missing part.@au-phiware When the compiler reads a JavaScript array or object literal, the result is a JSValue
. Normally this passes through to the compilation stage where the associated JavaScript literal is emitted in the JavaScript being output. But, if you have code like the following example
(let [#js [1] 3])
then the compiler would throw an “Unsupported binding form” exception containing the JSValue
object, and normally this would be displayed as
clojure.lang.ExceptionInfo: Unsupported binding form: cljs.tagged_literals.JSValue@216fea48
...
but if an exception like this needs to be serialized, that’s where I think you encounter the issue.@pesterhazy thanks for your input on promises. I think Im leaning more towards promises for most async problems in cljs. I can see core.async being useful in more complex async problems too. As for my current problem I think promises are the more appropriate solution. Thanks again
@lilactown re: preventing dead-code elimination - what are you actually trying to do? Then maybe something can be suggested.
if you’re just trying to make sure some ns survives so JS code can call it - there is an officially supported way - exporting via goog.exportSymbol
@dnolen I was trying to create a release build of my devcards to deploy and share with non-technical members of my team. the way I have it setup is there's a top-level ns that just require's all of my devcards ns' and calls dc/start-devcards-ui!
because all the devcards ns' just have a bunch of defcard
with no explicit side effect / not being called from other ns, they were being eliminated.
my solution was just to add a (def ^:export keep! "This makes it so that the release build doesn't remove this NS")
¯\(ツ)/¯
@lilactown given this is just for fun then why do you need advanced? simple will suffice no?
@lilactown are you sure its not devcards being compiled out? it has some stuff to ensure they are only available in development usually
yep! the first time I did the release build, the devcards UI came up but only 3 namespaces showed in the UI 😂
turns out they each had a println
in them that was preventing them from being eliminated
@lilactown DCE doesn’t apply to :simple
a single println
doesn't keep anything else from that file alive though so there must be something else going on.
just to double check myself, I went back and deleted or commented out the ^:export
ed variables and it made no change - the namespaces still show up in devcards o_O
did you try :simple
? maybe devcards just don't like :advanced
? maybe @bhauman can clarify if they are supposed to work in :advanced
builds
tried simple before in my initial testing and saw the same behavior, but currently using :advanced
I don't know much about devcards, but I'd think if the top-level ns you mentioned is 'requiring all your devcard ns's' then they shouldn't get DCEd anyway.
hmm, looks like defcard*
doesn't actually def anything in the current namespace actually
trying to :refer :all
(ns some-ns
(:require [another-ns :refer :all]))
And getting "Keyword is not ISeq"
is it not supported or I've made a mistake somewhere?https://stackoverflow.com/questions/12879027/cannot-use-in-clojurescript-repl oh, okay, no :refer :all or :use, explicit only
we forgot to mention there :refer :all case though thanks:)
@brownmoose3q ah yeah, feel free to open up issue on the clojurescript-site - https://github.com/clojure/clojurescript-site
@mfikes, thanks for the background. What about the "failed compiling constant: cljs.tagged_literals.JSValue; class cljs.tagged_literals.JSValue is not a valid ClojureScript constant." that I encountered? Are you familiar with that particular message? In what sort of situation would that arise? (Sorry, I didn't capture the full stack trace of that one... I've had to revert to a working version and move on to more pressing matters)
@au-phiware When a JSValue
makes it through to the compiler and is going to be emitted, it is supposed to be dispatched here https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/compiler.cljc#L393
but something odd in your case (perhaps multiple classloaders?) seems to have caused it to end up in the :default
branch here https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/compiler.cljc#L268
As an aside, we encountered exactly that sort of problem with self-hosted when working on a patch in master recently, and the root cause was an accidental double-loading of the cljs.tagged-literals
namespace, but that would be unrelated to what you are doing with JVM-based ClojureScript / boot, etc.