Fork me on GitHub
#clojurescript
<
2017-05-29
>
sophiago00:05:55

ok, seems to be a hygiene issue. i did in fact need to append a gensym to the var in let (probably would have been obvious if i used macros more than, well, hardly ever)

sophiago00:05:34

@mfikes the only problem remaining is a warning that cljs.core/eval is undefined. that's using it like this: (quasiquote (let [img# (eval ~image)] ...))

sophiago00:05:27

(had to edit since backticks don't play nicely with markdown)

adamvh00:05:58

image is a function defined in your cljs namespace right? and you want to bind your gensym to the result of calling it (at run-time)? if so, i think you can delete the eval and it will all work

sophiago00:05:05

but unquote outside the call, right? like: (quasiquote (let [img# ~(image)] ...))?

adamvh00:05:16

no, unquote inside the call

adamvh00:05:27

unless you want to call image at macroexpansion

sophiago00:05:48

you're right

sophiago00:05:25

finally compiling 😄

sophiago00:05:36

not doing what i want, but that's a separate issue. haha

sophiago00:05:42

thanks so much everyone!

gastove04:05:12

Anyone in here got some experience with routing CLJS-side?

gastove04:05:39

I’m trying to do a Clojure server serving a CLJS frontend; it is, like, 95% working

gastove04:05:01

But the remaining 5% is permalinking

gastove04:05:10

…which I kind of need 🙃

noisesmith04:05:35

what I had good luck with was using the fragment as my frontend dispatch, since without needing to use any trickery, changing the fragment never sends a new request to the server

noisesmith04:05:16

and then encoding any data that would need to be repropagated into the fragment string so that bookmarks would be meaningful (and back / forward button for that matter)

noisesmith04:05:47

then my router looks at the fragment string to find data to propagate, one piece of that being the handler to call to set up the next top level view

noisesmith04:05:13

I use the callback in goog.history to call my dispatcher

gastove04:05:23

So, that sooooounds a lot like what I’m trying to do, at least

gastove04:05:46

Where I’ve gotten is: I can href to fragments together, and my handler will update the page and the route — everything looks fine

noisesmith04:05:52

I didn't want an http style router - I just wanted each view to be a single named entity, no tree structure

gastove04:05:14

But if I, say, open a new browser tab and link directly to something in the app, the whole thing borks

gastove04:05:31

….which, come to think of it, makes me think the underlying webserver is probably swallowing the whole request

noisesmith04:05:54

OK - there are two parts there - making sure that everything needed to recreate the view from scratch is in the fragment, and ensuring the view itself knows how to bootstrap when hit directly

noisesmith04:05:09

the webserver should have nothing to do with this

noisesmith04:05:29

anything that would be recreated based on the fragment should be an explicit ajax or websocket request

noisesmith04:05:04

that is, if it relies on server data (of course)

gastove04:05:26

Ok, that makes sense

noisesmith04:05:53

what we have to look out for in our app is transitions that take for granted that a previous view was present. One way to avoid this is to explicitly erase all page specific data when the fragment navigation occurs, and make sure that every fragment change reconstructs view data (it doesn't have to be super slow if you have a separate non-view-specific data cache)

noisesmith04:05:41

this can be hooked into eg. om-next very easily, but you can also do it with a reagent render atom or whatever other store you like - the fundamental concept is knowing a) where a piece of data would be in the store if you had it and b) knowing how to get it from server if it is not there

noisesmith04:05:03

and the store is the canonical source of data, the view is constructed by pulling in parts of the store to various places in the dom

gastove04:05:34

nodnodnod I follow that

noisesmith04:05:01

also - I found it useful to make the store an explicit arg to the view render

noisesmith04:05:21

that way I could set up tests "if this data is in the store, this regex should match the html"

noisesmith04:05:20

if you have a more concrete problem I'm sure many of us would be happy to help, but that's an overview of making bookmarks / forward button / back button work consistently in my app looked like

noisesmith04:05:47

or even refresh for that matter

gastove04:05:20

nodnodnod that is actually super helpful, thanks!

kurt-o-sys08:05:37

anyone any recommendations for (heuristic) optimization libraries in cljs? The use case is: I have a number of entities with many attributes and have to group them in pairs and, if it's not possible with pairs only, triples. A valid pair or triple depends on the attributes of both (and a pair or triple can be given a score - the exact function is an exercise for me). There can be multiple possibilities, so it would be nice to have like the top 5 solutions (or all solutions, ranked by 'total score'). I was thinking mainly to use methods like evolutionary algorithms and simulated annealing, but there may be others. I'm looking for a cljs lib that's doing this and people have good experiences with.

kurt-o-sys08:05:08

Oh yeah, the number of entities is less than 50, usually between 15 and 30, so this means around 10-15 pairs/triples.

kurt-o-sys08:05:27

The number of attributes/entity is about 20-30.

pseud08:05:39

Anyone here writing their backend stuff in ClojureScript (on Node)? If so, do any of you have any experience to share ? I've only just started evaluating this path and I haven't (yet) fully decided to commit to it, so I am interested in hearing your experiences - especially in regards to REPL & macrowork, Cursive and the like

Roman Liutikov09:05:33

@pseud You should probably talk to @yogthos ad take a look at Macchiato https://macchiato-framework.github.io/

pseud09:05:48

@roman01la - ah, sure 🙂 Wonder how I'll get a hold of him, though, but yes, he ought to have some thoughts. WRT to Macchiato itself though, that part I am not sure I follow. I've been experimenting with Express.js itself and aside form needing a small wrapper to make things more clojure-esque (to me, anyway), it's actually been really neat.

Roman Liutikov09:05:11

@pseud I think it’s fine to use Express, it’s just that Macchiato follows Ring philosophy which is more like idiomatic way of building web servers

pseud09:05:56

Yea, I guess that depends on what you're after. My idea is to use ClojureScript exactly because the underlying environment (Node) is so attractive. To that end, I'm more concerned about making my bits fit with what an average piece of node middleware might expect than conform to the Ring/Clojure world. That said, it's a commendable undertaking

yogthos13:05:47

@pseud note that you can use Node middleware with Macchiato as well, here's an example https://github.com/facundoolano/cljsbin/blob/master/src/cljsbin/core.cljs#L23-L30

yogthos13:05:48

I actually started with the idea of wrapping express.js originally, but found that it really didn't add much

pseud13:05:16

@yogthos So now that I've gotten your attention ... 😉 How's your experience been with using ClojureScript for the backend? I.e. have you noticed any issues using the ClojureScript node REPL (e.g. reloading macro definitions) or with tool integration or what have you.

yogthos13:05:21

it's generally been good, I'm using figwheel to do the compilation and it behaves pretty much same targeting node as the browser

yogthos13:05:34

the only quirk I've ran into is that source maps don't stay in sync

yogthos13:05:21

so if you get an error you have to bounce node process to get the accurate trace

pseud13:05:29

Figwheel? Really now. Hmm, I might have to try that myself. Right now I'm using boot (& boot-cljs), which is nice. However, I'm reloading the app using nodemon which is a low-tech node-tool for basically restarting the process. It works, but it's not exactly glamerous

yogthos13:05:47

but thankfully node doesn't have a long startup time, so it hasn't been too much of an issue

yogthos13:05:25

I have figwheel configured to start cljs repl when it loads, so I just connect the editor to that

yogthos13:05:57

and figwheel doesn't need to be restarted for the sourcemap issue

pseud13:05:48

But aren't you then getting back into the clojurescript "issues" typically seen on the front-end ? That is, defining externs and such - or am I conflating using Figwheel with advanced optimisations in cljs

yogthos13:05:19

you don't need externs with node

yogthos13:05:34

there's no reason to minify js since you're not sending it anywhere 🙂

pseud13:05:59

Yea, exactly. So long as you don't enable advanced optimizations. I guess I was conflating issues then 🙂

yogthos13:05:06

I setup macchiato to use simple optimizations for the release build, and that just packages everything into a single js file

yogthos13:05:42

not having to worry about externs is definitely a plus for node

pseud13:05:21

Definitely (!). Maybe I just haven't found it, but you really should write an article on the nitty-gritty aspects of getting started with ClojureScript on the backend, that is, your thoughts on using figwheel with lein to get going. There's a dearth of good explanations and at least for me, that was a big stumbling block, so I'm guessing it'll make interesting reading. I'd do it myself, but my "hacked in anger" tooling "solution" is a little ugly 😛

yogthos13:05:56

if I get a chance, I'll do a bit of a write up on how I got macchiato setup 🙂

yogthos13:05:40

figwheel definitely made things easy for me

borkdude14:05:17

I expected this to work in ClojureScript: (cljs.reader/read-string (pr-str {:foo/id "foo" :foo/bar "bar"})) Why not?

paulbutcher14:05:41

@yogthos I’m in the very early stages of a new project, and I’m seriously considering AWS Lambda as a deployment platform. I’ve got the basics going on top of cljs-lambda (which is very nice), but I don’t really like the development experience - having to deploy to Lambda to test. I imagine that it should be possible to use Macchiato to run locally, but then deploy to Lambda? Is this something you have any experience with?

noisesmith14:05:11

@borkdude I've seen others talk of this issue - unless or until read-string handles the prefixed map reader, it might be easier to use something like transit?

borkdude14:05:56

@noisesmith I could do that, but our state also has functions. I thought I could get away with this for now while I’m experimenting.

noisesmith14:05:12

oh, right, pr-str preserves functions (sort of)

noisesmith14:05:19

be careful of multi-arity btw

borkdude14:05:32

yeah, I want to strip those out anyway, but first I have to see if this POC works

noisesmith14:05:53

actually - you could tell transit to use pr-str with a #fn tag for functions - it's pretty easy to configure

noisesmith14:05:06

but it's a yak for sure

noisesmith14:05:36

alternatively you could have a pre/post transform that turns :foo/bar into [:namespaced :foo :bar] and visa/versa

noisesmith14:05:48

which is a pain, but with the right keyword would be unambiguous

noisesmith14:05:08

maybe the next cljs will read namespaced maps?

borkdude14:05:58

I’m surprised this is broken. IMO it’s a fundamental thing in Clojure.

borkdude14:05:14

But I guess I can try transit next

noisesmith14:05:01

the keyword-namespaced-map reader tag is very new - but it was clearly only implemented as a writer for cljs, and not a reader

borkdude14:05:04

I’m not sure if that is intended or a bug

noisesmith14:05:28

the printer is intended - not reading it is a bug

yogthos14:05:41

@paulbutcher that definitely sounds like it should be possible, but I don't have any experience using AWS Lambda myself

paulbutcher14:05:18

OK, cool. I might have a bit of a play and see how I get on.

borkdude14:05:43

I’ll file a bug

yogthos14:05:05

@paulbutcher great, keep me posted if you get it working, I could an example for future reference here https://github.com/macchiato-framework/examples

noisesmith14:05:56

cool - I upvoted it

gastove16:05:15

I… feel like I’m losing my mind. This:

(defn page [title]
  (let [page-chan (hit-api "page" title)]
    (go
      (let [new-page (async/<! page-chan)]
        (swap! page-state (fn [_] new-page))))))
Throws <! used not in (go...) block

gastove16:05:59

Is… that…. I swear the word “go” is right there.

gastove16:05:53

This, on the other hand, works fine, but feels ridiculous:

(defn page [title]
  (let [page-chan (hit-api "page" title)]
    (go-loop [new-page (async/<! page-chan)]
      (swap! page-state (fn [_] new-page)))))

dvingo16:05:04

gastove, there are some notes on certain unsupported constructs, maybe that is one of them? https://github.com/clojure/core.async/wiki/Go-Block-Best-Practices#unsupported-constructs-and-other-limitations-in-go-blocks

dvingo16:05:11

it is weird that it works in the loop though

gastove17:05:01

Even better: it has just stopped working in the loop --

gastove17:05:33

Error must be coming from somewhere else, but I haven’t successfully gotten source maps working on this thing yet so I am not… sure from where.

dvingo17:05:30

from the notes, maybe try moving that swap call outside the loop - possibly add a callback argument to the page function that passes the new-page and calls swap there

gastove17:05:43

nodnod I’ll give that a try, thanks

mfikes17:05:57

@gastove FWIW, your first form, making use of go, compiles fine for me.

gastove17:05:18

I’ve just reloaded figwheel and things are… working again? Perhaps I just got in to a weird state w/r/t which code was actually being evaluated?

dvingo17:05:39

nice, party on

clj.max17:05:33

Trying Lumo out and want to read a file using 'fs'. I can get it to work in plain node, but not in Cljs. Anyone done this?

clj.max17:05:01

fs.readFile('file.json', "utf8", (err, data) => console.log(data)) works fine

clj.max17:05:38

(.readFile fs filename "utf8" (fn [err data] (println data))) does nothing

clj.max17:05:58

(oh yea, filename is def'd to the same filename)

clj.max17:05:15

(and when I give it an invalid filename, it errors out)

anmonteiro17:05:16

Lumo 1.5.0
ClojureScript 1.9.542
Node.js v7.10.0
 Docs: (doc function-name-here)
       (find-doc "part-of-name-here")
 Source: (source function-name-here)
 Exit: Control+D or :cljs/quit or exit

cljs.user=>
cljs.user=> (def fs (js/require "fs"))
#'cljs.user/fs
cljs.user=> (.readFile fs "foo.txt" "utf8" (fn [err data] (println data)))
nil
cljs.user=> Hi from Foo


anmonteiro17:05:47

@clj.max which version of Lumo are you using?

clj.max17:05:47

hm that seems quite equivalent

anmonteiro17:05:05

try upgrading to 1.5.0 I guess

anmonteiro17:05:16

are you doing it at the REPL?

clj.max17:05:17

is it on brew?

anmonteiro17:05:25

brew update && brew upgrade

clj.max17:05:33

I have a little .cljs file I run with lumo test.cljs

clj.max17:05:39

awesome, thx

anmonteiro17:05:42

yeah that’s fixed

clj.max17:05:52

lol it works

clj.max17:05:57

zomg i just spent 30 minutes on this^^

clj.max17:05:59

thanks dude 🙂

anmonteiro17:05:39

there was a regression in 1.4

clj.max17:05:50

no worries I guess it's pretty new 😉

clj.max17:05:55

i'm just messing around anyway

clj.max17:05:03

but sooo nice not to have startup time of JVM

clj.max17:05:15

I don't even know why but those 4 seconds feel like months

clj.max18:05:40

when using (JSON/parse ..) I get the warning No such namespace: JSON, could not locate JSON.cljs. It still works though. Do I need to require JSON or silence the warning or something?

mfikes18:05:46

@clj.max Anything before / implies a namespace. You can instead use the pseudo-namespace js to cause equivalent JavaScript to be emitted: (js/JSON.parse ...)

clj.max18:05:32

I had tried js/JSON/parse but that wasn't a thing 😉

clj.max19:05:59

by the way, I find the Lumo error messages pretty helpful. are they different from regular Clojure ones? I like the little arrow and the stack trace being succinct

anmonteiro19:05:25

achievement unlocked, I guess

anmonteiro19:05:40

inspiration was taken from Planck though, gotta give credit to @mfikes

clj.max21:05:40

@anmonteiro is there some kind of println flushing?

clj.max21:05:14

I'm doing a bunch of println in a ->>, and it doesn't print anything unless I put a "println" in the ->> afterwards

clj.max21:05:19

even if it just prints (nil nil nil)

anmonteiro21:05:42

it might just be that you’re doing lazy evaluation?

clj.max21:05:50

uh how do I tell

anmonteiro21:05:58

are you using map, etc

anmonteiro21:05:06

those are lazy 🙂

clj.max21:05:18

is doseq eager?

clj.max21:05:32

i'll try that then

clj.max21:05:58

is there a better way to thread into doseq than creating a fn like this?

(defn print-lines [lines]
  (doseq [l lines]
    (println l)))

anmonteiro21:05:16

(run! println lines)?

clj.max21:05:57

it does work 🙂

clj.max21:05:04

now i have to look up what run! does I guess

clj.max21:05:45

just doseq w/o the vector stuff?

anmonteiro21:05:38

run! is like map but for side-effects

anmonteiro21:05:39

and returns nil

clj.max21:05:10

cool, like forEach? I thought doseq was for that

gordon22:05:21

@clj.max they're similar, but doseq has those bindings and run! does not