This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-07
Channels
- # beginners (49)
- # boot (48)
- # cider (5)
- # cljs-dev (6)
- # clojure (165)
- # clojure-android (1)
- # clojure-austin (1)
- # clojure-india (2)
- # clojure-italy (23)
- # clojure-nl (2)
- # clojure-poland (4)
- # clojure-russia (63)
- # clojure-spec (5)
- # clojure-uk (121)
- # clojurescript (187)
- # core-async (1)
- # core-logic (4)
- # cursive (17)
- # datascript (1)
- # datomic (12)
- # emacs (2)
- # funcool (3)
- # hoplon (2)
- # jobs (7)
- # juxt (6)
- # lambdaisland (1)
- # luminus (2)
- # lumo (20)
- # midje (8)
- # off-topic (11)
- # om (38)
- # onyx (42)
- # pedestal (6)
- # planck (23)
- # protorepl (29)
- # ring (3)
- # rum (23)
- # spacemacs (6)
- # untangled (70)
- # vim (1)
@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/bideBide 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.
there's some sample code that I need to rewrite in cljs; and I'd prefer to do js -> badly written cljs -> clean cljs
JS isn't badly written cljs....it's like saying a paper airplane is just a badly designed 747 😛
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.
and the first step is just tedioius conversion of = into set! and other pure mechanical things
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 🙂
Actually, I wouldn't mind being pinged if you find such a tool 🙂
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.
@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
I found that through searching, @qqq. It's a start.
@isak thanks for your detailed answers! @qqq thanks for your feedback 🙂
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
What do I need additional?
Hm. Maybe a typo. After copy and pasting the project.clj again it works.
Next one in the tutorial. While running the repl I changed the hello.js and reloaded it, but got this error thrown:
(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)
`Adding "use strict"; doesn't resolve the error, neither adding :language-out :ecmascript6-strict to the repl options
does org.clojure/core.async "0.3.441" also provide core.async for cljs ? if not, what package do I need ?
That's the one
@qqq You need something else for self hosted cljs though: https://github.com/mfikes/andare
You can try lein ancient
(https://github.com/xsc/lein-ancient)
it should work. why wouldn't it?
I was just curious. I wanted to make sure I wasn't pre-shooting myself in the foot.
@fearphage not aware of anything, but the issue probably would not be with ClojureScript anyway - Clojure or the ClojureScript compiler deps
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.
@tech_hutch what do you mean by "CLJS promises"?
Clojure has promises. I thought ClojureScript did, but maybe not.
no it doesn't have promises as a language feature
Clojure or ClojureScript?
clojurescript 🙂
Oh okay.
@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
core.async is one, but frameworks like Om.next and Reframe have other methods
I'm curious, can async/await be transpiled to ES5?
I believe so
in which case it's basically the same thing as core.async's go
If I have to work with a JS promise-based library, can they be awaited in CLJS?
you'd need to write a macro that does a similar transformation to await I imagine
can't you just do (.then p (fn [] ...))
@tbaldridge maybe I'm hazy about the details
I could use then
, but I would prefer not to have the nesting.
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
@tech_hutch so one thing you can do is use promises + core.async to avoid nesting
which I wouldn’t recommend if you’re just starting out
but nevertheless
react-native already uses promises heavily in its public api
(.then some-promise #(async/put! chan %))
^ something like that, and take the value out of the channel in a go
block
Okay. I'm new to using channels, but I'll look into it.
there's a blog post waiting to be written: "Help! I need to use ES6 promises from clojurscript. what are my options?"
maybe 🙂
Oh, is that your blog? lol
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
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?
more fancy way is to use :external-config
in cljs compiler options and again read them using a macro and emit into cljs
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
@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 await
ing in another function.
@tech_hutch the ClojureScript compiler outputs ES3, so no async
or await
but an async
function just returns a promise AFAIK, so you can use then
, which CLJS supports
and any promise which is created by cljs code, can by used with await
in js code, I would assume
and by promise I mean js/Promise
:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
That's the thing. I'd rather not have to chain .then
s. I suppose I'd have to convert to channels to get similar behavior.
darwin, to use await
I'd have to write any code that uses it in JavaScript, then.
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
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).
I wonder if there is a nice library for converting various async primitives between each other in cljs
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
@darwin what is the problem you're seeing with turn-callback-into-channel
?
or I guess, what's the idea behind that function?
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
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
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?
I would need to install some kind of "observer” on existing js function calls, which is not possible I think
Maybe you could have the user wrap their callback in a function, or something.
Also, thanks for the help. I'm going to try channels.
the problem is that the user is not me, they live in javascript land and they wrote the code before me
Oh okay.
You could still give them a function to wrap theirs in, couldn't you?
Oh, never mind.
Er wait.
Is this for CLJS users, JS users, or both?
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
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
I would need a mechanism where given an existing function, I install some kind of observer for invoked calls on it
Okay, I understand.
You could require a wrapper, but it wouldn't work in all circumstances.
Yeah, I don't think any functionality like that exists in JS right now.
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.
@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
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.
@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
@mobileink there's quite a few functional ways to do client side stuff
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.
@tbaldridge yes and no. anything that updates the dom is not funtional, by definition.
Right, the DOM is purely a IO device at that point, a write-only IO device
imho this is an important conceptual distinction, even if it can be overlooked without problem.
So you treat it just like the network port on your machine and put it at the edges of your app
I disagree, the the connections are explicit...
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.
In something like Quiescent, you get your root dom element, and then in one location you call (render dom data-that-describes-my-dom)
the dom (in my example) is the connection
"connection"
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
well let's backup, you were saying that server-size rendering is inherently more functional than client-side rendering. Or did I misunderstand
Server side rendering is data->pure function->html->bytestream->tcp stream (aka IO). Client side is data->pure-function->data->dom differ (aka IO)
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.
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).
my complaint is that using the same term ("render") on both sides is deeply misleading
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?
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?
sure it can, it all depends on the implementation
render on the client could involve writing to a string (done that a few times) and then making the browser parse the string
ok, but it must involve dom ops, right? merely writing to a string does not render.
it doesn't on the server either
I have no clue what you're trying to say
Render - to translate a description of graphical interface display into a concrete representation.
That description generally begins as text, but may be intermediately stored in, say, the DOM or virtual DOM.
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.
PSA: just lost an hour on this
(->> :foo @(atom {:foo :bar}))
=> {:foo :bar}
(->> :foo (@(atom {:foo :bar})))
=> :bar
(macroexpand '(->> :foo @(atom {:foo :bar})))
=> (clojure.core/deref (atom {:foo :bar}) :foo)
@fellshard: close, but what does "translate" mean? return a result (functional) or trigger a side-effect (co-functional)?
Good question. I'd argue that it returns, though oftentimes JS by default conflates that with side-effects.
Hence why you have libraries - such as the CLJS React family - that aim for functional purity.
maybe that is my point: there is an inherent ambiguity in the way "render" is commonly used.
but does it really matter? Render is really just another word for "transform" commonly used when there cannot be a reverse transform
really has nothing to do with side-effects
I can make a 3d renderer, that goes from models to a bitmap
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).
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.
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.