Fork me on GitHub
#clojurescript
<
2017-03-07
>
mruzekw00:03:35

Has anyone used bidi? I’m having trouble setting up a route with multiple URL params

mruzekw00:03:36

Nvm I think I got it

kenny00:03:59

@mruzekw We use bide [1] in our app. Not sure if this is helpful but this is how you'd do it in bide:

(def routes (r/router [["/api/users/:id/:foo" :user-by-id-by-foo]]))
=> #'cljs.user/routes
(r/match routes "/api/users/1/2")
=> [:user-by-id-by-foo {:id "1", :foo "2"} nil]
[1] https://github.com/funcool/bide

mruzekw00:03:50

Oo that looks nice, compared to what I came up with

kenny00:03:01

Bide is nice and simple. It doesn't have as many features as bidi but we wouldn't use those features anyway so bide works great.

mruzekw00:03:34

I’ll give it a look. Thanks!

qqq03:03:20

is there any tool that does a dumb line by line translation of js into cljs ?

qqq03:03:40

there's some sample code that I need to rewrite in cljs; and I'd prefer to do js -> badly written cljs -> clean cljs

tbaldridge03:03:00

JS isn't badly written cljs....it's like saying a paper airplane is just a badly designed 747 😛

qqq03:03:08

it's more like: I need to do XYZ. There are no tutorials for doing XYZ in cljs. There are 10 tutorials for doing XYZ in js. Damn it, now I have to convert this js code to cljs, then refactor it into idiomatic cljs.

qqq03:03:41

and the first step is just tedioius conversion of = into set! and other pure mechanical things

jdeisenberg05:03:19

qqq: While you could do a translation of = to set!, etc., the result would be far from idiomatic ClojureScript. As long as you are going to clean up the code, it might be better to analyze what the original JS does, then translate it into a functional style for cljs. If your sample code is small, it is do-able by hand. If you have 10000 lines of code, then automating that is a serious AI problem 🙂

qqq06:03:29

I mentioend two steps, js -> ugly cljs -> clean cljs

qqq06:03:41

= to set! is part of the "js -> ugly cljs" step, and should be automagatable

qqq06:03:50

the "ugly cljs" is literally a line by line transcription of js into cljs

tech_hutch17:03:12

Actually, I wouldn't mind being pinged if you find such a tool 🙂

jdeisenberg19:03:08

I agree; it can be automated. I’m just not sure if it will make the ultimate translation from imperative design to functional design significantly easier.

qqq22:03:50

