Fork me on GitHub
#clojurescript
<
2018-08-12
>
Oliver George04:08:59

I'm surprised/confused by the source argument to cljs.build.api/build. It takes one source path but I have many. In cljs.main it's set by resolving the source path of the :main namespace. I can do this although that's different between dev & prod environments which makes it an extra thing to twiddle... Is it really needed? How is it used?

Oliver George04:08:10

Ah, you can pass a vector. The doc string An optional source parameter may be provided. and the cljs.main example led me to conclude that wasn't the case. source needs to implement -find-sources

(defprotocol Compilable
  (-compile [this opts] "Returns one or more IJavaScripts.")
  (-find-sources [this opts] "Returns one or more IJavascripts, without compiling them."))

Oliver George04:08:14

There are other examples in the cljs.build.api where a compilable is passed in. The docstring for them is more sensible to me, for example:

compile
function
Usage: (compile opts compilable)
       (compile state opts compilable)
Given a Compilable, compile it and return an IJavaScript.
Perhaps the build function should match this.

Karol Wójcik10:08:32

@bhauman May I please contact you via DM? I want to start contributing to figwheel/core and need some help in getting started.

Karol Wójcik10:08:29

@bhauman I isolated the problem and I am on my way to fix it 🙂 The problem is that figwheel_server.clj tries to parse the data and in the data there is #js literal. My question is how can I parse it to map when using clojure?

Karol Wójcik11:08:42

Imo I should slice the string to not contain #js but maybe you got better solution.

urbanslug11:08:57

Hello, I'm using core.async cljs and can't figure out why the x function blocks when it tries to put true in the txt-chan

(defn x
  [txt-chan]
  (go
    (if true
      (do (prn "a")
          (>! txt-chan "true"))
      (>! txt-chan "fail"))))

(defn x-caller
  []
  (go (let [y (<! (x (chan)))]
        (prn y))))

Karol Wójcik11:08:32

x should return the txt-chan

Karol Wójcik11:08:16

Could you please change the names of vars and fns? It's hard to follow it

urbanslug11:08:01

yeah seems x returning txt-chan fixed it but I don't see why. One sec let me rename vars

urbanslug11:08:28

The thing I can guess it the go block executed in another thread and the one that called it never took the result

Karol Wójcik11:08:03

Ok let me examine your code closer

Karol Wójcik11:08:34

Please correct the names to let me just copy and paste your code then I would love to help you 🙂

urbanslug11:08:34

(defn child
  [txt-chan]
  (go
    (do (prn "starting to put text in the channel")
        (>! txt-chan "true")
        (prn "finished putting text in the channel")))
  txt-chan)

(defn parent
  []
  (go (prn (<! (child (chan))))))

thheller11:08:00

@urbanslug one thing to be aware of is that you are using an unbuffered (chan) which means that the put >! only completes when something else takes it.

urbanslug11:08:12

I want a blocking network request for now.

urbanslug11:08:28

The problem I believe was that I was not returning txt-chan

Karol Wójcik11:08:30

