Fork me on GitHub
#clojurescript
<
2017-06-06
>
tomerweller05:06:46

foreign-libs - order of execution. Is there a way to ensure my js foreign-lib is loaded before the rest of my dependencies?

pesterhazy06:06:28

I've submitted a PR for "surrogate" packages that supply faux namespaces for cljsjs.react, cljsjs.react.dom and cljs.react.dom.server. This could reduce the headaches of using reagent (and other wrappers) with a provided version of React (e.g. in a separate webpack-built bundle): https://github.com/cljsjs/packages/pull/1192

pesterhazy06:06:01

This may help with issue people have had, e.g. @reefersleep's empty-namespace problem yesterday

dnolen13:06:10

@tomerweller there’s no way to control beyond the namespace dependency graph

tomerweller14:06:34

@dnolen, say that I want to use my own version of react but I need to load before reagent, any way to make that happen?

tomerweller14:06:00

(using foreign-lib, that is)

dnolen14:06:06

@tomerweller you need to make your own React foreign lib then

dnolen14:06:24

no need for a JAR or anything like that

dnolen14:06:50

just put it in a directory, and declare that it provides cljsjs.react

tomerweller14:06:54

@pesterhazy, Thanks 🙂 It’s been getting a lot more traffic than I expected

dnolen14:06:17

exclude cljsjs.react from your dependencies and you should be good to go

tomerweller14:06:43

Can it provide multiple namespaces?

tomerweller14:06:08

(In the case of a bundle, for example)

dnolen14:06:15

it should work yes, :foreign-libs entries can declare multiple :provides

ghadi18:06:14

dnolen: do you have a spec for :compiler-options? @U072WS7PE was asking about spec improving tooling, jogged my mind

dnolen18:06:19

we don’t but that’s to avoid a dep on Clojure 1.9

dnolen14:06:22

:provides is a vector

pesterhazy14:06:58