@tech_hutch @U47NLKWQY : I just like playing with working code -- having poorly written (but running cljs_ code around is useful, as I can incremental make changes, and still test if it works

tech_hutch22:03:52

I found that through searching, @qqq. It's a start.

piotr-yuxuan09:03:33

@isak thanks for your detailed answers! @qqq thanks for your feedback 🙂

danielgrosse10:03:51

I try the usage of modules after the description on https://clojurescript.org/guides/javascript-modules. But when I run lein trampoline run -m clojure.main watch.clj The error main class clojure.main is not found

danielgrosse10:03:02

What do I need additional?

danielgrosse11:03:33

Hm. Maybe a typo. After copy and pasting the project.clj again it works.

danielgrosse11:03:40

Next one in the tutorial. While running the repl I changed the hello.js and reloaded it, but got this error thrown:

danielgrosse11:03:42

(require '[js.hello :as hello] :reload)
SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode
    at Object.exports.runInThisContext (vm.js:53:16)
    at nodeGlobalRequire (repl:87:6)
    at global.CLOSURE_IMPORT_SCRIPT (repl:75:3)
    at Object.goog.require (repl:21:8)
    at repl:1:6
    at Object.exports.runInThisContext (vm.js:54:17)
    at Domain.<anonymous> ([stdin]:50:34)
    at Domain.run (domain.js:228:14)
    at Socket.<anonymous> ([stdin]:49:25)
    at emitOne (events.js:77:13)
`

danielgrosse11:03:41

Adding "use strict"; doesn't resolve the error, neither adding :language-out :ecmascript6-strict to the repl options

qqq11:03:56

does org.clojure/core.async "0.3.441" also provide core.async for cljs ? if not, what package do I need ?

mrchance12:03:58

@qqq You need something else for self hosted cljs though: https://github.com/mfikes/andare

qqq13:03:42

@mrchance: using jvm hosted cljs, not cljs hosted cljs

fearphage16:03:18

What's the equivalent of npm outdated for cljs?

fearphage17:03:39

Does cljs have any problems with openjdk or is it not recommended at all?

pesterhazy17:03:33

it should work. why wouldn't it?

fearphage17:03:35

I was just curious. I wanted to make sure I wasn't pre-shooting myself in the foot.

dnolen17:03:09

@fearphage not aware of anything, but the issue probably would not be with ClojureScript anyway - Clojure or the ClojureScript compiler deps

fearphage17:03:37

You are correct, but I can't say that was obvious from looking at a java error.

tech_hutch17:03:02

How can one await a JavaScript promise, like the ES8 keyword await? Could deref (or the @ reader macro) be used for that? For that matter, are CLJS promises implemented as JS promises internally? I can't find much online about this.

pesterhazy17:03:17

@tech_hutch what do you mean by "CLJS promises"?

tech_hutch17:03:18

Clojure has promises. I thought ClojureScript did, but maybe not.

pesterhazy17:03:49

no it doesn't have promises as a language feature

tech_hutch17:03:22

Clojure or ClojureScript?

pesterhazy17:03:02

clojurescript 🙂

tbaldridge17:03:28

@tech_hutch there's quite a few caveats with JS's promises, and await in general. So we tend to prefer other methods of handling async operations

tbaldridge17:03:54

core.async is one, but frameworks like Om.next and Reframe have other methods

pesterhazy17:03:55

I'm curious, can async/await be transpiled to ES5?

tech_hutch17:03:02

I believe so

tbaldridge17:03:23

in which case it's basically the same thing as core.async's go

tech_hutch17:03:01

If I have to work with a JS promise-based library, can they be awaited in CLJS?

pesterhazy17:03:40

you'd need to write a macro that does a similar transformation to await I imagine

tbaldridge17:03:02

can't you just do (.then p (fn [] ...))

fearphage17:03:22

await is es8?! Whoa. It's already in node 7.4+.

pesterhazy17:03:56

@tbaldridge maybe I'm hazy about the details

tech_hutch17:03:14

I could use then, but I would prefer not to have the nesting.

pesterhazy17:03:14

the problem is going to come up as libraries likes react-native start using async/await all over the place, and we cljs programmers need to interact with them

anmonteiro17:03:35

@tech_hutch so one thing you can do is use promises + core.async to avoid nesting

anmonteiro17:03:47

which I wouldn’t recommend if you’re just starting out

anmonteiro17:03:49

but nevertheless

pesterhazy17:03:57

react-native already uses promises heavily in its public api

anmonteiro17:03:18

(.then some-promise #(async/put! chan %))

anmonteiro17:03:38

^ something like that, and take the value out of the channel in a go block

tech_hutch17:03:53

Okay. I'm new to using channels, but I'll look into it.

pesterhazy17:03:43

there's a blog post waiting to be written: "Help! I need to use ES6 promises from clojurscript. what are my options?"

tech_hutch17:03:20

Oh, is that your blog? lol

darwin17:03:37

let’s await for a blog post (with no timeout)

dnolen17:03:31

I don’t see how ES6 promises pose any problems for ClojureScript, nor async/await

fossifoo18:03:35

hi. any hints on how to use goog.crypt when running on node? i get No such namespace: crypt, could not locate crypt.cljs, crypt.cljc, or Closure namespace "" at line 23 src/helper$1/core.cljs

fossifoo18:03:42

ah, disregard that, it was an artefact of how i run this i think

shader19:03:48

what's the best way to communicate env-ish config to clojurescript, so that it can point to different api servers in dev vs production?

jr19:03:06

<script id="app-config" type="application/edn">{:api-host ""}</script>

darwin19:03:09

@shader I would use env vars and emit them into cljs code using macros

darwin19:03:27

more fancy way is to use :external-config in cljs compiler options and again read them using a macro and emit into cljs

darwin19:03:38

actually this is a better example, I read :external-config and env config via macros, emit them into cljs, and during runtime initialization I merge them into a final map (along with default config) and make it available to my code at runtime: https://github.com/binaryage/cljs-devtools/blob/master/src/lib/devtools/prefs.clj#L16 https://github.com/binaryage/cljs-devtools/blob/master/src/lib/devtools/prefs.clj#L33 https://github.com/binaryage/cljs-devtools/blob/master/src/lib/devtools/prefs.cljs#L24

tech_hutch19:03:44

@dnolen well, how would you async/await? There's no way to tell the compiler to output the await keyword in the JS code, and my understanding of async/await says that you can't just make a JS function that uses await because that would be awaiting in another function.

anmonteiro19:03:31

@tech_hutch the ClojureScript compiler outputs ES3, so no async or await

anmonteiro19:03:54

but an async function just returns a promise AFAIK, so you can use then, which CLJS supports

darwin19:03:50

and any promise which is created by cljs code, can by used with await in js code, I would assume

tech_hutch19:03:52

That's the thing. I'd rather not have to chain .thens. I suppose I'd have to convert to channels to get similar behavior.

tech_hutch19:03:21

darwin, to use await I'd have to write any code that uses it in JavaScript, then.

darwin19:03:39

but await is just a sugar on top of promises so it is not strictly needed to use it in cljs, use js/Promise stuff directly and when it gets too complex, translate them into channels and use core.async instead

darwin19:03:40

I believe channels are general versions of promises (they can handle multiple items), so you can use channels as a promise replacement. In other words should be able to convert all promises to channels, and the same channels back to promises. @anmonteiro gave you an example how to wrap a promise into a channel. You can do similar wrapping the other way, by wrapping a channel in a promise. That channel has to handle only single put! and resolve the promise and then close~ (or ignore/throw on more puts).

darwin19:03:18

I wonder if there is a nice library for converting various async primitives between each other in cljs

darwin19:03:22

I have some half-baked functions here, but to-promise code-path is missing, and it looks like turn-callback-into-channel cannot be implemented: https://github.com/binaryage/dirac/blob/6b65f0ab4a636a6120757fe996329bffbdb1a560/src/shared/dirac/utils.cljs#L42-L80

tbaldridge20:03:00

@darwin what is the problem you're seeing with turn-callback-into-channel?

tbaldridge20:03:27

or I guess, what's the idea behind that function?

darwin20:03:48

let me think about it 🙂 I don’t remember exactly

darwin20:03:20

But general idea of to-callback is to turn any async-thingy into a series of calls to a provided callback function, and to-channel should do similar a thing, it should get some async-thing and turn it into a proper channel

darwin20:03:46

I thought any async primitive should be convertible both ways

darwin20:03:44

ah, now I recall, turn-callback-into-channel would want to return a channel and put! into it every time callback gets called, the problem is that I cannot mutate the callback passed, wrapping is easy, but that would create a new function, but in this case I would need to do it in-place, because I don’t control caller’s usage of the callback fn

mobileink20:03:54

is it just me or is server side "rendering" bs? afaik, it means sth like "serialization to a string", whereas client side rendering means "whack the dom". am i missing sth? isn't whole point of reactish stuff like om that the concept of "render" on the client has a "special" meaning, i.e. whack only the bits that need whacking?

darwin20:03:09

I would need to install some kind of "observer” on existing js function calls, which is not possible I think

tech_hutch20:03:38

Maybe you could have the user wrap their callback in a function, or something.

tech_hutch20:03:00

Also, thanks for the help. I'm going to try channels.

darwin20:03:38

the problem is that the user is not me, they live in javascript land and they wrote the code before me

tech_hutch20:03:36

You could still give them a function to wrap theirs in, couldn't you?

tech_hutch20:03:01

Oh, never mind.

tech_hutch20:03:42

Is this for CLJS users, JS users, or both?

darwin20:03:27

imagine: at the point when to-callback is called, the callback function (parameter) could have been used somewhere and registered in “async events sources” already, me wrapping it won’t capture those usages

darwin20:03:01

in ideal world, I would require user of my api to first call to-callback, I give them wrapped function back, and then they go and register it somewhere to be called

darwin20:03:27

but this is not guaranteed in general case, that was the point

darwin20:03:35

I would need a mechanism where given an existing function, I install some kind of observer for invoked calls on it

tech_hutch20:03:41

Okay, I understand.

tech_hutch20:03:11

You could require a wrapper, but it wouldn't work in all circumstances.

tech_hutch20:03:41

Yeah, I don't think any functionality like that exists in JS right now.

tech_hutch20:03:15

There probably won't be in the future, either, or at least I hope not. Having the possibility of side effects that happen when a function is called, but do not happen as a result of what is done in the function, sounds like a horrible idea.

qqq22:03:26

@mobileink: I think the theorey behind server side renering is that it gets you the initial state faster; instead of (1) send client js, (2) client run js, (3) client requests more data, (4) client renders a page; it's -- server computes entire initial state + send over js

mobileink22:03:17

@qqq: ok, but that’s not “rendering”. it’s just serialization.

mobileink22:03:09

rendering is all about side-effects on the client, as far as I can tell.

mobileink22:03:46

it just confuses things to call it the same thing on server and client sides, imo.

mobileink22:03:27

there’s a huge and very profound difference, IMHO. On the server side, “render” (=serialize) is functional: you give it some args and it returns a value - serialized HTML, let’s say. on the client side, it is co-functional - you give it some arguments, and it generates some side-effects. completely different animal, as far as I can tell. trivial? maybe, but I think it makes a big difference for noobs. speaking personally, I was just googling this stuff (in particular native react and “server side rendering”) and I had no idea what that was supposed to mean. i’m still not sure. maybe there’s more going on than I’m aware of. but that’s the problem: the language is unrevealing.

mobileink22:03:18

it makes everything seem the same, falsely.

qqq22:03:46

@mobileink : I have never used server side rendering; so this may be completely wrong; I was under the impression all it did was reduce some latency: i.e. the HTML sent over the wire is whatthe client would have rendered after it fetched its data

tbaldridge22:03:21

@mobileink there's quite a few functional ways to do client side stuff

tbaldridge22:03:47

Om.Next is one, Quiescent as well. You have data->view transform->data, then that data is diffed against the DOM. So your application remains functionally pure. You can even test your UI with stuff like generative testing.

mobileink22:03:35

@tbaldridge yes and no. anything that updates the dom is not funtional, by definition.

mobileink22:03:33

just like ns, def and defn are non-functional.

tbaldridge22:03:51

Right, the DOM is purely a IO device at that point, a write-only IO device

mobileink22:03:56

imho this is an important conceptual distinction, even if it can be overlooked without problem.

tbaldridge23:03:08

So you treat it just like the network port on your machine and put it at the edges of your app

mobileink23:03:59

indeed it is just like the network, except the connections are implicit.

mobileink23:03:39

but in the Big Conceptual Picture, such distinctions are important.

tbaldridge23:03:19

I disagree, the the connections are explicit...

mobileink23:03:58

example: contrary to popular opinion HTML is not only a programming language, it's a "pure" programming language. it programs machines, i.e. browsers. it just happens to be co-functional rather than functional.

tbaldridge23:03:09

In something like Quiescent, you get your root dom element, and then in one location you call (render dom data-that-describes-my-dom)

mobileink23:03:57

where's the connection? you don't need to give a network address ans port.

tbaldridge23:03:15

the dom (in my example) is the connection

tbaldridge23:03:30

"connection"

mobileink23:03:19

where is the dom? it's not in your app space, it's on the other side of an implicit connection. if it were explicit, we would have to give an address and port for every dom operation

mobileink23:03:05

dom ops look like functions, but they're not.

tbaldridge23:03:08

well let's backup, you were saying that server-size rendering is inherently more functional than client-side rendering. Or did I misunderstand

tbaldridge23:03:43

Server side rendering is data->pure function->html->bytestream->tcp stream (aka IO). Client side is data->pure-function->data->dom differ (aka IO)

mobileink23:03:39

what i understand by SSR is "serialize". you get a string; that's functional. then you send it to the browser; that's not functional, but it also has nothing to do with "rendering", if by that you mean displaying in a window.

tbaldridge23:03:52

I'm saying that sending a string via SSR is not pure, that's called IO. In the same way you can program client side rendering as data transformation to IO (the dom differ).

mobileink23:03:02

my complaint is that using the same term ("render") on both sides is deeply misleading

mobileink23:03:04

what does "send a string via SSR" mean?

mobileink23:03:17

(in case it isn't obvious i'm a tad fanatical about terminology 😉 )

tbaldridge23:03:58

This idea of making your UI functionally pure is what React is all about. So help me understand what about SSR is functional? How do you get a server generated response to a client in a functional way?

mobileink23:03:17

i guess that's kinda my q. a little background: i'm getting close (please, lord!) to releasing a webcomponents lib that generates static everything. the obvious next step is to integrate this with reacty stuff like om. so i do some googling, and see tons of stuff about SSR, "universal js", "isomorphic js", etc. most of which seems to boil down to old-fashioned "generate some html/css/js on the server and send it to the client. ok. but my take, which could be wrong, is that SSR effectively means serializing on the server. sending the serialization strike me as an orthogonal isse. in any case "render" obviously cannot have the same meaning on both server and client. no?

tbaldridge23:03:59

sure it can, it all depends on the implementation

tbaldridge23:03:35

render on the client could involve writing to a string (done that a few times) and then making the browser parse the string

mobileink23:03:45

ok, but it must involve dom ops, right? merely writing to a string does not render.

tbaldridge23:03:23

it doesn't on the server either

mobileink23:03:42

that's my point!

mobileink23:03:11

"render" has special meaning.

mobileink23:03:01

sending a string to a browser does not a render make.

mobileink23:03:36

i see your point, i think.

tbaldridge23:03:48

I have no clue what you're trying to say

fellshard23:03:49

Render - to translate a description of graphical interface display into a concrete representation.

fellshard23:03:21

That description generally begins as text, but may be intermediately stored in, say, the DOM or virtual DOM.

fellshard23:03:59

Does that differ from your understanding, mobileink?

mobileink23:03:19

there's a difference between calling "render" on a server and on a browser. on the server, it's a function, and you must do sth with the result, namely send it to the client. that is not the case on the client, where it is a co-function: you need not invoke another op to "send" the result to the dom, since there is no result, there is only the effect of whacking the dom.

misha23:03:13

PSA: just lost an hour on this opieop

(->> :foo @(atom {:foo :bar}))
=> {:foo :bar}
(->> :foo (@(atom {:foo :bar})))
=> :bar
(macroexpand '(->> :foo @(atom {:foo :bar})))
=> (clojure.core/deref (atom {:foo :bar}) :foo)

misha23:03:09

in clj i'd get

clojure.lang.ArityException: Wrong number of args (2) passed to: core/deref

jr23:03:13

javascript 😕

mobileink23:03:22

@fellshard: close, but what does "translate" mean? return a result (functional) or trigger a side-effect (co-functional)?

fellshard23:03:07

Good question. I'd argue that it returns, though oftentimes JS by default conflates that with side-effects.

fellshard23:03:52

Hence why you have libraries - such as the CLJS React family - that aim for functional purity.

mobileink23:03:07

maybe that is my point: there is an inherent ambiguity in the way "render" is commonly used.

tbaldridge23:03:49

but does it really matter? Render is really just another word for "transform" commonly used when there cannot be a reverse transform

tbaldridge23:03:09

really has nothing to do with side-effects

tbaldridge23:03:18

I can make a 3d renderer, that goes from models to a bitmap

fellshard23:03:25

It's less the meaning as it is the target

fellshard23:03:43

You can render to a DOM, but that's usually conflated with rendering to the DOM

mobileink23:03:01

matter to the world? danged if i know. matters to me, and as i pointed out to @fellshard, it's not as simple as that. when a browser transforms some html into a graphic display, that's one thing (non- or co-functional); it's a very different thing to translate one string into another (functional).

fellshard23:03:33

It may not even be into a string; it could be into an object model, much the same way as the text of an application can be 'rendered' into a syntax tree.

fellshard23:03:55

Or into a fully executable binary.

tbaldridge23:03:13

I guess, I don't see a point in trying to prove a point about the naming of things. It does matter to me what code does but I care less about what people call it. Some may call it side-effecting, some may call it "co-functional", either way, I'd rather have functions that take and return data.

mobileink23:03:16

ok, obviously i need to put in a little more work clarifying what i'm after.

mobileink23:03:43

fwiw, this is not just spouting. actually connected to foundational models of computation.

fellshard23:03:27

Naming things is hard and important, but taking time to whittle down whether the name is the problem in this case might be helpful 🙂 A little hammock time rarely hurts.