Fork me on GitHub
#clojurescript
<
2019-12-02
>
cch100:12:01

I’m stumped trying to get data_readers.cljc working with a Clojure + Clojurescript.

{
 rk/url x.literals.url/read
}
The implementation:
(ns x.literals.url
  (:refer-clojure :exclude [read])
  (:import #?@(:clj (.URL)
               :cljs (goog.Uri))))

(defn read
  "Construct a URL from its usual string representation"
  [s]
  (#?(:cljs goog.Uri. :clj .URL.) s))
The error I see in the (figwheel-main) REPL is Compile Exception: failed compiling constant: ; .URL is not a valid ClojureScript constant. It sounds similar to https://clojure.atlassian.net/browse/CLJS-1955, but I’m using ClojureScript 1.10.597 so that should be ruled out. AFAICT, the only meaningful difference between my example and the test case in the ticket above is that I have differing implementations in CLJ and CLJS described using reader conditionals. Without either reader conditionals or different source code files using .clj and .cljs, I don’t even see how to achieve anything but trivial tag readers.

lilactown00:12:36

Reader tags always run in clj when parsing CLJS

lilactown00:12:58

What your read function should do is output a s-expr that calls the correct constructor

cch103:12:40

Thanks, @lilactown. I’m going to try that now.

cch103:12:59

This indeed works. It has the unfortunate side effect of being more difficult to test as the read function now returns an s-expression instead of a url value -both in Clojure and ClojureScript. I suppose that is a challenge when testing code supporting data readers.

lilactown00:12:30

(defn url [s]
  #?(:cljs (goog.Uri. s) :clj (.URL. s)))

(defn read [s]
  `(url ~s))

lilactown00:12:11

this way the reader tag #rk/url "" will output (x.literals.url/url "") at read time, and then at runtime it will execute that function and construct the URL

cch103:12:44

Can anybody confirm if @lilactown’s solution ^ is a best practice? Are there alternatives that don’t carry the performance and complexity penalties of returning an s-expression from a data reader function?

lilactown03:12:17

that’s how reader literals and macros work

lilactown03:12:16

reader literals and macros are ways to introduce new syntax that get expanded into regular function calls / calls to other macros

lilactown03:12:51

especially in ClojureScript, your reader literal code and macro code is running in the compiler which is run in a Clojure JVM process at compile-time

lilactown03:12:01

your ClojureScript code needs to work at runtime in a browser

lilactown03:12:18

so you need to emmit code that will be valid ClojureScript that can be compiled to javascript

cch103:12:39

Got it. It is nevertheless annoyingly inconsistent that data readers must return code if the code needs to be evaluated in ClojureScript and can return code in Clojure even if read-time evaluation would be more performant. Doubly frustrating is that the documentation and test cases for ClojureScript’s support of data_readers.cljc use degenerate examples that leverage pure Clojure code that works identically on both platforms (`identity` seems to be really popular). Yet most real-world use cases for data readers leverage native platform interop.

didibus03:12:40

In Clojure they don't have to return code. They can return the constructed object. But ClojureScript doesn't truly support runtime compilation unless your in self-hosted land.

didibus03:12:24

Are you sure you can't have the clj part do that and only not do that for the cljs part?

cch104:12:03

@didibus That is exactly what I am trying to determine right now -it seems like a reasonable compromise.

cch104:12:34

Perhaps a conditional macro in data_readers.cljc to call two different fns.

lilactown04:12:48

you can’t use reader conditionals in the reader literal function though

lilactown04:12:16

because when your reader function is run by the ClojureScript compiler, it will run the :clj branch

cch104:12:04

Yep… just found that out the hard way.

lilactown04:12:23

so you have to defer the reader conditional to the point where the code is actually ran, not compiled

lilactown04:12:56

in most cases, reading happens in Clojure

lilactown04:12:18

there are two cases where reading happens in the ClojureScript runtime: 1. self-hosted ClojureScript. for instance lumo or planck which are stand-alone self hosted environments 2. using the built-in EDN reader, in which case you can pass it reader functions

lilactown04:12:14

if you are targeting either of those two cases, then you might also want to write a :cljs reader conditional in the read function itself

cch104:12:51

Yes, and I read in the planck docs where data_readers are read and run in a way that is more “natural” => in ClojureScript.

cch104:12:46

I am targeting both cases and I tried a reader conditional in read function itself . It did not work IIRC. Let me try again…

lilactown04:12:47

but the majority case where you are compiling ClojureScript to JavaScript, the CLJS compiler will run the :clj branch and so you have to defer to some other code to do the reader conditional

👍 4
talktoj04:12:12

Hi, We are using clojurescript with react native. Currently we are spending lot of time in debugging an application. Can anyone help us out with how we can debug an app in runtime ? We are using visual studio for devlopment. Please share plugin we can use in visual studio (with steps if possible). Thanks

cjohansen06:12:54

my team is presenting our Clojure work process to a different in-house team that's not using Clojure. what is your favorite ClojureScript presentation? Looking for good examples to steal from 🙂

Maikel13:12:41

Hi, we are creating a new clojurescript project with shadow-cljs. We want to integrate Sentry for error logging. Is there anyone who already has done this? We are stuck and have no idea how it should bbe integrated.

thheller13:12:43

what do the sentry docs tell you about integrating it? you basically follow that.

Maikel13:12:11

well, i was trying to follow the docs. Looks i just was able to capture a message

Maikel13:12:23

so hopefully it starts working now

ivana13:12:45

Hello! How can I get HTML string from hiccup syntax on frontend without rendering it as a component?

ivana14:12:03

Thanks!

👍 4
Pavel Klavík14:12:23

Hi, I have a webserver in ring. What is the common approach to deal with session timeouts? For instance when a user wake up laptop after a while. How should I detect on the client that session timeouted?

Emmanuel19:12:25

what is a cljs alternative for slurp in clojure? need to get text from a textfile hosted online.

Lu20:12:14

I assume you need to make an http request to achieve that. You can use ajax.

Emmanuel20:12:48

i'll look into that

pesterhazy20:12:05

@mail719 if you mean in the browser, just use js/fetch , like you would in JS. In Node, node-fetch works the same

Emmanuel23:12:05

yea but that returns a promise, and i'm not sure how to deal with promises in cljs..

Michaël Salihi10:12:40

You can use interop to consume promises with Fetch API like this :

(->
  (js/fetch "")
  (.then (fn [response] (.json response)))
  (.then (fn [data] (.log js/console data))))

👍 8
fossifoo20:12:03

hi. i'm trying to pr-str a (cljs-time/now) value and i get #object[Object 20191202T205302] which the edn reader barfs on. any clues what might be wrong?

fossifoo21:12:45

guess i have to configure to (de-)serialize that Date by hand?

fossifoo21:12:03

okay, found a thread from 2016 and the state doesn't seem to be much different. guess i'll just use nippy then

fossifoo21:12:55

ah, damn, that's not cljc ;_;

thheller21:12:03

I'd recommend using transit with custom handlers

thheller21:12:14

or you can extend IPrintWithWriter for the date type

fossifoo21:12:18

yeah, i guess transit it is...

shaun-mahood21:12:19

@fossifoo If you need to do anything extra with dates you could also look at https://github.com/juxt/tick - it does a lot more, but along with transit custom date handlers it's pretty nice to work with. https://gist.github.com/Deraen/eb3f650c472fb1abe970 is a good reference for how to deal with dates in transit.

fossifoo21:12:25

yeah, i was using cljs-time in one place and then tick in some others because i needed more functionality

fossifoo21:12:37

it's still a pita

shaun-mahood21:12:32

If you ever find a way to deal with dates that isn't painful you will be very popular 🙂

fossifoo21:12:29

just scrap them. i mean, who in the world cares about whether something happens now or a little later, right?

⏱️ 8
fossifoo21:12:14

i guess i'll just buy into the yak and port everything over to tick and transit

ivana21:12:58

Can anyone suggest, which lib/template for webworkers is more usable?

Pavel Klavík02:12:10

I would just use Shadow-cljs, it is quite easy to do the setup there.

✔️ 4
ivana12:12:15

Thanks, I'l try it

fossifoo21:12:02

as it happens, that's what i'm currently working on and i found all of them to be very thin, so i'm "just" using plain ones

fossifoo21:12:17

but as you can see above, you might run into details ;D

fossifoo21:12:16

works, thanks

fossifoo21:12:51

just another half hour well spent in the fragile corners of happy clojure(script)land :)