Fork me on GitHub
#clojurescript
<
2020-03-06
>
Edmund07:03:46

Hi. I'm trying to create a simple react dashboard component and use it in a react app. I've managed to get everything running using re-frame. I'm using shadow-cljs and releasing it as a node-library. I've created a simple react app using create-react-app and there goes my nightmares. I can't find any good example where this has been done. Most of the articles do the reverse (using node modules in clojurescript). I'm also using material-ui via npm (was just experimenting). What is the right way of exporting and then importing this library. Any reference to a good example can also do.

Edmund08:03:03

Yes and when I try to use the generated js file in my react app it gives compile errors right from the first line e.g. "define is not defined"

thheller09:03:27

note that you must publish a release build (ie. shadow-cljs release lib). you cannot publish the results of watch/compile.

Edmund11:03:19

Got it work as node-module. I'll try again with node-library. Thanks for helping.

jeroenvandijk12:03:58

Anyone know how to use apply for all constructors? Ok:

(apply js/Error ["msg here"] )
Not ok:
(apply js/EventSource ["/path-here"] )
;=>
Uncaught TypeError: Failed to construct 'EventSource': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

jeroenvandijk12:03:22

;; Ok
(let [sse (js/Function.prototype.bind.apply js/EventSource)]
  (println "works" (new sse "/path-here")))
;; Not ok
(let [sse (js/Function.prototype.bind.apply js/EventSource)]
  (println "__" (apply new sse ["/path-here"])))

delaguardo12:03:20

create dedicated function (e.g. (defn error [& messages] (js/Error. (apply str messages))) ) and then call apply for that function: (apply error ["str1" "str2"])

jeroenvandijk15:03:32

ai 😞 Ok so no one size fits all solution. That’s a pity

jeroenvandijk15:03:13

It’s for the interpreter of https://github.com/borkdude/sci so I don’t know in advance what object will called

jeroenvandijk15:03:37

ah but I can fake apply with multiple arities

Adriaan Callaerts14:03:27

has there been any plan/debate/consideration for implementing a clojurescript parser+compiler independent of googles closure compiler? My experience with cljs so far is that the tooling is far less mature then I've become accustomed to in js development over the past few years. While I like the clj(s) language, I'd feel much more comfortable with using js tooling, making use of tried-and-tested treeshaking/minification/... as offered by webpack, rollup and the like; getting easy access to the full js ecosystem rather than having to work around the (imho) clunky behemoth that is the closure compiler and library. My instinct is that a cljs compiler that worked as eg a webpack loader or babel plugin and emitted (as much as possible) dependency-free es6 code could integrate far better in the js ecosystem. Did anyone consider this in the past and was it deemed a bad idea? Probably I'm overlooking aspects of the cljs->js conversion that are prohibitive of doing this?

mauricio.szabo18:03:27

Using shadow-cljs I didn't find myself missing anything from webpack/babel/etc. It can include modules from NPM, it'll minify node_modules even for node-library or node-script targets, and simplifies reload-on-save for any target...

mauricio.szabo18:03:43

The problem of adding a CLJS compiler as a babel source is that you the REPL, hot-reload, and most tooling will stop to work, for example

thheller15:03:02

> making use of tried-and-tested treeshaking/minification/... as offered by webpack

thheller15:03:23

I'd argue that the closure-compiler is much more tried-and-tested in that area and has been for years 😛

thheller15:03:15

also try shadow-cljs 😉

✔️ 8
jeroenvandijk15:03:59

Any feedback on the following approach to use apply on constructors:

(defn constructor-fn [class]
  (let [constructor (js/Function.prototype.bind.apply class)]
    (fn
      ([a] (new constructor a))
      ([a b] (new constructor a b c))
      ([a b c] (new constructor a b c d))
      ([a b c d] (new constructor a b c d e))
      ([a b c d e] (new constructor a b c d e))
      ([a b c d e f] (new constructor a b c d e f))
      ([a b c d e f g] (new constructor a b c d e f g))
      ([a b c d e f g & more]
       (throw (ex-info "Constructors with more than 7 arguments are not supported" {:class class}))))))

