clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
2020-09-07T12:03:46.289800Z

Hi, I'm having some problems with encoding over a websocket. A small amount of users get encoding errors. What I get

Received unreadable data ' #object[G [:client/pong #object[h {:time 1599227731033}]]] ', for client: nil #error { :cause No reader function for tag object
Do any of you know what type of object '#object[G' can be? Is it on the browser side or on the server side it somehow get wrapped?

Timofey Sitnikov 2020-09-07T12:17:09.293700Z

Hello Clojurians, I am a noob and trying to figure out how to develop a full stack app using shadows-cljs. The default index.html seems to kick off the JS code, but how do you run the back-end server? Should the backend run through shadow-cljs or should it run through a completely independent instance of REPL?

grounded_sage 2020-09-07T12:30:54.295100Z

Is it possible to alias to a macro. (def my-var ns.macro-file/my-macro)

thheller 2020-09-07T13:04:08.296200Z

@timofey.sitnikov I recommend keeping your backend entirely separately and just have it serve the HTML and the static files shadow-cljs produced. shadow-cljs does not provide anything to do backend development.

thheller 2020-09-07T13:04:53.296600Z

@grounded_sage not in CLJS, you can with some trickery via CLJ

Timofey Sitnikov 2020-09-07T13:12:04.305300Z

@thheller, OK, so, I need two instances of terminal, one for CLJS and the other for for backend. What I am having a hard time with is shadow-cljs relies on index.html file in the public directory, but it seems like the backend should serve the index.html as well as provide the backend api.

grounded_sage 2020-09-07T13:12:08.305400Z

@thheller okay. Cljs is the particular one I was getting at. Was trying to see if it possible to avoid file duplication just to get at one or two macros. It is definitely possible doing :#?(:cljs (:require-macros [self-required.ns :refer [my-cljs-macro] :rename {my-cljs-macro normal-macro-name}]) for the current ns and also doing :require .. :refer .. :rename .. in outside files. Though my preference is to avoid the rename leaking into the public API from that ns. So I currently have the duplicated files with their minor variations of macros and am considering the auto-namespace aliasing if it makes sense to do so.

thheller 2020-09-07T13:14:14.305500Z

shadow-cljs does not rely on the index.html, you just need some HTML to instruct the browser to load the JS and so on. just have your backend server either generate the HTML or serve the file.

thheller 2020-09-07T13:21:27.306600Z

whenever I want macros from other namespaces to become part of an API I just create another macro either just directly calls that macro or emits code with the renamed symbol, eg. https://github.com/thheller/shadow-experiments/blob/master/src/main/shadow/experiments/grove.clj

Timofey Sitnikov 2020-09-07T13:22:37.307200Z

I may be missing how to tell shadow-cljs not to spin up its own http server. I already started the backend server, but when I start shadow-cljs, I get the TCP port in use warning, and it still spins up another http server.

[I] /home/sporty/clojure/bubbleuptop~> shadow-cljs watch app
shadow-cljs - config: /home/sporty/clojure/bubbleuptop/shadow-cljs.edn
[2020-09-07 09:17:33.474 - WARNING] TCP Port 8080 in use.
shadow-cljs - HTTP server available at <http://localhost:8081>
shadow-cljs - server version: 2.10.15 running at <http://localhost:9630>
shadow-cljs - nREPL server started on port 40611
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
Warning: Nashorn engine is planned to be removed from a future JDK release
[:app] Build completed. (6197 files, 0 compiled, 0 warnings, 22.65s)

thheller 2020-09-07T13:24:03.308300Z

quite often do this for plain functions too. just one function calling another, no need to make it more complicated than that IMHO

thheller 2020-09-07T13:24:25.308400Z

you configured that server in shadow-cljs.edn

thheller 2020-09-07T13:24:34.308600Z

either :dev-http or :devtools {:http-port ...}. just remove them if you don't intend to use them.

thheller 2020-09-07T13:29:20.309300Z

also yikes 6197 files πŸ˜›

Timofey Sitnikov 2020-09-07T13:29:44.309500Z

This makes me want to cry 😞, this is so simple, but coming into this so not obvious from system point of view. Thank you for helping, I would have banged my head agains the wall.

Timofey Sitnikov 2020-09-07T13:30:01.309700Z

Huh? what do you mean, what does it tell you?

thheller 2020-09-07T13:30:13.309900Z

that is a lot of files πŸ˜› likely including a lot of npm files which you may want to look into at some point. your output is likely gigantic.

grounded_sage 2020-09-07T14:01:41.314400Z

The problem I have there is that the macro I have is from a .cljc namespace. So the preferred name is already declared in that ns when it is ran through the clj compilation step to generate the macro. That is why I was thinking I could possibly have two variations of the macro with -cljs appended to the name for the cljs version and then rename it to remove the -cljs or redeclare the name after the clj macro to the same name but inside #?(:cljs …)

