Fork me on GitHub
#clojurescript
<
2021-02-05
>
Pete Parker03:02:10

Has anybody encountered issues passing MetaFn to JS functions? MetaFn isn’t a native JS function, so it isn’t executed as expected. For example:

(js/window.setTimeout #(js/console.log "execute native function")) ;; works
(js/window.setTimeout ^:private #(js/console.log "execute function with metadata")) ;; doesn't execute
I would have expected this to be documented somewhere, or be accounted for in JS interop.

p-himik03:02:09

It's the same for any CLJS type that implements IFn. Keywords, sets, maps, vectors, vars, maybe other things. Interop is finicky in some places, this is one of them.

👍 3
Cj Pangilinan03:02:38

Hi, I'm getting this error: Caused by: http://java.io.FileNotFoundException: Could not locate cljs/repl/nashorn__init.class or cljs/repl/nashorn.clj on classpath. I'm doing java -cp cljs.jar;src clojure.main repl.clj. It's from the book ClojureScript unraveled. I assume Nashorn is deprecated, but what is the alternative? Thanks.

p-himik03:02:40

An alternative would be running a NodeJS REPL. I'm using clj and I have this alias in my ~/.clojure/deps.edn:

:cljs-repl {:extra-deps {org.clojure/clojurescript {:mvn/version "RELEASE"}}
                :main-opts ["-m" "cljs.repl.node"]}
which can be used as clj -Mcljs-repl.

Cj Pangilinan03:02:55

Thank you. i'll try the node js repl next. i don't use lein or clj yet. i'm trying to understand how clojurscript works on a low level.

p-himik03:02:11

clj is just a way to create a classpath for a Java command, it has nothing to do with CLJS. I don't know what cljs.jar contains but you can try running java -cp cljs.jar;src clojure.main -m cljs.repl.node.

seancorfield03:02:26

I'm running this command on WSL2 (Ubuntu) on Windows 10 and Google Chrome starts up (on Ubuntu, displayed on Windows 10 via VcXsrv) but I never get the REPL prompt -- suggestions for troubleshooting this?

$ clojure -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "RELEASE"}}}' -M -m cljs.main

seancorfield03:02:34

The browser shows this URL and the expected cljs welcome page, so that part is working...

seancorfield03:02:16

Chrome Version 88.0.4324.96 (Official Build) (64-bit)

p-himik03:02:09

Does the network tab show a pending request to localhost (just in case - you should refresh the page after opening dev tools for that tab to have something)?

seancorfield03:02:30

Will try that... just a sec...

seancorfield03:02:35

Yup, looks like the last request just hangs:

{:repl "Thread-620", :type :result, :content "{:status :success, :value \"\"}", :order 2}: 

p-himik03:02:22

Yeah, it's supposed to be that way - long polling. Hmm, not sure then.

seancorfield03:02:08

Thanks. This all just works on macOS and I think it's the first time I've tried on WSL2/Windows 10.

p-himik03:02:52

Just out of interest - does it work without WSL2?

seancorfield03:02:20

Heh, how am I going to start a REPL without WSL2? I don't have clj installed on Powershell etc.

seancorfield03:02:04

FWIW, hitting the WSL2 process from Windows via 172.17.159.136 doesn't work either in exactly the same way.

p-himik03:02:59

clj just creates a classpath - you have said it yourself. :) You can run the Java command manually.

seancorfield03:02:50

Haha... touche! I don't even have java installed on Powershell.

p-himik04:02:47

You mean, there's no Java installed anywhere in the system but inside WSL2? Because I'm not sure what Powershell has to do with it - Java is just a regular executable that can be run by any means. In any case, I was just curious, nothing more. Unless someone else can chime in with some ideas, I would try to debug cljs.repl/repl*, namely its need-prompt part. (interestingly, for some reason it uses (identity true) instead of just true, huh)

seancorfield04:02:39

Right, I don't do any dev outside of WSL2 so there are no dev tools installed on the Windows side.

seancorfield04:02:06

You asked "does it work without WSL2" and there's no way to run Java or Clojure on my machine outside of WSL2.

p-himik04:02:50

I see. It's just that I used to have Java installed back when I was using Windows not because I did my development there but because something else needed Java. :) "Billions of devices!"

seancorfield04:02:03

So far nothing has needed Java on Windows 🙂

p-himik04:02:27

Oh, does the regular clj REPL prompt appear?

seancorfield04:02:10

Yeah, I do loads of Clojure work on this setup. And I've also had Figwheel Main run fine on this setup.

seancorfield04:02:19

So it's just the plain cljs REPL.

seancorfield04:02:46

Yup, just tested Figwheel...

clj -Sdeps "{:deps {com.bhauman/figwheel-main {:mvn/version \"0.2.12\"}}}"  -m figwheel.main
Starts the browser, produces a REPL, all works.

p-himik06:02:28