(apply (constructor-fn js/EventSource) ["/yeah"])
(thanks @delaguardo for the idea of having a dedicated function 🙂

✔️ 4
thheller15:03:58

what are you doing that you need apply for new? 😛

jeroenvandijk15:03:30

haha good question

jeroenvandijk15:03:02

If you have ideas please let me know 🙂

jeroenvandijk15:03:27

normal constructors work, but (js/EventSource. "asdfsa") doesn’t work with apply

jeroenvandijk15:03:49

I just checked and this solution doesn’t work in advanced compilation (not sure why)

jeroenvandijk15:03:56

WARNING: Use of undeclared Var sci.impl.interop/c at line 47 /Users/jeroen/Projects/Github/sci/src/sci/impl/interop.cljc
WARNING: Use of undeclared Var sci.impl.interop/d at line 48 /Users/jeroen/Projects/Github/sci/src/sci/impl/interop.cljc
WARNING: Use of undeclared Var sci.impl.interop/e at line 49 /Users/jeroen/Projects/Github/sci/src/sci/impl/interop.cljc

thheller15:03:04

ah this is for sci

thheller15:03:21

so rather "reflection" heavy

jeroenvandijk15:03:46

In the JVM it’s all reflection, but js doesn’t have that right?

thheller15:03:06

not in the JVM sense no

thheller15:03:28

but you don't really need apply in this case?

thheller15:03:48

you know how many args you have and could just write a bit of boilerplate 😉

jeroenvandijk15:03:39

hmm you mean I could call new myself. True probably, but I would like to get the cljs experience in sci. So no context switching

jeroenvandijk15:03:43

pretend it’s the same

borkdude15:03:32

it was only done for perf optimization

jeroenvandijk15:03:52

I can remove the boilerplate, but it doesn’t seem to work in advanced mode yet. compiler doesn’t like c, d, and e for some reason

jeroenvandijk15:03:03

and trying with one arity gives a weird error still. Ok back to the drawing board

jeroenvandijk16:03:37

Ah wait you mean not using apply at all. I can try that 🙂

thheller16:03:59

(let [ctor (get-static-field [class field])]
  (case (count args)
    0 (new ctor)
    1 (new ctor (nth args 0))
    ...))

thheller16:03:22

something like that .. assuming get-static-field just returns the actual type

jeroenvandijk16:03:53

I think it does… but I am not entirely sure what I’m doing either

jeroenvandijk16:03:16

@thheller your suggestion works, sci.evalString("(js/EventSource. \"/aaa\")", {"classes": {"allow": "all", "js": window}}) works now

jeroenvandijk16:03:02

When I want to use addEventListener there is a new problem waiting 🙂

jeroenvandijk18:03:14

@thheller In case you are curious here is the WIP https://github.com/borkdude/sci/pull/286 still not perfect, but getting there

jeroenvandijk18:03:25

Thanks for your help!

Jacob O'Bryant17:03:59

Does anyone know if the metadata reader macro is supposed to work within go blocks? If I run (go (println (meta ^:foo {}))) it prints nil to the console (whereas (go (println (meta (with-meta {} {:foo true})))) and (println (meta ^:foo {})) both print {:foo true})

Jacob O'Bryant17:03:27

I'm writing a library function that takes a data structure with optional metadata, so I'm thinking of turning the function into a macro that does (my-fn {:foo ^:bar {}}) -> (my-fn ((fn [] {:foo ^:bar {}}))) . It'll break any <!s inside the call, but I'd rather do that than lose metadata silently. This should be ok, but I'm wondering if there's a better way.

Jacob O'Bryant17:03:24

(since wrapping the arg in a function prevents the go block from clobbering the metadata). hm... maybe the macro could instead do a clojure.walk/postwalk and wrap anything that has metadata with with-meta calls

Jacob O'Bryant18:03:15

ah, thanks for the link

lilactown18:03:54

cljs.user=> (require '[cljs.core.async :as a])
nil
cljs.user=> (macroexpand '(a/go (prn ^:foo {})))
(let* [c__45917__auto__ (cljs.core.async/chan 1)] (cljs.core.async.impl.dispatch/run (clojure.core/fn [] (clojure.core/let [f__45918__auto__ (clojure.core/let [switch__45894__auto__ (clojure.core/fn [state_127784] (clojure.core/let [state_val_127785 (clojure.core/aget state_127784 1)] (clojure.core/cond (clojure.core/== state_val_127785 1) (clojure.core/let [inst_127781 (. cljs.core/PersistentHashMap -EMPTY) inst_127782 (prn inst_127781) state_127784 state_127784] (cljs.core.async.impl.ioc-helpers/return-chan state_127784 inst_127782)))))] (clojure.core/fn state-machine__45895__auto__ ([] (cljs.core.async.impl.ioc-macros/aset-all! (clojure.core/make-array 7) 0 state-machine__45895__auto__ 1 1)) ([state_127784] (clojure.core/let [ret-value__45896__auto__ (try (clojure.core/loop [] (clojure.core/let [result__45897__auto__ (switch__45894__auto__ state_127784)] (if (cljs.core/keyword-identical? result__45897__auto__ :recur) (recur) result__45897__auto__))) (catch js/Object ex__45898__auto__ (cljs.core.async.impl.ioc-macros/aset-all! state_127784 5 ex__45898__auto__) (cljs.core.async.impl.ioc-helpers/process-exception state_127784) :recur))] (if (cljs.core/keyword-identical? ret-value__45896__auto__ :recur) (recur state_127784) ret-value__45896__auto__))))) state__45919__auto__ (clojure.core/-> (f__45918__auto__) (cljs.core.async.impl.ioc-macros/aset-all! cljs.core.async.impl.ioc-helpers/USER-START-IDX c__45917__auto__))] (cljs.core.async.impl.ioc-helpers/run-state-machine-wrapped state__45919__auto__)))) c__45917__auto__)

lilactown18:03:26

notably, this form:

(clojure.core/let [inst_127781 (. cljs.core/PersistentHashMap -EMPTY)
seems to be a rewritten version of the {} that perhaps doesn’t propagate the metadata. I’m not sure why that happens

Alex Miller (Clojure team)18:03:57

Is it only empty colls? There is actually a ticket about this in Clojure

Jacob O'Bryant18:03:12

(go (println (meta ^:foo {:bar "baz"}))) also gives me nil

Alex Miller (Clojure team)18:03:45

ok, just wanted to make sure this wasn't that. more likely both. :)

👍 4