@tomerweller, I spend a day writing out a blog post (https://github.com/pesterhazy/presumably/blob/master/posts/double-bundle.md) then found your post, which is similar, in an almost uncanny way

pesterhazy14:06:19

Except one year before me 🙂

tomerweller14:06:26

Looks good. There’s enough curiosity in this space for more resources 🙂

iGEL14:06:00

Hey y'all! I am confused by some code I wrote on Thursday and of which I think it worked then, but now it doesn't:

(go-loop []
  (let [{:keys [type bytes-sent bytes-total response] :as x} (<! channel)]
    (when (= :progress type)
      (dispatch [:something uid (/ (float bytes-sent) bytes-total)]))
    (when (= :success type)
      (dispatch [:something-else])))
  (recur))
I get can't recur here. But recur is the last expression of the go-loop :thinking_face:

tomerweller14:06:01

I’m revisiting this right now, might add an update with the foreign-libs options.

iGEL14:06:17

Don't have a lot of experience recur or core.async, tho 😕

captainlexington14:06:05

@igel, is there a reason your recur happens outside the let? I don't think this could cause the error but I'm curious

iGEL14:06:09

I also tried to move it in, same error. It's outside because it's independent of what happens inside the let

captainlexington14:06:40

Can you move the bindings from the let into the bindings for the go-loop? They're both binding forms, right?

iGEL14:06:52

sorry, I was stupid

iGEL14:06:53

After unstashing the changes, the go-loop macro wasn't required anymore. Don't get why it was lost

iGEL14:06:36

Now I know. I unstashed on the wrong branch 😉

captainlexington14:06:19

Hahaha oops :thumbsup:

iGEL14:06:52

Thanks anyway, and sorry about that 😉

borkdude14:06:54

@igel I made this, it works:

(def channel (chan))

(reg-event-fx :foo
              (fn [_ _]
                (println “foo”)))

(reg-event-fx :bar
              (fn [_ _]
                (println “bar”)))

(go-loop []
  (let [x (<! channel)]
    (when (odd? x) (dispatch [:foo]))
    (when (even? x) (dispatch [:bar])))
  (recur))

(put! channel (rand-int 10))

iGEL14:06:33

borkdude: Thanks, but as I wrote about, it was just my stupidity

borkdude14:06:00

I read it yes, glad you figured it out

tomerweller14:06:29

@dnolen Thanks, That was very helpful.

tomerweller14:06:49

I’m now looking at :npm-deps. Is there a way to have these provide namespace(s)?

dnolen15:06:17

@tomerweller nope not possible - Google Closure controls the naming there

dnolen17:06:09

Clara rules + Reagent

captainlexington17:06:50

Wow, that's awesome.

captainlexington17:06:47

A lot of JavaScript front-end is criticized for chasing the next new hotness

captainlexington17:06:06

ClojureScript seems to have the same rapid pace, but every new hotness is really flippin' sweet

nikki17:06:27

Waiiit what!!!

nikki17:06:31

That's awesome

roberto17:06:51

I’m confused. What does it do?

nikki17:06:53

I was sort of visualizing something like this and hoping to try it 😮 eavt fact db plus additive rule engine

nikki17:06:05

Late-binds object semantics

captainlexington17:06:23

@roberto This is the headline, buried in the Readme (although it's not implemented yet, it's the basic idea): >Using a rule engine allows us to know exactly what changes from one state to the next. This means we don't need React's diff algorithm or the concept of subscriptions. If we declare views as the consequences of rules, we can automatically point update them when the facts they care about change.

roberto17:06:07

Yeah, but what is it? A front end framework like reagent? A rules engine?

roberto17:06:10

I’m still confused

roberto17:06:21

I thought it was a layer over clara/optaplanner

nikki17:06:24

i think it's one of those things where it makes sense to read the quick spec

roberto17:06:25

but apparently it isn’t

nikki17:06:35

then decide what you want to call it in ur mind :thinking_face:

nikki17:06:51

just seems to sit over a few categories

captainlexington17:06:53

It does say it wraps Clara in the Readme.

roberto17:06:57

hmm, that is not very “newbie” friendly

nikki17:06:02

i would say it's a performance system for a complex system

nikki17:06:10

a la John Holland

nikki17:06:23

Except doesn't have messaging

nikki17:06:34

But you can impl messaging in its rules

nikki17:06:54

I would just render a rule query at 60fps with opengl

nikki17:06:59

Diffing is lolz

nikki17:06:09

Suddenly you have an RTS game

dealy17:06:34

I'm using a JS library, that has a funky constructor sequence: new Chart(ctx).Doughnut(data,option); I'm having trouble constructing this Doughnut object in cljs. What is the best way to do something like this?

roberto17:06:59

(let [chart (Chart. ctx)
        dnot (.Doughnut chart data option)]
???

dealy17:06:18

yea, that's basically what I have, but I get errors whenever I try to make the doughnut 😞

roberto17:06:38

what is Doughnut?

dealy17:06:48

its a type of pie chart

roberto17:06:57

so it is not a method on Chart?

dealy17:06:59

with a hole in it, hence a dounut

dealy17:06:56

The docs on the JS lib aren't that great, and I'm not a JS expert so its a little hard to tell from the source code

dealy17:06:24

correct, I don't see an obvious method Doughnut

roberto17:06:35

what is the error you get?

captainlexington17:06:39

Maybe Doughnut is like a method on Chart.prototype?

roberto17:06:59

hmm, but he is calling it on an instance.

captainlexington17:06:04

Like, the equivalent of a static method on the Chart class, rather than something a Chart instance has

john17:06:10

@roberto Seems like, insofar as it does what re-frame does... It lenses over your state db/atom and updates it in place, using a declarative rules engine.

roberto17:06:31

that is much more clearer

dealy17:06:08

I've got a < 10 line stack trace, should I post it here or somewhere else?

roberto17:06:21

you can post it here

captainlexington18:06:29

What are you trying to read .value of? The donut?

roberto18:06:40

i think one of the values he is passing might be null

roberto18:06:53

and the constructor for donut is trying to do something with it

roberto18:06:45

what is the link for this library you are using?

dealy18:06:48

I'm not sure what .value is referring to, the things that are passed to the ctor are a couple of maps that I converted with clj->js

dealy18:06:39

there are definitely nil vals in one of the maps, but that is what the example code showed, definitly kinda confusing when the docs and examples are lacking

roberto18:06:52

yeah, that always sucks

roberto18:06:15

from the stack trace, it looks like it is iterating over some object inside the constructor, and one of the fields in the object is nil

dealy18:06:40

well, I was thinking I might have been constructing the object incorrectly, but based on what you guys are saying it looks like my original code was correct, so the problem lies somewhere else

dealy18:06:13

Hah! Found it, I had forgot to call clj->js on the first data structure

dealy18:06:30

Thanks for helping guys

roberto18:06:35

ur welcome

john18:06:54

Yeah, Precept looks bad ass

john18:06:20

I'm unsure why creating a session appears to require scraping a whole namespace for rules... (session my-session 'my-ns.rules) Am I reading that right? Why not just provide the rules as a collection?

roberto18:06:14

yep, that confused me too while going through the Readme

dnolen19:06:28

@john well they are looking for feedback 🙂

john19:06:18

Aye, I'll follow up. Hopefully they start up a #precept channel too 🙂

michaellindon19:06:52

how do i maintain a reference to a map whilst destructuring it at the esame time?

john19:06:07

@michaellindon I think you want :as

john19:06:50

(let [{a :a, b :b, :as all} my-hashmap]
  (println a b all))

john19:06:26

Updated example for map destructuring.

eoliphant19:06:42

hey quick question. I’m using selmer in a luminus generated app, and I want to serve some css that’s in a cljsjs .jar. I tried {% style "/class/path/my.css" %} but that’s not working

john01:06:16

eoliphant: you might want to ping @U050CBXUZ about it. I think he knows quite a bit about selmer.

eoliphant01:06:35

ok will do thx

tech_hutch19:06:45

I also have a quick question. I'm using a framework that, in JS, is started by calling new Komada.Client(...) (where Komada is just the required framework). How would this be done in Clojure, syntactically? I have the framework bound to Komada. I tried ((.-Client Komada). ...), but that throws an error that _SLASH_ is not defined.

spinningtopsofdoom19:06:42

(js/Komada.Client. ...)

spinningtopsofdoom19:06:30

js/Komada gives you the global JavaScript object Komada

spinningtopsofdoom19:06:14

(js/App.Object. <arguments>) is equivalent to new App.Object(<arguments>)

tech_hutch19:06:50

Oh, okay. Thanks.

tech_hutch19:06:10

I didn't know that js was used with more than just global built-in objects.

tech_hutch19:06:42

You said "the global JavaScript object Komada"

tech_hutch19:06:54

It's not global. It's bound using let.

tech_hutch19:06:22

I guess it'd just be (Komada.Client. ...) then?

spinningtopsofdoom19:06:19

How are you binding it in your let?

tech_hutch19:06:05

(let [Komada (js/require "komada")

tech_hutch19:06:30

(That's the first line of my let.)

spinningtopsofdoom19:06:30

I don;t think that will work ClojureScript does not know about CommonJS require's. How are you getting Komada into your project?

tech_hutch19:06:30

Oh, I'm using Node

tech_hutch19:06:30

I'm getting it into my project by installing it with npm

spinningtopsofdoom19:06:58

You'll want to use cljs.nodejs/require then like so

(ns my.app
  (:require [cljs.nodejs :as nodejs]))
(def Komada (nodejs/require "Komada"))

thheller19:06:31

@spinningtopsofdoom that doesn’t matter, it does the same thing

thheller19:06:01

@tech_hutch (new (.-Client Komada) args) should work

thheller19:06:18

js/require is fine (in node)

spinningtopsofdoom19:06:46

@thheller Thanks for the correction, I was mistakenly recalling ClojureScript in the browser

tech_hutch19:06:20

Okay, I forgot about new.

pradyumna20:06:10

I have question about om.next. I see that you can provide IQuery which will be available as props to the component. Also you can pass props to child component. So what happens actually for a child component with both specified? Is it ok not to pass the props to child component with just the IQuery specified?

joshkh21:06:21

does anybody have any experience with sente? my client is connecting to the server just fine, and i'm setting the :uid on the session, but i can't quite figure out how to "reconnect" the websocket so that sente sees the previously anonymous connection with the new :uid

noisesmith21:06:53

when I connect I send my uid, if I have one

noisesmith21:06:57

and that maintains the session

noisesmith21:06:06

(from the frontend point of view)

joshkh21:06:37

hmmm, this is a new user posting credentials to my /login route

joshkh21:06:58

but since it's a single page app i'm not refreshing the page which would then have the uid on the session

noisesmith21:06:12

oh, so you want to explicitly give them a new connection uid? I’ve never done that

noisesmith21:06:24

I’ve only selected uid from frontend

noisesmith21:06:39

(or just allowed a default pick from backend)

joshkh21:06:47

well it's just that the server side connection atom doesn't seem to reflect the :uid

joshkh21:06:33

out of curiosity, do you handle authentication via web sockets? i'm sending back a JWT which then gets sent back with every web socket push. does that make sense or is it totally bananas?

noisesmith21:06:33

that’s what I do

noisesmith21:06:56

and my middleware on the other end of hte websocket checks for the jwt (if it asks for anything that requires auth, which is just about everything)

joshkh21:06:46

roger that

noisesmith21:06:27

I keep the payload small by just sending ids for lookup in the jwt (where info is concerned) and caching the full data to value store on server side

noisesmith21:06:54

but mostly the jwt is there for saying “this is really the person with user id 161”

joshkh21:06:46

so when your client connects, say for the first time, it sends an auto generated uid. your server then sets the uid on the session and sente is all peachy. but if you want to push a message to <mailto:[email protected]|[email protected]>, how do you reconcile that with your client side auto generated id?

joshkh21:06:18

and thanks for bearing with me, i'm pretty new to sockets / sente

noisesmith21:06:42

every message is paired with the requesting client’s current UID

noisesmith21:06:06

so for things that act like request / response I just keep it in those terms

noisesmith21:06:44

for sending to all (or any) websockets belonging to user X my first instinct would be to keep a mapping from user id to socket UIDs (and then from there send to the ones that are still open for that user)

noisesmith21:06:28

since users can have multiple tabs open to my app, I can’t 1->1 map user to tab, which means no 1->1 user to websocket is possible

noisesmith21:06:00

now that I think of it, I should totally make that hash map and propagate it via my auth middleware

joshkh21:06:58

thank you very much for the explanation. that makes loads more sense now.

noisesmith21:06:59

currently I don’t have code that does unsolicited server push to clients - each message starts with the client and gets 0 or more server responses (and all those responses just get uid of user’s websocket from the incoming message)

noisesmith21:06:24

but yeah, with a simple hash-map update I could be doing push to clients too, if I ever need it

joshkh21:06:27

i follow 🙂

adamvh22:06:04

@pradyumna om/IQuery and passing props to your component are very different

adamvh22:06:29

or, rather, when your component implements IQuery, it does so because you expect om next to be passing props to it

adamvh22:06:53

IQuery is mostly plumbing so that om next can know what data your component depends on and schedule re-renders accordingly

joshkh22:06:55

@noisesmith do you happen to have any open source code online somewhere regarding your sente implementation?

noisesmith23:06:46

Not the relevant part, sorry