The problem is that go returns the channel. It returns the last evaluated body which is (prn "finished putting text". Since putting nil on channel is an error than it's impossible to prn <! (child (chan))

Karol Wójcik11:08:01

Yes that's the whole problem because as I said the go returns it's own channel

Karol Wójcik11:08:15

which has the value of the last body

urbanslug11:08:59

so go returns its own channel which contains a nil

urbanslug11:08:07

and taking nil causes an error

Karol Wójcik11:08:11

Let me check it one more time

Karol Wójcik11:08:22

I want to be 100% sure 😛

Karol Wójcik11:08:19

@urbanslug 1. only (put! channel nil) returns an error so there is no error in your code 2. @thheller it 100% right. You are putting sth into the channel but since there is nothing which can take from the channel then the code blocks 3. But why there is no take? Because: 3.1 go returns it's own channel 3.2 you do not return the txt-chan therefore the take is done on channel returned from go and txt-chan still has some value which is not taken 😛 That why it blocks. @thheller Could you please confirm?

thheller11:08:45

the channel returned by go returns the last result of the go block

thheller11:08:54

so since prn returns nil you got nothing

urbanslug11:08:14

but shouldn't it have printed "finished putting text in the channel" ?

urbanslug11:08:24

the side effect should have been visible

Karol Wójcik11:08:38

Now I am confused a little bit

thheller11:08:10

what code exactly? too many confusing examples with totally different structure

Karol Wójcik11:08:02

(defn child
  [txt-chan]
  (go
    (do (prn "starting to put text in the channel")
        (>! txt-chan "true")
        (prn "finished putting text in the channel"))))

(defn parent
  []
  (go (prn (<! (child (chan))))))
Sorry for messing things up. I think that txt-chan blocks but in go block. Therefore prn does not prints "finished putting text in the channel"

thheller11:08:12

whats the problem? this code will print the finish msg?

Karol Wójcik11:08:42

Nope it won't. Question is: Why it won't?

thheller11:08:09

yes it does? I just tested it

Karol Wójcik11:08:53

Sorry :face_palm: without returning txt-chan

thheller11:08:35

ok without that the >! will park until it is taken somewhere else

👍 4
🙂 4
❤️ 4
thheller11:08:53

but since nothing ever takes from txt-chan it prn never happens

Karol Wójcik12:08:48

Ok thank you for the clarification 😜 Sorry one more time for messing the examples 😛 @urbanslug I think that you got the answer now 🙂

thheller12:08:49

thats the unbuffered channel

thheller12:08:59

(chan 1) would cause the prn to happen

👍 4
urbanslug12:08:21

but parent wouldn't print "true" because it's taking nil

urbanslug15:08:10

Thanks for that

abdullahibra14:08:11

when i try this i got the error:

abdullahibra14:08:13

TypeError: (intermediate value).ih is undefined

abdullahibra14:08:27

what is it meaning?

thheller14:08:54

@abdullahibra that is about missing externs and the hide fn call getting renamed

abdullahibra14:08:07

@thheller what actually i'm trying to do is using dateDropper plugin within my app: https://felicegattuso.com/projects/datedropper/

abdullahibra14:08:21

i got jquery hide function working properly now

abdullahibra14:08:42

that's the code

abdullahibra14:08:31

for using datedroppper which is jquery plugin

abdullahibra14:08:26

can anybody help me in this?

abdullahibra14:08:55

by trying jquery hide function, i'm sure jquery is loaded successfully globally

lilactown14:08:36

@abdullahibra what do you need help with?

abdullahibra14:08:02

i'm trying to use dateDropper inside my code but failed

abdullahibra15:08:55

@lilactown that's what i have tried

abdullahibra15:08:05

do you have any suggestions ?

lilactown15:08:24

remove the js/ in front of dateDropper

lilactown15:08:44

#(.dateDropper (js/$ "hello"))

abdullahibra15:08:10

TypeError: $(...).hh is not a function

abdullahibra15:08:14

that's what i got

lilactown15:08:55

but .hide works?

abdullahibra15:08:43

it's working correctly

abdullahibra15:08:51

but not working with .dateDropper

lilactown15:08:18

do you have externs inference on?

abdullahibra15:08:37

:foreign-libs [{:file "resources/public/js/date/datedropper.min.js" :provides ["ui.datedropper"]}]

abdullahibra15:08:03

then using (:require [ui.datedropper]) in the ns i want to use functions at

lilactown15:08:25

how are you including jquery in your project?

abdullahibra15:08:40

so it's available using js/$

lilactown15:08:45

hm. I’m not sure why it’s fine with (.hide ...) but not (.dateDropper ...)

lilactown15:08:57

add (set! *warn-on-infer* true) to the top of your file

abdullahibra15:08:58

WARNING: Adding extern to Object for property dateDropper due to ambiguous expression (. (js/$ "#hello") dateDropper) at line 42

abdullahibra15:08:18

referred line: [:input {:placeholder "input..." :on-change #(.dateDropper (js/$ "#hello"))}]

lilactown15:08:55

strange that it says i’ts adding the extern but when it compiles it isn’t right.

lilactown15:08:10

when you change it to .hide does it give the same error?

lilactown15:08:01

anyway, the solution is to write an externs file for datedropper

abdullahibra15:08:11

WARNING: Adding extern to Object for property hide due to ambiguous expression (. (js/$ "#hello") hide) at line 42

abdullahibra15:08:17

and it's working

abdullahibra15:08:29

what do you mean with externs file?

lilactown15:08:17

an externs file helps the Closure compiler know what external JS you have in your project so it can optimize correctly

abdullahibra15:08:52

so it can work without optimization true?

lilactown15:08:26

your current code should work without optimizations

abdullahibra15:08:02

i'll try dev mode now

Karol Wójcik16:08:56

@bhauman I am here if you want to discuss further that figwheel parsing problem. 🙂

bhauman16:08:11

I replied to the ticket

bhauman16:08:38

and you did as well i see

bhauman16:08:29

so if the problem is a problem with reading a clojure string you don't want to adhoc change the string

Karol Wójcik16:08:31

If you prefer communicating via Github then I don't mind 🙂

bhauman16:08:40

you want to fix the whats reading the string

Karol Wójcik16:08:08

Yes you got right.

bhauman16:08:27

In this case you want to make sure that #js tags are not causing things to blow up

bhauman16:08:53

but still the string that is in the ticket is not a proper clojure string

bhauman16:08:14

"{:value {#js {:prop1 blabla}}"

bhauman16:08:48

because if you remove the #js you are left with a map with one item in it

Karol Wójcik16:08:53

Did not want to overhelm the ticket with to much information

bhauman16:08:41

so "{:value #js {:prop1 blabla}}"

Karol Wójcik16:08:38

I edited my comment

Karol Wójcik16:08:54

So as you can see it's not a problem with the #js

Karol Wójcik16:08:18

it's a problem that the parser tries to evaluate (or read ((clojure noob here, don't punch plx))) the #object #js as reading macros

