Fork me on GitHub
#clojurescript
<
2017-02-24
>
pesterhazy00:02:48

@uwo, what I've done in the past is to store only serializable values in my state atom

pesterhazy00:02:41

and use local state (a closure-bound ratom) for ephemeral resources like timers, dom nodes etc.

tech_hutch00:02:34

Is it possible to eval code in ClojureScript? Searching has brought conflicting and confusing answers.

darwin00:02:23

@tech_hutch no, unless you are running self-hosted clojurescript

tech_hutch00:02:21

I am. I'm running in node.

darwin00:02:20

I doubt it, running in node does not automatically mean using self-hosted clojurescript

tech_hutch00:02:40

Oh? Then I'm not sure what you mean.

pesterhazy00:02:22

are you using lumo?

tech_hutch00:02:39

(I don't know what that is.)

isak00:02:06

self hosted means you bake in a verison of the clojurescript compiler runnable in javascript in your app, very few apps do this

tech_hutch00:02:52

Oh. I would like to do that.

isak00:02:04

for most apps it is basically a dev dependency, not a runtime dependency

tech_hutch00:02:22

Okay, thanks.

tech_hutch00:02:28

(This is just a personal project.)

pesterhazy00:02:25

In lumo you can do

(require 'lumo.repl) (lumo.repl/execute "text" "(js/console.log \"hello\")")

anmonteiro00:02:33

^ which is a private API and may break eventually 🙂

anmonteiro00:02:52

you should use the officially supported cljs.js API

darwin00:02:58

depends on your goals, it is fine for greenfield projects or toy examples, but be aware that in self-hosted mode macros have to be written in a way which does not expect JVM under the hood, which could limit possible set of 3rd party libraries available

pesterhazy00:02:57

actually these days a lot of stuff just works

tech_hutch00:02:15

That's okay. I'm not planning on messing with macros.

tech_hutch00:02:28

Does anyone have a link to the docs? The links in the article don't work.

anmonteiro00:02:51

@tech_hutch you should be aware that the self-hosted API is for advanced users and I wouldn’t recommend using it if you’re just starting out

tech_hutch00:02:19

I'm just looking for simple evaling of strings.

anmonteiro00:02:36

that said, I don’t think there are official docs, but you can read the docstrings? https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/js.cljs

anmonteiro00:02:04

freebie example for evaluating a string:

(require '[cljs.js :as cljs])

(def st (cljs/empty-state))

(cljs/eval-str st "(+ 1 2)" prn)

anmonteiro00:02:22

ClojureScript doesn’t have eval like Clojure

tech_hutch00:02:00

Okay, thanks.

pesterhazy00:02:25

@anmonteiro is there a reason why cljs.js doesn't have separate read and eval phases?

anmonteiro00:02:59

@pesterhazy there is cljs.js/analyze-str and cljs.js/compile-str

pesterhazy00:02:09

oh I though that's waht you meant by "ClojureScript doesn’t have eval like Clojure"

anmonteiro00:02:28

no I meant that there’s no cljs.core/eval like there is clojure.core/eval

anmonteiro00:02:39

simply because ClojureScript’s compilation model will never support it

tech_hutch00:02:51

@anmonteiro I'm getting {:error #error {:message "ERROR", :data {:tag :cljs/analysis-error}, :cause #object[Error Error: No *eval-fn* set]}}. Do I need to, e.g., pass an eval function as an option?

anmonteiro00:02:13

(cljs/eval-str st "(+ 1 2)" nil {:eval #(js/eval (:source %))} prn)

anmonteiro00:02:23

^ I revised the last line of my snippet above

tech_hutch00:02:39

Is it necessary or beneficial to wrap js/eval in a lambda, like that?

tech_hutch00:02:45

Thanks, by the way

tech_hutch01:02:36

Also, that worked! Thanks!

anmonteiro01:02:02

well, there are other ways to make it work without a lambda

anmonteiro01:02:29

(cljs/eval-str st "(+ 1 2)" nil {:eval (comp js/eval :source )} prn)

anmonteiro01:02:48

but you ultimately need to extract the :source from the map that the eval-fn is passed

tech_hutch01:02:01

I only asked because the article above just passed js/eval directly.

anmonteiro01:02:25

I don’t think js/eval can understand the ClojureScript map that is passed to it?

anmonteiro01:02:53

you’ll get a very weird result if you do that

Pablo Fernandez06:02:23

How do I write the equivalent of <Input value={this.state.name} onChange={this.handleChange.bind(this, 'name')} /> in ClojureScript/Reagent? Specially, the onChange part.

iku00088806:02:48

@pupeno something along [:input {:value stuff :on-change (fn [event] ...)}] ?

Pablo Fernandez06:02:26

@iku000888 yes, I got that part, the on-change is what I'm missing in a way that works properly.

iku00088806:02:24

Ah, sorry about that.

iku00088806:02:41

What is supposed to happen in this.handleChange.bind(this, 'name') ?

Pablo Fernandez06:02:02

Update the state without triggering a re-rendering of the element that will cause the cursor to jump to the end of the text.

iku00088806:02:22

Hm, so updating an atom somewhere won't do?

Pablo Fernandez06:02:57

Updating the atom triggers a re-rendering.

iku00088807:02:47

Can't figure out, sorry. But please do let me know if you happen to get a clue. I also have some problems trying to fine tune re-rendering.

iku00088807:02:38

That component does seem to do a lot...

iku00088807:02:02

Perhaps use it directly with reagent's create-element? (Never done it my self...)

iku00088807:02:57

current-component

iku00088807:02:21

Will apparently give you access to 'this'

Pablo Fernandez07:02:45

I'm not entirely sure what you mean.

Pablo Fernandez07:02:25

I mean, that creates a react element, when I'm trying to use a react element. I'm actually writing the library to make it usable for everybody.

iku00088807:02:59

Oh that is cool!

iku00088807:02:27

Sorry I know too little to be of any help, but that is a great cause...

iku00088807:02:44

Will make use of those one day...!

iku00088807:02:22

I do have some pain points controlling re-rendering too, but has been on the bottom of the TODO for ever...

Pablo Fernandez07:02:58

With the latest Reagent in plain inputs, it seems to work ok. At least with my Free-from library there are no issues that I know of.

pesterhazy08:02:24

@pupeno you're running into the classic problem with reagent and input elements

pesterhazy08:02:27

Reagent has special logic to prevent the jumping cursor when you use a [:input]

Pablo Fernandez08:02:53

I know. But I though 0.6.0 helped with this.

pesterhazy08:02:13

but if you use a 3rd party library that wraps inputs, Reagent has no way of knowing it's dealing with an input field

Pablo Fernandez08:02:21

What about when I don't use an html input? How do I apply said magic?

pesterhazy08:02:25

the same issue arose a while ago for the semantic-ui React library

pesterhazy08:02:32

and also I think in React Native

pesterhazy08:02:03

i.e. it arises whenever a controlled input field is used, which is not using Reagent's code

qqq08:02:24

@pupeno: is re-com an option? I've had great experience with their UI lib

pesterhazy08:02:27

so I think the first step would be to discover the root cause of the jumping

pesterhazy08:02:05

I think (but am not 100% sure) the reason is that Reagent (but not React) works asynchronously and batches updates

pesterhazy08:02:56

that's a performance optimization but in this case it causes the input field not to be updated quickly enough

pesterhazy08:02:18

one thing to try is to force updates on every on-change event

pesterhazy08:02:59

there's a flush function in reagent

pesterhazy08:02:34

another thing to try would be to use component-local state (manually accessing .-state this, not through Reagent's helpers), which should trigger immediate updates

pesterhazy08:02:08

but in that case I'm not sure how you would sync with a ratom

pesterhazy08:02:34

finally you could look into Reagent's magic, but it's unfortunately a bit opaque

Pablo Fernandez08:02:58

qqq: no, I wouldn't be making my own if I find something I liked already 😉

Pablo Fernandez08:02:18

@pesterhazy I thought the issue was plain re rendering of the component. Why would batches updates cause an issue?

pesterhazy08:02:50

well go forth and find out! 🙂

Pablo Fernandez08:02:09

I'll do. Thanks a lot for the info.

pesterhazy08:02:45

please report back, this is a hard-ish problem that has bitten many people before so it'd be great to have a recipe for solving this

Pablo Fernandez09:02:19

Good to know. Maybe I'll blog it.

metametadata10:02:35

@pupeno @iku000888 @pesterhazy I had the similar problem with inputs while using react-bootstrap+`Reagent`, here's the fix I use: https://gist.github.com/metametadata/3b4e9d5d767dfdfe85ad7f3773696a60

pesterhazy11:02:08

@metametadata what's the key change in the snippet? force-update?

metametadata11:02:22

@pesterhazy yes. So that - in my understanding - React's virtual DOM is immediately aware of the current DOM value and on next frame doesn't try to render the stale input value (which will lead to cursor jump on the frame after that).

pesterhazy11:02:12

ok that's what I thought

pesterhazy11:02:15

great solution btw ! the only thing I wondered about is if updating the atom in should-component-update may be dangerous (it should be free of side-effects)

metametadata11:02:26

@pesterhazy it just changes a local atom so I guess it shouldn't be dangerous

metametadata11:02:16

Yeah, maybe it is more correct to reset the local atom in componentWillReceiveProps. I don't remember why I preferred the current solution. Maybe it's less code this way )

pesterhazy11:02:29

I'm wondering if there could be a general Higher Order Component for this type of thing

metametadata11:02:59

but I didn't have time to extract it and test with different libs

metametadata11:02:03

I think all that is required is passing the "input" component (such component must have value and on-change props) as a parameter instead of using hardcoded react-bootstrap/FormControl

pesterhazy11:02:10

still it's interesting that the Reagent source contains significantly more complicated logic

metametadata11:02:30

it probably takes in account IE issues which I haven't encountered

Jon11:02:27

@thheller ...follow ups to yesterday's Object.freeze issue, I received comment that they use Object.defineProperty(My.prototype, 'toString', { value: function () {return 'My'}}) to set toString properly when they use Object.freeze(Object.prototype). I guess I can never make Google write code in that way. 😂

thheller12:02:05

@jiyinyiyong you can write a closure compiler pass that just rewrites the one form to the other for you

thheller12:02:10

no idea how that would work with :advanced compilation but it should just work

thheller12:02:35

doesn't have to be a closure pass, could use babel for it as well

thheller12:02:47

anything that can rewrite JS code really

darwin12:02:17

what about (js* “some js code here”) ?

thheller12:02:34

@darwin it isn't CLJS, it is the closure library itself

thheller12:02:23

@jiyinyiyong if you write a function that takes a string of JS code and returns the modified version the rest will be very simple

Jon12:02:50

It can be as complicated as AST rewriting...

Jon12:02:12

I don't think a regex is enough for this case

thheller12:02:23

yeah definitely no regex

Jon14:02:38

thheller: problem is that's quite large file, processing a large file would be really slow

thheller14:02:34

I meant you can process each file individually, only doing it once

thheller14:02:50

that should be pretty fast

thheller14:02:22

I wrote a closure compiler pass that optimizes some CLJS related things and that is basically not noticeable performance wise

thheller14:02:41

10ms or so for an :advanced compiled build

thheller14:02:46

so just one file should be fast

thheller14:02:26

this replaces every call to new cljs.core.Keyword... with a global name

thheller14:02:34

ensuring that every keyword is only allocated once

thheller14:02:46

basically what :emit-constants for CLJS does but better 😉

thheller14:02:18

it isn't that scary and yours should be a lot simpler

thheller14:02:35

this is only the relevant bit

thheller14:02:36

but yeah it was a lot of work trying to figure out how closure works 😉

Jon16:02:19

Thanks. Can't imagine how much work I need to do. I don't write Java, so that thing just not in my plan.

thheller17:02:51

@jiyinyiyong like I said, it doesn't have to use Closure. babel would in theory let you write it in CLJS. well you could write the closure pass in CLJ as well but babel is probably a lot simpler

Jon03:02:09

I don't get it. I think Babel is only transpiling ES6+ to ES5 ?

thheller12:02:31

but AST rewriting is really simple

Jon12:02:03

no.. giving up

jaimeagudo12:02:00

Hi guys, trying to follow https://github.com/bhauman/lein-figwheel/wiki/Node.js-development-with-figwheel#nodejs-standalone-application-development-with-figwheel after running

$ node target/server_out/figwheel4node_server_with_figwheel.js          
Hello from the Node!
Figwheel: Can't start Figwheel!! Please make sure ws is installed
 do -> 'npm install ws'

Pablo Fernandez12:02:35

If I have a reagent component and I don't know if it's form 1, 2 or 3. How can I wrap it so that I can preprocess arguments passed to it?

thheller12:02:37

@jaimeagudo which directory did you run it in? make sure the node_modules directory it created is somewhere node can find it

jaimeagudo12:02:24

I ran it on the root folder (the same project.clj lives in)

thheller12:02:40

node and then require("ws") works I guess?

jaimeagudo12:02:18

many thanks, I haven't tried but I am in the middle of upgrading node to 7.6.0, will keep you posted 🙂

jaimeagudo12:02:34

I was in 5.8.0

jaimeagudo12:02:46

cool! it works on 7.6.0 😄

metametadata13:02:44

@pupeno users always invoke the component as [my-component arg1 arg2 ...], so why would you care which form is used for component implementation?

Pablo Fernandez13:02:55

There are ways of wrapping a component with a function that only works for fomr-1 or form-2 but not both.

Pablo Fernandez13:02:06

I think I figured out a generic way.

pesterhazy13:02:35

not sure what you mean @pupeno?

Pablo Fernandez13:02:31

What do I mean why what?

pesterhazy13:02:58

"ways of wrapping a component with a function that only works for fomr-1 or form-2 but not both"

tomaas14:02:15

my bad, sorry

borkdude15:02:52

Just checking, but JS still doesn’t have a do like construct except for an anonymous function that you call once right?

val_waeselynck15:02:43

not sure if it's an expression or a statement though.

Roman Liutikov15:02:16

@borkdude there’s a proposal for do expressions

borkdude15:02:30

@val_waeselynck That looks only like new scoping rules. I was thinking of using something like this in JSX: { console.log(‘foo’); return 1; } which only works when you wrap it in a anon fun

borkdude15:02:20

Hmm, you can do it right now with comma’s?

borkdude15:02:01

Not sure if that works

borkdude15:02:38

but yeah, that proposal looks good

Roman Liutikov15:02:00

yeah, lispy JS with commas would work 🙂

borkdude15:02:52

@roman01la x = console.log('foo'), 1 this doesn’t yield x = 1 in my browser?

Roman Liutikov15:02:47

@borkdude bc you assigned result of logging to x which is undefined

borkdude15:02:25

Ah, x = (console.log('foo'), 1) works.

borkdude15:02:35

so I could use that in JSX I guess

borkdude15:02:28

(1,2,3) == 3, interesting

Roman Liutikov15:02:58

yeah, returns the last value always

borkdude15:02:08

how is that construct called?

Roman Liutikov15:02:24

hmmm, basically converting everything to expression

borkdude15:02:44

nothing I can google?

borkdude15:02:58

So that basically is already do. Then what is the point of adding do to the language?

thheller15:02:43

@borkdude why are you trying to do this in the first place? JS really isn't meant for this 🙂 (1,if (foo) ... nevermind ...)

thheller15:02:52

debugMe(<Foo>...) doesn't work?

borkdude15:02:02

so things like {(console.log(x), x)}

thheller15:02:26

function debugMe(x) { console.log(x); return x; }

borkdude15:02:10

yeah, possible. I just wondered why JS didn’t have anything like do, but turns out it does

Roman Liutikov15:02:02

I guess because wrapping statements into parens won't work

thheller15:02:39

well that isn't exactly do, but as long as your issue is solved who cares 😉

borkdude15:02:47

@roman01la @thheller true, it’s more limited.

borkdude16:02:05

if I’m now using cljsjs to use React Virtualized, but I want to be able to step through its code (which the UMD build is not so suited for), what’s my best option? Basically I want to be able to step through this function: https://github.com/bvaughn/react-virtualized/blob/ad6200c15844a5585032e2848b8fd90af3e66143/source/InfiniteLoader/InfiniteLoader.js#L106 I could download it and add the files to resources, but I’m not sure how to add it as a foreign library that way...

mruzekw17:02:21

Has anyone used bidi and pushy together? I’m having trouble setting things up

mruzekw17:02:02

Never mind, I think I got it!

borkdude18:02:39

Ah unpacking the jar into the resource folder allows me to override and edit the file 🙂

PB21:02:02

Hey all: Is there a reason I cannot iterate through a javascript object using for or map? I get the following error: Uncaught Error: [object Object] is not ISeqable

thheller21:02:37

@petr can't really tell you why other than it probably wouldn't be a good idea, as it would iterate over the objects toString method

thheller21:02:54

but there are utility functions in goog.object like getKeys and getValues

thheller21:02:18

those return arrays which you can iterate over

PB21:02:08

Thank you!

cldwalker22:02:07

Anyone use any clojurescript testing libs for react apps, particularly for functional testing? I’ve only seen https://github.com/bensu/cljs-react-test

anmonteiro22:02:33

@cldwalker I normally just use React’s ShallowRenderer from test utils

qqq22:02:25

does cljs support exact integers? I read that all cljs numbers map to js doubles -- which are not BigInts

thheller22:02:08

@qqq numbers are native JS numbers yes, so yes they are not ints

qqq22:02:48

@thheller: so I need arbitrary precision Ints; any recommened libraries?

dnolen23:02:28

@piotr2b I would use an older version of ClojureScript for now