Hmm, I'm getting

Failed to launch a browser:
 The BROWSE action is not supported on the current platform!

p-himik06:02:48

Ah, apparently VirtualBox cannot work with WSL2 at all.

suren10:02:13

Why does *ns* in clojurescript return nil?

thheller10:02:21

because it doesn't exist in the REPL technically, should only be used in macros

suren10:02:03

Yup I can confirm it. Thanks

Ivan Fedorov11:02:20

On Web Workers. Anyone managed to pass CLJS maps between different contexts without serialization? I’ve posted this on reddit for indexation purposes. https://www.reddit.com/r/Clojure/comments/ld5f2h/cljs_web_workers_transferable_db/

Fredrik Andersson14:02:04

I'm new to clojure/clojurescript and thinking about the possibility to make a macro somehow that builds defines static variables of paths in a map?

Fredrik Andersson14:02:02

The reason is that i would like to pass paths in state to different functions when rendering my hiccup

Fredrik Andersson14:02:37

that way i could more easily reuse components of my UI in different parts of my state

Fredrik Andersson14:02:19

I would like to have them statically defined so that when something changes i get notified by the compiler

Fredrik Andersson14:02:57

the solution i use now is to

(def state-path-login-username [:login :username])

Fredrik Andersson14:02:02

but if i have to keep these defines in sync with the model

Fredrik Andersson14:02:53

is it even possible to write a macro that does this?

p-himik14:02:42

Do you meant that you want to be able to have something like this in your code

(generate-state-path-defs
  [:login :username]
  [:login :password]
  [:some :other :state])
and end up with
(def state-path-login-username [:login :username])
(def state-path-login-password [:login :password])
(def state-path-some-other-state [:some :other :state])
being actually compiled?

Fredrik Andersson14:02:44

well thats a start

Fredrik Andersson14:02:53

but maybe more like this (defstate {:login {:username "" :password ""} :other-state...})

Fredrik Andersson14:02:26

and end up with something like this

(def state (r/atom {:login {:username "" :password ""} :other-state...}))

(def state-path-login-username [:login :username])

p-himik14:02:24

It is possible. The first step would be to turn the map into a collection of vectors with all possible paths. The second step would be to write macro that generates those def statements and, it seems, a ratom, based on that collection of vectors. The first step is actually a bit harder to implement than the second one and it has nothing to do with macros. If you want to learn more about writing macros to be able to implement the second step yourself, I find this article quite good to get started with them: https://www.braveclojure.com/writing-macros/

p-himik14:02:46

One thing to note - [:a-b] and [:a :b] will generate the same exact symbol for def in your case. Something to be aware of. Either of the steps could make the check and report any collisions.

p-himik14:02:10

Another thing - your IDE probably won't be able to figure out that there are some generated def statements. So no autocompletion and symbol resolution unless you customize it yourself.

Fredrik Andersson16:02:58

ok, thanks ill look into it. But then i know it wouldnt be futile to give it a try

👍 3
snickell18:02:27

👋 , any recs on the best way in 2021 to start on a cljs project where I can’t use JVM at all (target processor has no JDK)?

thheller18:02:45

you don't need the JVM on the target once everything is compiled

snickell18:02:45

I’m tempted to start from #klipse, and remove pieces I don’t need, rather than work the other way….. my ideal would be a shadow-cljs level of featured REPL, but running on and accessed in the browser rather than from terminal

snickell18:02:59

I need CLJS scripting as a user feature in the webapp

snickell18:02:17

And ideally, it would be homogenous toolchain with how I write the core

snickell18:02:16

Cool, I read through that, I wasn’t sure how relevant it still was in 2021

thheller18:02:23

hasn't changed

snickell18:02:48

I’ll try to make a clone-able github repo that provides an example of this pattern

snickell18:02:11

oh…. @thheller hahaha, just recognized the name 🙇

👋 3
snickell18:02:12

@thheller I got a sense from your blog that this is sort a “yeah, you can do this, but its not a great path yet, avoid if you don’t really really need it”

snickell18:02:26

Does that seem accurate?

thheller18:02:17

if you need to eval at runtime thats the only path to do it apart from a slightly less powerful eval using https://github.com/borkdude/sci

thheller18:02:01

and yes, if you don't really need eval then you shouldn't do it as it makes the build rather large

thheller18:02:42

kinda depends on what kind of eval you are talking about

FlavaDave18:02:20

Having trouble using base64 encoding a file from a file uploader and getting into the body of a request.

