This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-03-02
Channels
- # aleph (1)
- # announcements (1)
- # babashka (4)
- # beginners (89)
- # calva (3)
- # chlorine-clover (18)
- # cider (33)
- # clj-kondo (27)
- # cljdoc (4)
- # cljsrn (2)
- # clojure (248)
- # clojure-europe (7)
- # clojure-italy (15)
- # clojure-nl (7)
- # clojure-norway (10)
- # clojure-poland (1)
- # clojure-spec (12)
- # clojure-sweden (5)
- # clojure-uk (57)
- # clojured (4)
- # clojuredesign-podcast (1)
- # clojurescript (55)
- # core-async (14)
- # core-logic (3)
- # cursive (10)
- # datomic (38)
- # figwheel-main (8)
- # fulcro (23)
- # graalvm (126)
- # hoplon (59)
- # jobs (1)
- # kaocha (3)
- # malli (30)
- # meander (17)
- # off-topic (32)
- # pathom (19)
- # pedestal (4)
- # re-frame (12)
- # reagent (2)
- # reitit (3)
- # shadow-cljs (81)
- # sql (9)
- # tools-deps (34)
- # vim (20)
- # vscode (7)
- # xtdb (5)
ran into an externs issue of vars getting munged when upgrading cljs and migrating over to shadow-cljs that I was hoping someone could help shed light on: the js file is pulled in as an external script src. i had an externs file that looked like:
var Foo = {
data: {
Bar: {
width: 1,
height: 1
}
}
}
and
(fn [evt]
(when (and (.-data evt) (.-Bar (.-data evt)))
... ))
this used to work with cljs 1.7/figwheel, but migrating to cljs 1.10/shadow-cljs breaks it. two ways to fix have been:
1. prefixing with ^js (`(fn [^js evt]`)
2. changing the top level variable from Foo to evt
anyone have insight into why this breaks? is it because var Foo
is equivalent to js/Foo in a global context and js/Foo is what is being expected here?prefixing with ^js
is the correct way to do this. if you do you don't need any additional manual externs.
@U05224H0W Should the above example work with just ^js evt
? Or should it also specify ^js (.-data evt)
to make sure that .-Bar
is not mangled?
Huh. But does that mean that I cannot really put anything that must get mangled inside the objects that must not get mangled? E.g. when passing your own objects into some thirdparty JS library.
Ah, right. I guess I could come up with some example where you put a CLJS object into a JS object and then attempt to access an internal JS field from the CLJS object. But that's probably contrived beyond being even remotely useful.
No, I mean something like #js {:js_field some-cljs-object}
.
:js_field
will not be renamed. If you pass it somewhere else, especially from a thirdparty JS library, you should use ^js
.
But the transpiled code of some-cljs-object
will contain renamed fields.
Suppose it must have a property called stuff
. Without optimizations I can just get it via (.. js-obj -js_field -stuff)
. With optimizations, I have to mark js-obj
with ^js
but I may no longer access the -stuff
part since it was renamed, as all CLJS code usually goes through advanced optimizations.
no matter where -stuff
is from ... as long as it was part of the :advanced
compilation it will NOT be renamed since the ^js
caused it to generate externs for stuff
> no matter where -stuff
is from
Oh... So if I write something like (defn f [^js x] (.-meta ))
then cljs.core.PersistentArrayMap.meta
will not be renamed as well, even though x
has nothing to do with cljs.core.PersistentArrayMap
?
we really want the property renaming for the long protocol properties CLJS generates
That's good. It's just that I was thinking that it did some type inference clever enough to not mix fields with the same names from different areas together.
as soon as it finds one untyped reference to -stuff
it won't rename -stuff
at all anywhere
Yeah, I see. > CLJS is untyped Type inference is still possible though. But probably immensely complicated. And given what you said, it's probably not worth it.
(:foo bar)
is the most common casse in CLJS code .. that is rarely typed or inferenced
I used to worry about this but after extensive tests in my works projects it barely ever made a difference of more than 1%
thanks. my curiosity was around whether anyone knew what the source of the regression of the behavior was. the given extern used to prevent .-Bar and .-data from being munged, even though Foo wasn't referred to directly. i assume it's due to some change in the closure compiler. moving forward, ill switch to using ^js
in these situations. thanks.
turn on externs inference so you catch those things early https://shadow-cljs.github.io/docs/UsersGuide.html#infer-externs
this is a really great writeup that a Chrome engineer did about moving work from the main thread to a web worker: https://docs.google.com/document/d/1nu0EcVNC3jtmUVWL8Gs5eCj2p_984kamNhG2nS9gOC0/edit#heading=h.e6n21l1n04rc
FWIW the new shadow-cljs UI uses approach #2 and it works ok but is hardly worth the more complicated setup overall. same conclusion they came too I guess.
interesting. do you think that having better APIs/abstractions on top of web workers would tip the equation to being more worth it?
I imagine something like apollo or datascript being a decent abstraction over something that talks to a web worker. but I don’t know what the packaging / deployment complications are, which might be difficult to abstract over
so in the case of clojurescript, that especially bites since you need to load all of clojure.core etc.
my framework hides the async stuff fairly well but it can still be annoying when all your data access is async