thheller 2020-09-07T14:04:12.315500Z

I don't quite understand what you are trying to do here? just have the macro detect whether its supposed to generate CLJ or CLJS code?

grounded_sage 2020-09-07T14:05:18.316300Z

There is multiple macros being layered on. The (:ns &amp;env) doesn’t appear to work with this happening.

grounded_sage 2020-09-07T14:06:51.317300Z

This is where the macro layers start. https://github.com/replikativ/hitchhiker-tree/blob/master/src/hitchhiker/tree/utils/async.cljc#L10 I resolved this issue by duplicating the files and just having the if-async? set to true for the cljs version.

thheller 2020-09-07T14:08:05.318300Z

(def ^:dynamic *async?*
  #?(:clj false :cljs true))
this is always :clj and thus true as far as the macro is concerned

grounded_sage 2020-09-07T14:08:45.318900Z

So I just duplicated those files and had them false and true in their respective clojure cljs namespaces

thheller 2020-09-07T14:10:11.319200Z

what you are saying does not make sense to me

thheller 2020-09-07T14:11:31.320600Z

(defmacro if-async?
  ""
  {:style/indent 2}
  [then else]
  (if (is-cljs? &amp;env)
    then
    else))

grounded_sage 2020-09-07T14:11:44.320900Z

Well the *async?* is always in clj when being evaluated in the macros.

thheller 2020-09-07T14:12:09.321500Z

just have the macro figure out what its supposed to do when it is called

thheller 2020-09-07T14:12:17.321800Z

you cannot determine this anywhere else

thheller 2020-09-07T14:15:25.323200Z

looks fine

thheller 2020-09-07T14:16:09.323500Z

the version below however does not

thheller 2020-09-07T14:16:26.323700Z

(defmacro go-try
  "Asynchronously executes the body in a go block. Returns a channel
  which will receive the result of the body when completed or the
  exception if an exception is thrown. You are responsible to take
  this exception and deal with it! This means you need to take the
  result from the channel at some point."
  {:style/indent 1}
  [&amp; body]
  (if-async?
    (let [e (if (:ns &amp;env) 'js/Error Throwable)]
      `(async/go
         (try
           (do ~@body)
           (catch ~e e# e#))))
    `(do ~@body)))

thheller 2020-09-07T14:16:44.324200Z

the if-async? is expanded when the macro is loaded in CLJ, thus it takes the CLJ branch and is not async

thheller 2020-09-07T14:17:46.325200Z

macros can be confusing like that πŸ˜‰

πŸ˜‚ 1
grounded_sage 2020-09-07T14:17:49.325300Z

Yea that’s what was happening. The macroexpansion happening in CLJ basically cascades through when it is used in other macros

thheller 2020-09-07T14:18:53.325700Z

(defmacro go-try
  "Asynchronously executes the body in a go block. Returns a channel
  which will receive the result of the body when completed or the
  exception if an exception is thrown. You are responsible to take
  this exception and deal with it! This means you need to take the
  result from the channel at some point."
  {:style/indent 1}
  [&amp; body]
  (if (async? &amp;env)
    (let [e (if (:ns &amp;env) 'js/Error Throwable)]
      `(async/go
         (try
           (do ~@body)
           (catch ~e e# e#))))
    `(do ~@body)))

thheller 2020-09-07T14:19:15.326200Z

always check against the env when doing this kind of stuff

thheller 2020-09-07T14:20:30.327700Z

honestly I think what you are trying to do there is doomed to fail. you cannot just "add async" as if it didn't change the entire semantics of the entire code infecting everything

thheller 2020-09-07T14:20:39.328Z

might as well start from scratch with a better setup πŸ˜›

grounded_sage 2020-09-07T14:30:57.331100Z

Well it now works just not as elegant as I thought I could make it. There is code that makes the necessary parts sync when needed. I’m still relatively new to the project so I am yet to have a comprehensive overview of how all the pieces fit together.

kiranshila 2020-09-07T17:57:53.335800Z

What's the current best way to interopt with AsyncIterators ? I have bytes coming in via a callback but the msgpack library I am using wants to consume bytes asynchronously via stream: AsyncIterator&lt;Uint8Array&gt; . Right now I have my callback just putting the incoming bytes onto a channel, but I'm not sure the best way to pipe that channel into an async iterator.

2020-09-07T23:04:13.337900Z

Hi everybody!, Does anybody knows why this macro

(defmacro tester [form]
  (println (macroexpand form))
  nil)
When used from clojure :
(tester (let [a 5] a))
;; prints
(let* [a 5] a)
But when used from clojurescript :
(tester (let [a 5] a))
;; prints
(let [a 5] a)
So the same macro doesn't do the same, macroexpand doesn't work at macro level when the cljs compiler calls it