(defn form
  []
  [:div 
   [:form {:id       "upload-form"
           :enc-type "multipart/form-data"}
    [:label {:for "upload-file"}
     "upload"]
    [:input {:type   "file"
             :id     "upload-file"
             :name   "upload-file"
             :accept "image/jpeg"}]
    [:button {:on-click #(upload-file "upload-file")}
     "button"]]])

(defn put-file-in-bucket [file path]
  (PUT (str endpoint "/photo/bucket-name/" path)
       {:handler       handler
        :error-handler error-handler
        :body          file}))


(defn upload-file [element-id]
  (let [el        (.getElementById js/document element-id)
        file      (aget (.-files el) 0)
        file-name (.-name file)
        reader    (new js/FileReader)
        binary    (.readAsText reader file)
        b64       (js/btoa binary)]
    (put-file-in-bucket b64 file-name)))
That is as far as ive gotten so far but when i console.log the results of (.readAsText reader file) it comes back as undefined and same as when i use (.readAsBinaryString reader file).

p-himik18:02:00

Those functions don't return anything. They change the reader in-place.

p-himik18:02:55

All file operations are async, you cannot directly get a result from something like that - you have to chain the actions together with promises or events.

FlavaDave18:02:50

ah ok that makes sense

FlavaDave18:02:47

i found this code online

input.onchange = function () {
  var file = input.files[0],
    reader = new FileReader();

  reader.onloadend = function () {
    // Since it contains the Data URI, we should remove the prefix and keep only Base64 string
    var b64 = reader.result.replace(/^data:.+;base64,/, '');
    console.log(b64); 
  };
the only thing i dont understand is how to use interop on the reader.onLoadEnd = function() …

FlavaDave18:02:53

would it be (def on-load-end (.onLoadEnd reader #(,,,)?

p-himik19:02:12

(set! (.-onloadend reader) (fn [event] ...)) This is a decent cheat sheet: https://cljs.info/cheatsheet/

FlavaDave20:02:29

Thank you. I’ll try that out later today

snickell18:02:35

@thheller Hi, build size is no worries for this use, since its cached on-device

borkdude18:02:25

there is a #sci channel if you want to know more

henrik4219:02:15

Hey! We have a JavaServerFaces app with some JavaScript code (inlined as well as in js-src). So we're working with post-backs and page-loads/navigation all the time. What could be a migration path to first using CLJS for better UX and later switch to SPA and get rid of JSF? A naive idea would be to just replace the JS with CLJS, but we would be loading it over and over again. May be not too bad since it's an internal app so little latency and much bandwidth and browser cache. Would wrapping the JSF app in an IFRAME help? So load the CLJS just once and keep it while doing the JSF navigation just in the IFRAME. I'm not an expert browser/JS developer so I wonder if that could work. Any thoughts? Anyone else mixing JSF and CLJS?

snickell20:02:53

@borkdude / @thheller What are the eval differences / tradeoffs between the two approaches?

borkdude20:02:49

if you ask me: self-hosted yields a bigger bundle size (about 8mb unzipped, 1mb zipped) but bundles a full compiler: the code it generates is more performant than an interpreter. sci offers a (significant) subset of clojure as an interpreter: smaller bundle size, but the code in it will not run as performant.

snickell20:02:24

Got it! I’m running on an embedded device without JVM support

snickell20:02:31

So bundle size is not a concern

borkdude20:02:53

sci can run in advanced compiled CLJS and can hook into your advanced compiled functions, which may compensate performance issues

snickell20:02:01

I think….. repl tooling and features, and performance of compiled code are probably my emphasis?

borkdude20:02:10

whereas self-hosted cannot run in advanced mode

snickell20:02:25

oh interesting!

borkdude20:02:59

@snickellto go back to your original problem: > to start on a cljs project where I can’t use JVM at all (target processor has no JDK) why don't you compile on another machine which does have a JVM and then move the JS to the device that doesn't have a JVM?

borkdude20:02:24

I mean, browsers don't have a JVM either (well, let's ignore applets). That's no reason to not use CLJS + JVM for dev

snickell20:02:50

I need to compile potentially complex user entered scripts

snickell20:02:04

(or interpret)

borkdude20:02:08

right, gotcha. yeah, then self-hosted or sci makes sense.

snickell20:02:28

thanks, I appreciate your feedback, you always know least when you start on a new area

snickell20:02:42

You’re helping me not blow my foot off while I figure out the self-hosted area

Ricardo Cabral21:02:09

Hello all, why is so complicated to add npm dependencies to a clojurescript project? Do people use shadow-cljs for it? I am just trying to add react and testing libraries (https://testing-library.com/) along with react. and figwheel and clojurescript. Can someone let me know what is the stack to create a project TDD based with clojurescript?

seancorfield23:02:01

@ricardozcabral I suspect a lot of folks doing ClojureScript just use clojure.test because it's built in and then use one of the various cljs test runners (I use the CLI/`deps.edn` rather than lein so I use Olical's cljs-test-runner for some stuff and I just started using Figwheel Main and I seem to recall that automatically runs your tests for you and can display them in a browser).

👍 3
seancorfield23:02:53

(and, so far, I've managed to avoid npm and any dependencies from that!)