Fork me on GitHub
#clojurescript
<
2020-09-07
>
Erik Thorselius12:09:46

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 Sitnikov12:09:09

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_sage12:09:54

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

thheller13:09:08

@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.

thheller13:09:53

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

Timofey Sitnikov13:09:04

@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.

thheller13:09:14

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.

Timofey Sitnikov13:09:37

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 
shadow-cljs - server version: 2.10.15 running at 
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)

thheller13:09:25

you configured that server in shadow-cljs.edn

thheller13:09:34

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

thheller13:09:20

also yikes 6197 files 😛

Timofey Sitnikov13:09:44

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 Sitnikov13:09:01

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

thheller13:09:13

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_sage13:09:08

@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.

thheller13:09:27

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

thheller13:09:03

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

grounded_sage14:09:41

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 …)

thheller14:09:12

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_sage14:09:18

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

grounded_sage14:09:51

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.

thheller14:09:05

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

grounded_sage14:09:45

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

thheller14:09:11

what you are saying does not make sense to me

thheller14:09:31

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

grounded_sage14:09:44

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

thheller14:09:09

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

thheller14:09:17

you cannot determine this anywhere else

thheller14:09:09

the version below however does not

thheller14:09:26

(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}
  [& body]
  (if-async?
    (let [e (if (:ns &env) 'js/Error Throwable)]
      `(async/go
         (try
           (do ~@body)
           (catch ~e e# e#))))
    `(do ~@body)))

thheller14:09:44

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

thheller14:09:46

macros can be confusing like that 😉

😂 3
grounded_sage14:09:49

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

thheller14:09:53

(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}
  [& body]
  (if (async? &env)
    (let [e (if (:ns &env) 'js/Error Throwable)]
      `(async/go
         (try
           (do ~@body)
           (catch ~e e# e#))))
    `(do ~@body)))

thheller14:09:15

always check against the env when doing this kind of stuff

thheller14:09:30

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

thheller14:09:39

might as well start from scratch with a better setup 😛

grounded_sage14:09:57

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.

kiranshila17:09:53

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<Uint8Array> . 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.

jpmonettas23:09:13

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