This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-11
Channels
- # announcements (4)
- # aws (6)
- # babashka (40)
- # beginners (318)
- # biff (4)
- # bootstrapped-cljs (9)
- # calva (19)
- # chlorine-clover (1)
- # cider (3)
- # clj-on-windows (25)
- # cljdoc (8)
- # cljfx (1)
- # cljs-dev (30)
- # cljss (2)
- # clojure (62)
- # clojure-chile (9)
- # clojure-europe (11)
- # clojure-finland (17)
- # clojure-italy (1)
- # clojure-kc (1)
- # clojure-nl (3)
- # clojure-spec (27)
- # clojure-uk (40)
- # clojuremn (1)
- # clojurescript (51)
- # conjure (6)
- # cursive (8)
- # data-science (9)
- # datahike (4)
- # datascript (1)
- # datomic (31)
- # emacs (10)
- # emotion-cljs (1)
- # events (1)
- # figwheel-main (16)
- # find-my-lib (1)
- # fulcro (30)
- # graalvm (3)
- # graphql (12)
- # helix (16)
- # honeysql (5)
- # jobs (1)
- # jobs-discuss (10)
- # juxt (3)
- # kaocha (26)
- # lambdaisland (3)
- # leiningen (15)
- # malli (7)
- # off-topic (100)
- # pathom (8)
- # pedestal (15)
- # protojure (24)
- # re-frame (2)
- # reagent (7)
- # reitit (22)
- # remote-jobs (1)
- # shadow-cljs (140)
- # spacemacs (17)
- # spire (2)
- # tools-deps (23)
- # uix (11)
- # vim (5)
- # xtdb (3)
- # yada (3)
reposting from #reagent as I'm wondering if this is a shadow-cljs issue: I have the following bit of code to create a datepicker:
(ns ui.components.picker.core
(:require ["@material-ui/pickers" :refer [TimePicker DatePicker MuiPickersUtilsProvider]]
["@date-io/moment" :as MomentUtils]
[ui.utils.core :as utils]
[reagent.core :as reagent]))
(def component-styles {})
(def component-props {:inputVariant "outlined" :fullWidth true})
(defn date-picker-real [props & children]
(let [all-props (-> component-props (merge props))]
(utils/->component DatePicker all-props
:styles component-styles
:children children)))
;; Call this datepicker from the UI; really it's just wrapping the actual DatePicker component with the MuiPickersUtilsProvider, which is necessary to get this all to work.
(defn date-picker [props & children]
[:> MuiPickersUtilsProvider {:utils (reagent/as-element MomentUtils)} [date-picker-real props children]])
This works well if I compile to a browser target. But when I compile to npm module, I get error messages like the following:
VM53713 react_devtools_backend.js:6 Warning: Failed prop type: Invalid prop `utils` of type `object` supplied to `MuiPickersUtilsProvider`, expected `function`.
[. . .]
Uncaught TypeError: Utils is not a constructor
at eval (useUtils-cfb96ac9.js?2ccd:11)
at mountMemo (react-dom.development.js?61bb:15442)
at Object.useMemo (react-dom.development.js?61bb:15738)
at useMemo (react.development.js?72d0:1521)
at MuiPickersUtilsProvider (useUtils-cfb96ac9.js?2ccd:10)
at renderWithHooks (react-dom.development.js?61bb:14803)
at mountIndeterminateComponent (react-dom.development.js?61bb:17482)
at beginWork (react-dom.development.js?61bb:18596)
at HTMLUnknownElement.callCallback (react-dom.development.js?61bb:188)
at Object.invokeGuardedCallbackDev (react-dom.development.js?61bb:237)
Seems strange the behavior would change depending on compilation method, so wondering if I might be missing something?@lilactown do you mean something like (js/console.log (reagent/as-element MomentUtils))
?
@rbruehlman my guess would by the {:utils (reagent/as-element MomentUtils)}
isn't correct and that it expects an actual class/function there. so maybe just {:utils MomentUtils}
here's the object (somewhat truncated... not quite sure how to better format)
Module {__esModule: true, Symbol(Symbol.toStringTag): "Module", default: ƒ}
default: ƒ MomentUtils(_a)
arguments: (...)
caller: (...)
length: 1
name: "MomentUtils"
prototype:
addDays: ƒ (date, count)
date: ƒ (value)
endOfDay: ƒ (date)
endOfMonth: ƒ (date)
format: ƒ (date, formatString)
formatNumber: ƒ (numberToFormat)
getCalendarHeaderText: ƒ (date)
getDatePickerHeaderText: ƒ (date)
getDateTimePickerHeaderText: ƒ (date)
getDayText: ƒ (date)
getDiff: ƒ (date, comparing)
getHourText: ƒ (date, ampm)
getHours: ƒ (date)
getMeridiemText: ƒ (ampm)
getMinuteText: ƒ (date)
getMinutes: ƒ (date)
getMonth: ƒ (date)
getMonthArray: ƒ (date)
getMonthText: ƒ (date)
getNextMonth: ƒ (date)
getPreviousMonth: ƒ (date)
getSecondText: ƒ (date)
getSeconds: ƒ (date)
getWeekArray: ƒ (date)
getWeekdays: ƒ ()
getYear: ƒ (date)
getYearRange: ƒ (start, end)
getYearText: ƒ (date)
isAfter: ƒ (date, value)
isAfterDay: ƒ (date, value)
isAfterYear: ƒ (date, value)
isBefore: ƒ (date, value)
isBeforeDay: ƒ (date, value)
isBeforeYear: ƒ (date, value)
isEqual: ƒ (value, comparing)
isNull: ƒ (date)
isSameDay: ƒ (date, comparing)
isSameHour: ƒ (date, comparing)
isSameMonth: ƒ (date, comparing)
isSameYear: ƒ (date, comparing)
isValid: ƒ (value)
mergeDateAndTime: ƒ (date, time)
parse: ƒ (value, format)
setHours: ƒ (date, count)
setMinutes: ƒ (date, count)
setMonth: ƒ (date, count)
setSeconds: ƒ (date, count)
setYear: ƒ (date, year)
startOfDay: ƒ (date)
startOfMonth: ƒ (date)
constructor: ƒ MomentUtils(_a)
__proto__: Object
__proto__: ƒ ()
property: ƒ (prop, desc)
apply: ƒ apply()
arguments: (...)
bind: ƒ bind()
call: ƒ call()
caller: (...)
constructor: ƒ Function()
length: 0
name: ""
toString: ƒ toString()
Symbol(Symbol.hasInstance): ƒ [Symbol.hasInstance]()
get arguments: ƒ ()
set arguments: ƒ ()
get caller: ƒ ()
set caller: ƒ ()
__proto__: Object
[[FunctionLocation]]: <unknown>
[[Scopes]]: Scopes[0]
[[FunctionLocation]]: index.esm.js?d37f:4
[[Scopes]]: Scopes[4]
Symbol(Symbol.toStringTag): "Module"
__esModule: true
__proto__: Object
maybe you just don't have the correct object? whats the JS example you are basing this on?
it looks like the npm-module build is resolving it as an ES module. note the "default"
key in that object
@lilactown thats incorrect. note the __esModule
. that is es module rewritten by babel to commonjs
@rbruehlman says that it works in browser build, so I have to assume that it resolves to the correct function somehow in that context
I’m also not convinced that creating an element out of it is correct, but just narrowing down on why you would see different behaviors between different build configs
Right, yeah, it resolves in the browser build. I'll try :default
and see if it gets me anywhere. I didn't write the code in question, but a JS example would be something to the effect of:
import MomentUtils from '@date-io/moment';
import DateFnsUtils from '@date-io/date-fns';
import LuxonUtils from '@date-io/luxon';
import { MuiPickersUtilsProvider } from 'material-ui-pickers';
function App() {
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Root />
</MuiPickersUtilsProvider>
);
}
render(<App />, document.querySelector('#app'));
my coworker, who wrote the code, said he fought with it for a long while and was only able to get it to work in the browser with (reagent/as-element MomentUtils)
in lieu of just MomentUtils
, so hence the choice of as-element
oh, hey, :default
worked, with no need for as-element
. Interesting quirk. Thanks for the help!
Hey @thheller - re. your comment on my PR - would you be open to a PR that removes the semvar.js dep and instead uses a CLJ-based implementation?
Relatedly, have you seen https://github.com/grimradical/clj-semver?
absolutely. as long as it parses node versions in the same way. no extra dependency.
Yeah, I think you're right - just pulled up the shadow code to see what you were using it for now
Looks like we would likely need a re-write
Still, I might take a crack at porting it over since I'm playing with loom for my runtime and GraalVM + Loom looks like a long way out
I mean its just a nashorn replacement. doesn't have anything else to do with graal vm
Definitely not sure - a bit lacking in my knowledge of Graal nuance. My understanding was that Graal was a special cut of the JVM - I take it that it's not?
there is graalvm yes. completely separate and not related to the graaljs scriptengine
Haha, indeed, I was wondering how you were going to address it in non-nashorn releases
Wonderful
I will have to look at graaljs a bit more to understand where the boundaries are. Seeing as that there are other JS deps in shadow anyway, porting to graaljs probably makes more sense since it seems unlikely to get off of JS completely, right?
I wouldn't call it "porting" exactly. Its just adding the extra dependency and switching the name here https://github.com/thheller/shadow-cljs/blob/db38f5968a8ecefcd10cd62412333028ee13959b/src/main/shadow/cljs/devtools/server/npm_deps.clj#L30
Yes! I was saying that that seems like a better alternative than rewriting semver.js in cljc
(ie. porting semver.js to cljc)
well I'd still prefer a CLJ impl for that part. bit of a gigantic overhead to launch an entire JS vm for a bit of version parsing
Totally
I might take a poke at using graaljs since getting that into the project seems like a long-term goal anyway, and it could serve as an easier fix to porting
If that's something that you'd still be interested in
there is really not much to do .. its mostly about testing in a few different JDK versions and so on
Playing with it now 🙂
Hahaha, it's indeed a bit wonky
The long and short of it is that I have cider starting shadow and it seems to use shadow to manage both the clj JVM and the cljs process
(and I could be 100% wrong about what cider-jack-in-clj&cljs is actually doing, but as far as I can tell it's starting a JVM and then loading nREPL on the backend, and then starting shadow as java lib, and then starting a second nREPL on the JS side)
That makes two of us 😉
the one you are using does expect that the same jvm can juggle both sessions. not usually true with shadow
but if you check your *Messages*
buffer it will say the one command being used to start a jvm
Even if I did use it separately, wouldn't it use the same default java command? ie. won't they be the same JVM runtime version unless I explicitly configure two different runtime paths ?
(right now 15-loom
is my "default" JDK)
same jvm runtime version and default java command but that seems neither here nor there
But shadow (the node package) invokes java on the $PATH right?
I might be wrong, but then I would expect that it'd just be two separate processes both running loom anyway - which I think leaves me in the same pickle of needing a nathorn replacement in the JDK-15 based build
Borderline insane I'd say
But yeah, I can't resist playing with the concurrency constructs
or nix
right? 😉
never used nix before but there are plenty of options to select a different JDK per project 😛
But none the less, it seems like shadow will need to overcome nathorn disappearing at some point, regardless of how crazy bleeding edge I am
yes. everything is in place. like I said .. add the dependency and change "nashorn"
to "JavaScript"
. that should be all there is to it.
I just need to get around testing it a bit more .. which I'll do when jdk15 is actually out and nashorn actually removed.
Playing with it thus far - looks like there may be additional work to get it to register with the ScriptManager
but not convinced that I'm doing it right yet
Well there's my problem 😛
Didn't see the second dep - testing now
just like the removed a bunch of stuff after jdk8 and turned it into libs instead? like jaxb?
doesn't really matter ... if all else fails I'll just remove the semver.js ... its annoying anyways
I admittedly have almost no context here. That being said, it seems like graal-js might be the better pick anyway?
That being said, I use loom, so you can tell that I favor cutting myself on the bleeding edge
(ie. comparing whether to introduce the nathorn lib vs the graal-js lib)
yeah I don't want to get too hyped about loom just yet .. still probably a couple years out right?
JDK 18 I think is what I remember reading
+ another 10 till enough people have it to warrant actually using it in shadow-cljs 😛
But it's definitely hype worthy. https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function/ is a fantastic read on why a runtime based scheduler is preferable
Yeah I don't know if it'll ever matter in the context of shadow - and definitely a way out. But in terms of what it means for the JVM, quite exciting to see
I'm curious - why don't you think it would work? Haven't Go and BEAM (Erlang), and to some extent GHC, demonstrated that a run-time based scheduler solution can work?
well there is going to be a tradeoff somewhere. this can't be free. either overall performance, GC perf or whatever.
erlang also has a quite different memory/process model which makes this a whole lot easier
In some initial toy benchmarks I made 5000 HTTP requests simultaneously using both aleph (manifold based, nio) and hato (clj-http mimicing client wrapping JDK 11 http client). Loom was about 2x as fast
I expect that that might have something to do with aleph's default thread pool as it didn't manage to "light up" the cores nearly as effectively as loom
Yeah, it's wonderful
Also, seriously, not leaking deferred / promises all over
(or go channels, whatever your concurrency primitive is)
suddenly concurrency becomes caller controlled, not implementing function's responsibility
exactly
Cannot wait
I've had it in erlang and haskell, and it's 100% the thing I miss most
Also, I imagine something like aleph's let-flow
which could disect a body of code and automatically parallelize paths
eg.
(parallelize
(let [a (foo)
b (bar)
c (+ foo bar)]
(println "Hello")
c))
Imagine something that disects the body to run (foo)
(bar)
and (println)
in parallel, and then rejoins on c
I'm happy with core.async if I can get rid of the go
macro. just blocking ops everywhere. already using mostly async/thread in shadow-cljs and its sooo much better than go
Yep! Yeah, you still need channels / streams to coordinate execution within. ie. for the same reason I prefer (map f coll)
to imperative manipulation, I want ways to operate over queues (eg. stream/map
) - but to not have to consider whether something inside those transformations is "blocking" is 😍
Anyway, sorry for nerding out haha. Got the engine working. How should I best test this? JDK 8, 11, 13 and 15-loom sound like an okay checklist?
(15-loom is for me, I'll admit it!)
Awesome - I'll test it out on JDK 8 and make sure it works. Also going to add a couple tests (mostly just porting over your semver-intersects comments) just so there's something in case you ever wire up multi JDK CI tests
I'd rather delay switching away from nashorn. not fond of adding extra deps if I don't have to.
Ah, okay. It does considerably cleanup the module to remove nashorn (eg. make-engine*
and get-jvm-major-version
can be removed)
But, I tested on open-jdk-8 and all is good either way... So if you don't want that cleanup in the PR let me know
not interested it making it the default just yet. still want the option to be available though.
I mean, shadow isn't exactly light anyway. You're interoping with NPM, etc
Maybe it's just me personally, but I don't expect it to be a lightweight library
No comment there! I just meant given that it's close to an IDE in some respects, it gets some license in my mind
So, regarding the changes to the actual file then, if I'm not cleaning up detecting the major JVM version, etc. do you just want a one-liner string substitution + the deps changes + the tests?
https://github.com/thheller/shadow-cljs/pull/731 If it's easier to collaborate there (through in the cleanup, but 100% happy to undo it)
let me think about this for a bit. too tired to decide now. its either removing all the version check stuff and just using graal or some system property/config entry to control which engine is used
Sounds good! I'll just wait for whatever you decide on the PR. Thanks again for all the help 🙂