bhauman16:08:22

so it is a reader problem because its happening in the reader

Karol Wójcik16:08:42

You mean edn/read-string

bhauman16:08:26

the reader is the clojure parser

Karol Wójcik16:08:05

yea but how the Clojure parser can know what #js means. It means something in Clojurescript environment not in Clojure env

bhauman16:08:47

so on that page of particular interest is the tagged literal section

bhauman16:08:13

and in that section is describe the *default-data-reader-fn*

bhauman16:08:38

and the default data reader fn

Karol Wójcik16:08:42

Ok sorry let me read that

bhauman16:08:02

will handle any missing tagged literals

bhauman16:08:07

@kwcharllie379 you also don't seemed to have responded to me stating that figwheel.main has the exact same edn/read-string and so I'm very suspicious about what is going on here

Karol Wójcik16:08:47

Let me check that again

bhauman16:08:37

we should move this conversation to #lein-figwheel

athomasoriginal16:08:19

I am trying to see what it would look like to write CLJS tests with Jest. The problem is that Jest defines global functions. These globals are only available are runtime so there is no easy way to import them. Is it possible to compile my CLJS without importing the actual modules, perhaps they are mocked in some way, to get through the compilation step? The idea being that when these tests are run, I will have access to the globals because Jest will provide them.

Karol Wójcik16:08:28

Does js/someGlobal works?

athomasoriginal16:08:01

Yup, it totally does. I have no idea why I was thinking that the compiler would try to see if that global exists and just fail because its not there. Thanks!

Karol Wójcik16:08:34

No problem 😛

dangercoder20:08:29

what http-lib do you guys usually use for Cljs? I'm thinking about using https://github.com/r0man/cljs-http for my project

dangercoder10:08:02

@urbanslug you and me then 😉

urbanslug21:08:19

How would you guys handle it if you had an array of values and wanted to make a network request for each one?

urbanslug21:08:07

trying to use reduce or for but all my attemps are just a fail

mfikes22:08:04

@urbanslug Assuming your network requests are async, you’d probably want to return an array of promises or core.async channels onto which the responses are placed, and then turn that into a collection of resolved values.

urbanslug22:08:37

yes they're async

mfikes22:08:55

I don’t know if there is a function already in core.async like this, but if you have a seq of channels you could use something like

(defn take-chans [chans]
  (go
    (loop [results []
           chans   chans]
      (if (seq chans)
        (recur (conj results (<! (first chans))) (rest chans))
        results))))

mfikes22:08:01

How you form the seq of channels is another half of the problem, depending on your network request lib, but you’d have it put the responses onto each of a collection of channels.

mfikes22:08:58

This is a fairly naïve way to do it, I suspect, but it gets you in the right direction of something that works.

mfikes22:08:00

@urbanslug Try

(go (prn (<! (take-chans (map mock-request [1 2 3])))))

mfikes22:08:52

This returns a vector of the values produced by mock-request, so your mock-request implementation could be revised to simply put the value on the channel. (It appears you have a vector containing a value, so that vector wrapper could be removed, essentially.)

mfikes22:08:08

I suppose that what I posted here is lazy, do you could wrap the map with doall or use mapv (to force requests to be initiated eagerly)

mfikes22:08:41

I’m curious if there is a better solution than the take-chans posted above, but it works.

urbanslug22:08:27

hmmm I tried it out with the mock and it works. with your take chans returning a single channel of requests

urbanslug22:08:39

I wonder how this handles failure and retries

urbanslug22:08:42

:thinking_face:

mfikes22:08:34

Yeah, none of the above has any robustness built into it.

urbanslug22:08:00

I would expect that people have ran into this kind of problem in the past

Karol Wójcik22:08:23

Hmm it depends on your problem.

Karol Wójcik22:08:35

Do you run the code in backend environment (Node.js)

Karol Wójcik22:08:40

or in the browser?

Karol Wójcik22:08:01

Do you prefer to handle your errors in a single place

Karol Wójcik22:08:44

or you would rather to handle the error in the place where you send the request?

urbanslug22:08:59

you mean client side?

Karol Wójcik22:08:24

Yes. For instance you can take the value from the channel check whether it's an error and then pass it to your error handler. But if you prefer some kind of FRP then promesa might be a good choice https://github.com/funcool/promesa.

urbanslug22:08:22

Thanks @kwcharllie379 I'll eval both options

Karol Wójcik22:08:15

I think that if we could take a look into the real sample of code then we would give you better and more accurate advices.

urbanslug22:08:54

if I create an array of promises though it's hard to handle errors because that means looking through an array of results

urbanslug22:08:05

ya I just need to take a break and get back to it