Fork me on GitHub
#clojurescript
<
2021-07-29
>
Chris McCormick01:07:55

Hello all! Is there any good resource on publishing a clojurescript library as both a jar & on also on npm (with exports for JS consumption)? When published on clojars is there a way to have the package.json inherited by the project that is using the library?

emccue03:07:01

Generally clojurescript libraries don't exist on npm

đź‘Ť 2
emccue03:07:49

the only example i am aware of is mori

emccue03:07:54

and that is abandoned

Mathias Kjeldsberg Andersen13:07:08

Hi all. I have been trying to implement the https://www.npmjs.com/package/paho-mqtt in an ClojureScript app running as a React Native app using https://github.com/PEZ/rn-rf-shadow. I have gotten it to connect to the MQTT server and I am able to send a message from the client, but when I publish a message on a topic the client is subscribed to it closes the connection and gives me a cryptic error message. The javascript example for the client describes the onConnectionLost and onMessageArrived functions like this:

// called when the client loses its connection
function onConnectionLost(responseObject) {
  if (responseObject.errorCode !== 0) {
    console.log("onConnectionLost:"+responseObject.errorMessage);
  }
}

// called when a message arrives
function onMessageArrived(message) {
  console.log("onMessageArrived:"+message.payloadString);
}
and that you set the callback handlers on the client object like this:
// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;
I setup the connection like this in src/main/example/app.cljs:
(:require
   ["react-native" :as rn]
   [reagent.core :as r]
   [re-frame.core :as rf]
   [shadow.expo :as expo]
   ["paho-mqtt" :as paho]
   [example.events]
   [example.subs]))

...

(defonce mqtt-client (paho/Client. "127.0.0.1" 8000 "myClientId"))

(defn mqtt-connected [] (.subscribe mqtt-client "World"))
(defn mqtt-on-message [message] (prn str("I have a message for you! " message)))
(defn mqtt-connection-lost [response-object] (prn "mqtt connection lost! " response-object))

