This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-25
Channels
- # anglican (2)
- # babashka (53)
- # beginners (99)
- # brompton (1)
- # calva (28)
- # circleci (43)
- # clj-commons (4)
- # clj-kondo (176)
- # cljsrn (22)
- # clojars (7)
- # clojure (175)
- # clojure-australia (2)
- # clojure-europe (20)
- # clojure-germany (1)
- # clojure-uk (5)
- # clojurescript (195)
- # cursive (18)
- # datomic (13)
- # emacs (2)
- # farolero (9)
- # find-my-lib (6)
- # fulcro (8)
- # graalvm (12)
- # gratitude (5)
- # helix (11)
- # improve-getting-started (36)
- # introduce-yourself (3)
- # jackdaw (21)
- # jobs (2)
- # joker (2)
- # malli (65)
- # meander (24)
- # nbb (2)
- # off-topic (4)
- # pathom (2)
- # polylith (17)
- # portal (5)
- # react (3)
- # reagent (22)
- # releases (1)
- # ring (4)
- # shadow-cljs (79)
- # show-and-tell (2)
- # testing (5)
- # tools-deps (9)
- # xtdb (12)
A user of tools.cli
on ClojureScript just tripped over this difference from Clojure -- is this a known issue? Is it considered a bug?
ClojureScript 1.10.758
cljs.user=> (hash-map :a)
{}
cljs.user=> (apply hash-map [:a])
{:a nil}
Both of those raise exceptions in Clojure -- and they don't even seem consistent with each other in ClojureScript.(they had a named argument without a value -- which is an error in Clojure but slightly behaved in ClojureScript as if the named argument had the value nil
)
Does someone know where i can find this pulsating hint component: I have often seen it in getting started guides and i suspect it is a OTS component.
It's relatively easy to implement with just CSS, no need for some components at all. For example: https://findbootstrapsnippets.com/bootstrap-templates/ripple-dot-animation.html
for reference. I might look into using this: https://ant.design/components/badge/# with :status "processing"
As long as you're aware of the potential consequences of using just a single component from a huge UI library. :)
That can very well be a problem. It all depends on how much that component uses and how you import it. Advanced compilation is not a wizard - DCE is rather limited in its abilities.
Personally, I wouldn't even try using some library for just that tiny dot. I'd copy the CSS and be done with it. Apart from giving me a guarantee that it will remain tiny, forever, it also gives me an ability to customize it in absolutely any way. But if you really want to use some component, make sure to analyze the resulting bundle size (at least shadow-cljs is able to provide you with the details) and see how bad it is.
Actually I agree that it is quite ridiculous to use a component in this case. But another very relevant topic is bundle size: ā¢ when I run a prod build on shadow-cljs it doesn't show this message. but shows it in dev builds. So i think it works. ā¢ But what tool in shadowcljs are you referring to? the 13.4 build report? (see image)
> when I run a prod build on shadow-cljs it doesn't show this message. but shows it in dev builds What message?
Hm so I have an ancient clj library that predates cljs and I'm thinking of implementing the same functionality in cljs. What would be a good way to publish that as a library? It needs JS dependencies. The app I want to use it with is using shadow-cljs but uh I basically have no idea how cljs+js+clojars works.
I wrote about this topic here https://widdindustries.com/cljs-npm-libraries/
huh I was trying to see a full example but https://github.com/henryw374/cljs.java-time/blob/master/deps.edn doesn't contain any npm
But it basically mirrors what david said I think https://clojurians.slack.com/archives/C03S1L9DN/p1629895641082600
well... no. there's quite a bit of detail that's not documented anywhere else. also there's choices wrt npm-deps, cljsjs etc that is discussed
https://clojurians.slack.com/archives/C03S1L9DN/p1629965814002900?thread_ts=1629892957.080800&cid=C03S1L9DN that's deps.edn, for cljs js dpes, there's also deps.cljs, a different thing
@pepijndevos publishing CLJS is the same as CLJ more or less
deps.cljs
in the JAR can declare :npm-deps
which is used to determine deps from NPM
Hey all, trying to use the materialdesignicon (mdi) library for icons.. it's basically a ton of exported vars with svg attached like mdiAccountCircle, is there a way to import without naming each individual icon? I've tried [:require "@mdi/js" :as "mdi" then calling mdi/mdiAccountCircle but no luck so far.
Hmm I think I sorted it by not including the name I :as'd to. [:> Icon {:path "mdiAccountCircle"}] worked just fine with my :as mdi
Note that importing all the icons will increase your bundle size, even the release one.
Hmm a good point, I guess the bundle size restriction would be worth the super gangly import (we use like 30-40 icons on various bits of global nav
Ok, a bit of refactoring later and I did need to add the :as, e.g. mdi/mdiAccountCircle ... I'm trying to abstract it to just require the mdiAccountCircle as a string, I tried to call it using (symbol "mdi" "mdiAccountCircle") but I don't think its resolving.. what do I need to call on a symbol to resolve it from an import?
mdi
will be a JS object - you will be able to access mdiAccountCircle
via regular JS interop.
I'm struggling with this a bit.. the only thing I can get to work is [:> Icon {:path mdi/mdiAccountCircle}], cannot figure out how to replcea the mdiAccountCircle piece with an arbitrary string
You should be able to replace mdi/mdiAccountCircle
with (goog.object/get mdi "mdiAccountCircle")
.
thanks @p-himik .. I was trying all sorts of dots and dashes .. I felt like I was trying to fake morse code
Hi all, this might be an easy question but I couldnāt find an answer. Is there a way to convert integers to doubles (with decimal) in ClojureScript? Simply Iād do (double 1.0) => 1.0 in clojure to get the value but in cljs I get (double 1.0) => 1 which is causing me issues when I try to validate input in backend.
Thanks for the quick reply but Iām still a bit confused. Letās say I want to call my endpoint with {:value (- 5.00 1.00)}
and on server side I validate schema by saying value should be double. value
I sent gets converted (after the - calculation) to 4 instead of 4.00 which will cause exception. How would you go for it or am I missing something?
Not sure exactlyā¦ what is in the request to the server? E.g. what is in the request in Chromeās network tab
["^ ","~:endHeight",12,"~:endX",152.9246,"~:type","Text","~:startHeight",12,"~:startPage",2,"~:endY",332.625,"~:startX",54,"~:startY",332.625,"~:endPage",2,"~:text","Some example text here"]
This is a transit request body taken from the Chrome Network tab which Iām trying to send startX value as double, but I cannot send it as 54.0
which our backend expects it to be a double and gives exception.
This is the request body we passed to cljs-ajax:
{:type "Text"
:text text
:startX (double (:x start-position))
:startY (double (:y start-position))
:startHeight (double (:height start-position))
:endX (double (:x end-position))
:endY (double (:y end-position))
:endHeight (double (:height end-position))
:startPage start-page-number
:endPage end-page-number}
I would probably coerce before validating. AFAIK there is no way to ensure itās represented as a double in js
As an alternative, change the backend so the relevant functionality accepts not only doubles but also longs.
> valueĀ I sent gets converted (after the - calculation) to 4 instead of 4.00
This statement is false. 4.00 does not get converted to 4. They are exactly identical. There is no 4
integral value in javascript
Taken from core.cljs
(defn ^number short [x] x)
(defn ^number float [x] x)
(defn ^number double [x] x)
Seems like clojurescript doesnāt do anything with double
function which confused me in the first place. Iām guessing it is related to number handling in js world as you all said. Thanks for answers and your time.@p-himik we already diverted to that path I wanted to see if there is any other way š
If there was anything to be done in the client, it would be done in your serialization code. Not by doing any sort of conversion on the value.
Thanks David!
@esezgin2000 there are no integers in JavaScript. What you are seeing is simply how JavaScript prints values. You probably want to format then.
["^ ","~:endHeight",12,"~:endX",152.9246,"~:type","Text","~:startHeight",12,"~:startPage",2,"~:endY",332.625,"~:startX",54,"~:startY",332.625,"~:endPage",2,"~:text","Some example text here"]
This is a transit request body taken from the Chrome Network tab which Iām trying to send startX value as double, but I cannot send it as 54.0
which our backend expects it to be a double and gives exception.
This is the request body we passed to cljs-ajax:
{:type "Text"
:text text
:startX (double (:x start-position))
:startY (double (:y start-position))
:startHeight (double (:height start-position))
:endX (double (:x end-position))
:endY (double (:y end-position))
:endHeight (double (:height end-position))
:startPage start-page-number
:endPage end-page-number}
Taken from core.cljs
(defn ^number short [x] x)
(defn ^number float [x] x)
(defn ^number double [x] x)
Seems like clojurescript doesnāt do anything with double
function which confused me in the first place. Iām guessing it is related to number handling in js world as you all said. Thanks for answers and your time.back when I worked on transit-js at Cognitect - it was decided for transport, integers were probably the more common case for typical client to backend - that's debatable - but that's what we went with
just define your own tagged type - wrap your JS numbers in it, and then you will get what you want on the other side provided you have corresponding read handler
Thanks for the detailed answer, after reading your messages I read the source code for the transit conversion where I believe this is implemented. It gave me a good insight for how it works.
Welp somehow the very first thing I try in cljs.core.async blows up spectactularly
(defn pouch-swap! [db key f & args]
(go-loop [r (<p! (.get db key))]
(try
(<p! (.put db (apply f r args)))
(catch js/Error err
(recur (<p! (.get db key)))))))
What?
IllegalArgumentException: No implementation of method: :emit-instruction of protocol: #'cljs.core.async.impl.ioc-macros/IEmittableInstruction found for class: cljs.core.async.impl.ioc_macros.Jmp
@pepijndevos you cannot recur across try
Hm so how do I work around that?
one possible solution
(defn pouch-swap! [db key f & args]
(go-loop []
(let [r (<p! (.get db key))
[result ex] (try
[(<p! (.put db (apply f r args)))]
(catch js/Error ex
[nil ex]))]
(if ex
(recur)
result))))
Lift the recur
from try
, make it conditional upon one of the two values returned from try
(the regular result and the error result).
worth a ticket for a better error message?
I can never figure out where the type hint goes when the compiler complains.
(.-status (.-cause res))
I've tried spamming ^js
everywhere but it keeps saying `Cannot infer target type in expression (. inst_37262 -cause)`It also plain doesn't work. If I make rest a global variable in the firefox console temp1.cause.status
gives 409
but apparently that code does not...
I've tried ^js (.-status ^js (.-cause ^js res))
and still nothing
99% but everything is so fucked up right now I have no idea what's going on. It's the only -cause
in the whole code, but it's in a go
block so maybe that's doing funky stuff.
what the hell
Instead, extract that getting operation in a function with a proper hint and call that function in the go
block.
:face_palm:
A go
block is a macro that heavily transforms the code within it. It just isn't written in a way that would preserve that metadata (not sure if it's possible to write it in such a way at all).
Ok yea that did the trick
Superficially, seems to work just fine:
cljs.user=> (a/go (js/console.log (a/<! (a/go #js {:a 1}))))
#object[cljs.core.async.impl.channels.ManyToManyChannel]
cljs.user=> { a: 1 }
I can't remember now, but it's something with var access....
(def a 1)
(defn ...
(let [a 2]
(go #js {:a a})))
Maybe you need a <! in some place too.cljs.core.async
go
block definitely has many old issues - it was never brought in line with Clojure impl
the js literal thing is the killer one - that's definitely next on my list when I have time for core.async stuff
unfortunately unlike the years old and/or
bug which was finally fixed, this requires actually tweaking core.async
Eh... how broken is this go block?
(defn pouch-swap! [db key f]
(go-loop []
(let [old (js->clj (<p! (.get db key)))
new (f old)
res (try
(<p! (.put db (clj->js new)))
(catch js/Object err err))]
(if (instance? js/Error res)
(if (= 409 (errorcode res))
(recur)
(throw res))
[old new]))))
Gives
Uncaught Error: Invalid arity: 7
call core.cljs:6851
switch__29505__auto__ hipflask.cljs:11
ret_value__29507__auto__ hipflask.cljs:11
[...]
Where the core.cljs line points to
(deftype PersistentArrayMap [meta cnt arr ^:mutable __hash]
What the hell?In CLJS projects do you folks typically run tests with both optimizations none and advanced or only the latter?
@pepijndevos you probably want (catch :default ...)
Apart from :default
, don't use the word new
- that's the thing that messes the above code.
@pepijndevos you're also throwing from async code which is meaningless
ahh new
messed it up apparently ok wft haha
Uh so what do you do with the error? Just log it and pretend all is good?
with core.async you should probably return the error as the value of channel - (in the above case exit the loop and return the error value for somebody do something about it - if something can be done)
Is there a good way to have an optional dependency in cljs? Like in clojure I can do the following:
(try (require '[some.ns :as a])
(do stuff)
(catch Exception _))
And with that it'll do the stuff iff the library some.ns is available, and will do nothing if it isn't. Is there something I can do in cljs that's equivalent?@suskeyhose it is not possible
Why do these produce different result?
cljs.user=> (macroexpand '(js/Number.))
(new js/Number)
cljs.user=> (macroexpand '(do (js/Number.)))
(do (js/Number.))
Ah, that's frustrating. I guess this has to be a clj-only feature in my library for now.
I thought macroexpand
was recursive, but only expanded macros that are at the call position of the top-most list.
It's these sorts of things that make me wish that the clojure cli and deps.edn had a way of resolving dependencies with aliases applied from the dependency map, that way we could more or less have feature flags like in rust.
Especially if it were paired with an "optional require" syntax, where it'd require a namespace if it is available, but wouldn't error if it isn't.
@dnolen Any chance we'll see clojure.walk/macroexpand-all
in CLJS? Got a bit confused by its absence.
@pepijndevos @dnolen And seems like that issue with new
is indeed a bug with go
:
(let [new 1] (js/Number.))
after compilation =>
var new_35 = (1);
(new Number());
whereas
(a/go (let [new 1] (js/Number.)))
after compilation (abridged) =>
[...]
var inst_36 = (1).call(null,Number);
[...]
So in a regular let
the new
gets replaced with new_35
. But in a let
within a go
, it's not replaced, making it possible to shadow it.right there's lot of stuff like this because cljs.core.async
doesn't use any analyzer lib
it would mostly be mechanical - since it has been done once already with tools.analyzer
for Clojure
that could be adapted - but of course it will be slow going to get all the tests to pass etc.
is there a good document that shows how to hack on the compiler? Just quality of life things like some function that takes a string of clojurescript and returns (or even prints) the compiled js code? I remember seemingly simple things like this were surprisingly difficult to find for me last time.
no document - but there are lot of tests that show exactly how to do stuff like that
tests for externs inference, and/or optimization, etc. all need to compile some form as data and check the output for something
probably not that well known but even the build function takes forms and can generate a string
Hello there! I'd like to ask for guidance to set up a repository for a new library I'm developing. Requirements: - It's meant to target CLJS, hence why I'm posting here - If possible, I would prefer to use deps.edn instead of lein or shadow-cljs - The setup should include tests and examples (ClojureDocs or similar are a plus) How should I set up the repository? How to build and package? Can I host in clojars and are there better alternatives? Any guides or tutorials are welcome! I'm most comfortable with Clojure, having limited Clojurescript experience.
in terms of building and packaging and publishing to clojars, all you need to do is publish a JAR with your clojurescript source code in it
for running tests, kaocha makes it pretty easy to do that from the CLI and in a CI environment
i think i remember the most trouble was figuring out how to get the correct initialized environment.
@dpsutton right the tests how to do all that too - it is annoying for sure and become more so over time mostly due to externs inference
@dpsutton https://github.com/clojure/clojurescript/blob/master/src/test/clojure/cljs/analyzer_pass_tests.clj
oh nice. that's quite helpful. I think it would be kinda fun to try this. Might apply for the clojurists together bit
it does take some time to get familiar with - but honestly I do not think it is particularly challenging
again you have many tests to look at - the new passes stuff would also be useful when hacking
in the case of core.async
I'm pretty sure you're just messing around w/ the AST - you don't need to concern yourself with much else
I believe I fixed the last issue with tools.analyzer rep conformance when I did the and/or stuff
Hi, I would like to use a material web component in my reagent app, specifically the mwc-button (https://github.com/material-components/material-web/tree/master/packages/button). Any idea?
https://github.com/reagent-project/reagent/blob/master/doc/examples/material-ui.md
unfortunately this is the web component (mwc-button) that I need, not the react component for material UI
for the react material ui there is: https://github.com/arttuka/reagent-material-ui
Re, yesterday's convo on ESM style imports + the new dollar sign in CLJS. I just tried this with the nodejs chalk library to stay close to their README example, and with #nbb it just worked :)
(ns script
(:require ["chalk$default" :as chalk]
["console$log" :as log]))
;; Combine styled and normal strings
(log (chalk/blue "hello") (str " world" (chalk/red "!")))
please note that :as
is meant to be an alias, if you are calling it directly you likely should be using :refer
(eg. (:require ["console" :refer (log)])
)
also note that there is no such thing as ESM style imports. "$"
works for any JS and is not related to ESM in any way. literally all it does is append the suffix to the thing you imported
Good points. The dollar is probably just more ubiquitous because of the ādefaultā thing with ESM
yeah its syntax sugar since ["chalk" :as chalk]
and (chalk/default.blue "hello")
kinda sucks, as does ["chalk" :rename {default chalk}]
(.. chalk (blue "hello"))
even ["chalk" :default chalk]
and (.. chalk (blue "hello"))
kinda sucks so the "$"
setting up any :as
alias is nicer.
does anyone know if there is a tool like the following for clojurescript: https://github.com/gfredericks/clj-usage-graph ??
both these tools leverage kondo: https://github.com/SevereOverfl0w/vizns https://github.com/benedekfazekas/morpheus
@U04V15CAJ thanks, i'll look into that
Does cljs have like a drop trait? Basically I made a deftype constructor that registers an event handler that calls methods on the deftype, the problem is this event handler leaks the deftype. So somehow I need to cancel the event handler when the deftype is freed.
Not sure I understand. What do you mean by "when the deftype is freed"? Shouldn't it be the reverse - you detach the event handler, and it no longer holds a reference to an instance of the deftype?
Exactly, so you hold on to the reference to p
in that .on "change"
. Remove the handler - and the reference should be freed as well.
Yea so then you manually have to cancel the handler when you're done with the PAtom.
I was hoping there is a way to have like a "weak" reference to the PAtom, and then cancel the event handler when the PAtom goes out of scope.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef hmmmmm
WeakMap/WeakRef and finalizers have only been in the spec for a couple years. previous to that you had no real way to do this in a JS context
(defn patom [db key]
(let [p (PAtom. db key nil nil)
wp (js/WeakRef. p)
ch (.changes db #js{:since "now"
:live true
:include_docs true
:doc_ids #js[key]})]
(.on ch "change" (fn [change]
(if-let [myp (.deref wp)]
(-notify-watches myp nil (js->clj (.-doc change)))
(.cancel ch))))
p))
Still doesn't work.(defn watch-changes [db key wp]
(let [ch (.changes db #js{:since "now"
:live true
:include_docs true
:doc_ids #js[key]})]
(.on ch "change" (fn [change]
(if-let [myp (.deref wp)]
(-notify-watches myp nil (js->clj (.-doc change)))
(.cancel ch))))))
(defn patom [db key]
(let [p (PAtom. db key nil nil nil)]
(set! (.-changes p) (watch-changes db key (js/WeakRef. p)))
p))
If I do this... well, without the set!
it doesn't trigger at all, and with the set!
the callback and PAtom never gets freed.So it seems there is REEEEAALLY sneaky stuff going on with closures holding on to stuff or not.
that looks right. I don't know how you would reason that p
never gets freed because of set!
I figured if I broke out the watch-changes function it would not hold on to the patom closure, which... maybe worked?
you don't get any guarantees about when or even if p
gets freed, only that it eventually might, and if it does it will cancel the change listener
Well so without the set, it never works in the first place.
ah no... works... but now big question is... will it ever get cancelled.
otherwise you're relying on the GC, which may decide to reclaim it immediately or never
Yea I mean, I don't care when it does it... I just want to verify it'll do so before my ram explodes.
Is there a way to see what is referencing an object?
don't think so. at least in chrome. maybe the firefox or safari devtools have something.
Yesterday late at night I was experimenting a bit with just making several thousand listeners and seeing what happened. I got mixed results of CPU spikes followed by what seemed to be reclamation, or just hanging the browser entirely. I'll have to try that some more.
In Firefox I could not really find a memory profiler. It can just take snapshots, or profile CPU.