(set! (.-onMessageArrived mqtt-client) mqtt-on-message)
(set! (.-onConnectionLost mqtt-client) mqtt-connection-lost)
(.connect mqtt-client #js {:onSuccess mqtt-connected})
When I publish a message to the "World" topic it gives me this from the onConnectionLost function:
"mqtt connection lost! " #js {:errorCode 5, :errorMessage "AMQJS0005E Internal error. Error Message: fexpr__29213.call is not a function. (In 'fexpr__29213.call(null,message)', 'fexpr__29213.call' is undefined), Stack trace: No Error Stack Available", :reconnect nil, :uri ""}
It seems like the onMessageArrived function is never called and I don't know why. The onConnectionLost function works fine but the onMessageArrived function does not even though it is registered in the exact same way as the onConnectionLost function. Any suggestions? @hiskennyness

p-himik13:07:10

A very suspicious line in your code:

(defn mqtt-on-message [message] (prn str("I have a message for you! " message)))
Do you see an issue there?

p-himik13:07:01

Also, I'm not sure about React Native, but in regular browsers where you have DevTools, you can set a breakpoint on any exception. Quite helpful in such circumstances.

Mathias Kjeldsberg Andersen13:07:04

I have tried it by just having it be (prn "fooo") and nothing changed

kennytilton13:07:06

But you have (prn str(... where I think you want (prn (str ...)) @U029L20KBQB

kennytilton13:07:31

Now that you have switched to (print "foo"), just make sure that new code is running. 🙂

kennytilton14:07:00

I checked the Machine_Head client code https://github.com/clojurewerkz/machine_head/blob/master/src/clojure/clojurewerkz/machine_head/client.clj and was struck by the different handling given to message receipt:

(defn ^:private ^IMqttMessageListener reify-message-listener
  [delivery-fn]
  (reify IMqttMessageListener
    (^void messageArrived [this ^String topic ^MqttMessage msg]
      (delivery-fn topic (cnv/message->metadata msg) (.getPayload msg)))))
But I know nothing about interop. 🤷

Mathias Kjeldsberg Andersen14:07:54

You're right about the (prn (str ...)) my mistake. I relaunch the app from the metro bundler every time I test a new thing (mostly because of the (defonce ...) and I want to be sure that the client connects again. (I could probably reconnect it using the repl))

đź‘Ť 3
kennytilton21:07:59

So in the end we shifted to https://www.npmjs.com/package/react-native-native-mqtt since that is where we were running and after some more interop learning curve we are up and pub/subbing. @U029L20KBQB can explain better if anyone is curious.

tessocog14:07:37

is there a lib for converting edn to reasonably pretty hiccup?

tessocog15:07:00

also, what is the representation of string type in clojurescript? can't find it in cljs.core/...

Richard Bowen15:07:21

clojure.string assuming you want access to the many string functions.

tessocog15:07:30

doesn't work though, there is no clojure.string/String in that ns

tessocog15:07:33

i need to write something like the following: (instance? ???? "fooobar")

dpsutton15:07:56

(defn ^boolean string?
  "Returns true if x is a JavaScript string."
  [x]
  (goog/isString x))

tessocog15:07:31

eh, no, i want the direct representation of String type as a value

tessocog15:07:02

like so: cljs.core/PersistentArrayMap

dpsutton15:07:43

js/String then i think

tessocog15:07:23

(instance? js/String "foo") => false

javi15:07:48

(instance? js/String (js/String. "")) ; => true (instance? js/String "") ; => false string primitive vs string object

tessocog15:07:18

so what is the type of "" ?

Richard Bowen15:07:44

java.lang.String

tessocog15:07:00

thanks

đź‘Ť 3
mikerod17:07:58

When upgrading from clojurescript v 1.10.764 to 1.10.866 , which notably had 2 goog closure lib upgrades I note with a dev figwheel style build (latest lein-figwheel + cljsbuild) that I suddenly get

Uncaught SyntaxError: Unexpected token '!'
Digging deeper the devtools difference I see in the browser is in the file: <js-compilation-location>/dev/goog/log/log.js

mikerod17:07:15

The odd part is in the old cljs version, this file looked like the direct source JS file from google closure lib. In the new cljs version, it instead showing me some transpiled variant, with a header like this:

/*TRANSPILED*//*

 Copyright The Closure Library Authors.
 SPDX-License-Identifier: Apache-2.0
*/
Then the actual offending line is here (with the name truncated a bit):
/*TRANSPILED*//*

 Copyright The Closure Library Authors.
 SPDX-License-Identifier: Apache-2.0
*/
goog.provide("goog.log");
goog.provide("goog.log.Level");
goog.provide("goog.log.LogBuffer");
goog.provide("goog.log.LogRecord");
goog.provide("goog.log.Logger");
goog.require("goog.asserts");
goog.require("goog.debug");
goog.log.Loggable;
goog.log.ENABLED = goog.define("goog.log.ENABLED", goog.debug.LOGGING_ENABLED);
goog.log.ROOT_LOGGER_NAME = "";
var file_$Users$myuser$_m2$repository$org$clojure$google_closure_library$0_0_20201211_3e6c510d$google_closure_library_0_0_20201211_3e6c510d_jar!$goog$log$log$classdecl$var0 = function(name, value) {
  this.name = name;
  this.value = value;
};
You can see in the long var name in the transpiled one there is an “!” used in the name. I don’t know that that’s even a legal JS identifier. This looks to be what is reported. I don’t understand why previously I don’t see this “transpiled” file at all, but with the cljs upgrade now I do. So why it exist now is the first real mystery to me. The second is why it’s producing this invalid name.

Alex Miller (Clojure team)17:07:01

that looks like an encoded jvm resource url

mikerod19:07:50

I actually didn’t think of that. That’s at least something for me to go from. Thanks!

Richard Bowen18:07:40

Hey, what would be a good way to create a custom material-ui SvgIcon component based on an svg files (since shadow-cljs doesn't support importing assets.)? Would the svg path attribute behave like the src attribute and load the contents of a svg file, i.e. <svg path="/path/to/file.svg">?

javi18:07:41

[:img {:src "path/to/file.svg" :width 48 :height 48}]
You can use svg in image tags. The svg "<path ... > " is a different thing. It is used to define the shape of a path.

Richard Bowen18:07:36

Yea. So an image tag can be used inside a material-ui SvgIcon component?

javi18:07:04

ahh, that makes more sense.. material-ui SvgIcon... I am not familiar with material ui... Are you using reagent/hiccup?

javi18:07:12

and you have access to the path of your svg?

javi19:07:37

Just an idea... it says in https://stackoverflow.com/questions/38510443/how-to-use-an-svg-file-in-a-svgicon-in-material-ui (scroll down) that you can use react components in svgIcon . You could try turning your svg into hiccup https://htmltohiccup.herokuapp.com/, then make a reagent component out of it and pass it to SvigIcon.

(defn my-icon-comp
  [props]
 .....)

[:> SvgIcon  
 (r/as-element [my-icon-comp {}])
]   

javi19:07:25

also... as you can use react components in svgIcon i guess you can use [:img {:src "path/to.svg"}] too and load it dynamically. But you loose control over styling the svg... as far as i know.

Richard Bowen19:07:16

No need to style it, other than maybe sizing.

Richard Bowen19:07:56

Alright, thanks for the suggestions, I'll try them out.

javi19:07:00

remove width and height from the svg and leave viewBox. that will make it expand to the container. should work.

Richard Bowen19:07:32

I think SvgIcon comes with it's own dimentions.

Richard Bowen19:07:43

24x24 I think.

Asko NĹŤmm19:07:35

(if that helps at all)

javi20:07:15

yeah, as @U026NQLSBLH points out, maybe just use reagent components and do not use Material's svgIcon..