Fork me on GitHub
#beginners
<
2021-05-10
>
Pavel Klavík00:05:30

Hi, I have the following ClojureScript code to get the set of all loaded fonts:

(->> js/document .-fonts .entries (map #(.-family (first %))) set)
.entries returns JS iterator object. It works perfectly fine in Chrome, but I am getting the following error on iOS Safari:
Execution error (Error) at (<cljs repl>:1).
[object FontFace] is not ISeqable
Of course I can rewrite it directly using JS interop. But is this a bug in ClojureScript compiler? Or is there some other idiomatic way to write this code?

dpsutton01:05:47

I’d look at documentation and the stack trace. My guess is that family is returning a single fontface either due to differences in how the browser works or different fonts loaded in the browsers

Pavel Klavík01:05:43

ok, so I checked further and the error is unrelated to JS iterator object

Pavel Klavík01:05:11

for whatever reason Chrome returns an array with two FontFace (hence using first), but Safari returns just a single FontFace

dpsutton01:05:47

From which call? Fonts or family?

Pavel Klavík01:05:12

each value returned by iterator is array of two font-faces

Pavel Klavík01:05:39

in the end, I tested the map solution and it does not work in FF, screw this browser stuff ...

Pavel Klavík01:05:59

but I ended up with this code which seems to work everywhere

(defn- find-all-loaded-fonts
  "Iterates through all loaded fonts and construct a set of their font families."
  []
  (reduce (fn [[fonts it] _]
            (let [next (.next it)]
              (if (.-done next)
                (reduced fonts)
                (let [next-value (.-value next)
                      next-font (if (instance? js/FontFace next-value)
                                  (.-family next-value)     ; For Safari
                                  (-> next-value first .-family))] ; For Chrome
                  [(conj fonts next-font) it]))))
          [#{} (->> js/document .-fonts .entries)] (range)))

West05:05:34

I’m in the process of switching over to CircleCI for deploying my site to my raspberry pi. I’m using it as it seems to be a tad more flexible than gitlab CI. The trouble I’m having is getting ssh to work. Now usually I would do something like ssh-copy-id on my main machine so I can log in. Now CircleCI instructs to take the private key and add it via project settings -> SSH Keys -> Additional SSH Keys -> Add SSH Key. Then in the yaml put add_ssh_keys as one of the steps in my deployment job. Great in theory, but it doesn’t work. Am I missing something important? Maybe another helpful detail is, I’ll ultimately use rsync to transfer over the files over SSH. I did some searching and apparently there are problems with scp, which I used before. I tested rsync from my laptop, and it seems to transfer everything over just fine.

heyarne08:05:58

how can I add additional dependencies when using cloure -M:…? I am habitually trying out libraries using a nice repl (i.e. rebel-readline), for which i have the following alias defined:

{:rebel
 {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
  :main-opts ["-m" "rebel-readline.main"]}}
This lets me try out datahike for example via clojure -A:rebel -Sdeps '{:deps {io.replikativ/datahike {:mvn/version "0.3.6"}}}'. However, there's a deprecation warning that :main-opts shouldn't be used with clojure -A, clojure -M should be used instead. When using clojure -M:rebel , rebel-readline gets started lilke before, but (require '[datahike.api :as d]) fails because it can't find the dependency

Alex Miller (Clojure team)11:05:33

The latter should be correct, but you need to make sure to put -Sdeps before -M

👍 3
Alex Miller (Clojure team)11:05:42

Otherwise it becomes args to main

popeye13:05:09

I have output string below {\"email\":\"\",\"user\":\"popeye\",\"domain\":\"\",\"user\":\"popeye\",\"domain\":\"\",\"status\":\"valid\",\"reason\":\"The email address is valid.\",\"disposable\":false} how can i get the values from email and status

delaguardo13:05:02

How should the result look like?

popeye13:05:11

{"email":"<mailto:[email protected]|[email protected]>" "user":"name" "domain":"http://example.com" "status":"invalid" "reason":"No mail server for <mailto:[email protected]|[email protected]>" "disposable":false }

delaguardo13:05:08

then just read that string using any json reader. most likely they will return a map like you just describe

delaguardo13:05:40

clojure data.json I guess should be the first one to try

3
Jeevaraj MV13:05:08

Use Clojure data json

6
Jeevaraj MV13:05:46

(Json/read-str “{\”a”\”:1,\”b\”:2} Output would be like —> {“a” 1, ”b” 2}

Jeevaraj MV13:05:00

(get map key)

Rob Haisfield14:05:29

So I’m going through Clojure for the Brave and True, and I was wondering if there was some way that I could use the REPL to see what the value is of each of the symbols when I run it? Sometimes it’s hard to understand what’s going on, but I think it would be easier if I could tell what each “part” and “remaining” is and see how it’s executed.

Michael Stokley14:05:43

you could also step through it with a debugger

tvirolai14:05:25

A simple way would be to declare an atom outside the function scope and store the intermediate values there.

3
Michael Stokley14:05:56

there's also tap>. and also inline def (although that will get stomped on successive executions)

Michael Stokley14:05:24

or! just println

Noah Bogart14:05:09

tap> is good for that

Rob Haisfield13:05:19

Thank you! This is all super helpful

Rob Haisfield13:05:26

I’ll play around with these

FHE18:05:53

Hi. Does anyone know where you are supposed to point the javascript line in index.html for a webapp if you are using a build tool that has multiple kinds of output? Maybe the multiple possible build targets (I'm most concerned with dev vs production for now, but mobile later) are supposed to have the same target folder for their JS output? I am trying to get a bare minimum webapp built with shadow-cljs (on WSL2 Ubuntu 20.04 if that matters). So far I installed ClojureScript and npm and shadow-cljs, and I have created a project folder and in it run

npx create-cljs-project my-project
(as mentioned in https://shadow-cljs.github.io/docs/UsersGuide.html#_standalone_via_code_npm_code ). I'm having real trouble trying to follow the shadow-cljs User Guide beyond that, but I did, after poring through the giant file structure the command above creates, find out none of that contains the absolute basics of a webapp (index.html and maybe some CSS), so I manually created a 'public' folder with index.html in it, and 'css' and 'js' subfolders.

Drew Verlee20:05:11

From the quick start docs https://github.com/thheller/shadow-cljs#quick-start Given a shadow-cljs.edn with the following data:

{...
 :builds
 {:frontend
  {:target :browser
   :modules {:main {:init-fn }}
   }}}
> This config tells the compiler to call `(http://acme.frontend.app/init)` when the generated JS code is loaded. Since no `:output-dir` is configured the default `public/js` is used. So in your root directory, when you run npx shadow-cljs watch frontend it will target the browser and create a js code bundle based on the keyword you supply to the module hashmap. In this case :main becomes main.js (or thats what i recall) so you should have a public/js/main.js Now thats a development built (not minified, optimized, etc..) so likely you want to create a production build to. That and more is covered here in official guide: https://shadow-cljs.github.io/docs/UsersGuide.html#release

Drew Verlee20:05:22

err also try #shadow-cljs for other shadow-cljs related questions.

FHE21:05:11

@U0DJ4T5U1 Thanks. I'll re-read that tonight when I get at this again. 🙂 I thought of posting my question in the shadow-cljs channel, by the way, but I thought it might be more of a general question.

Drew Verlee00:05:17

@UH5SE3NM9 clojure(script) has to work with the platform tools. So your html's script tag has to point to the js file location, shadow-cljs is a build tool helped to provide some helper functions in organizing that. Basically every dev is going to want to do the same thing and with a library like shadow we can all be on the same page: reusable functionality, shared mindspace, optimizations, etc... So i would say its definitely a shadow cljs question. But the shadow docs are really good. Don't hesitate to ask me questions though 🙂

FHE01:05:00

I think I ended up starting in the deep end of the pool with: https://shadow-cljs.github.io/docs/UsersGuide.html While I was away from my computer and had a few minutes with my phone i found this: https://github.com/shadow-cljs/quickstart-browser ...kind of wish I had stumbled in that first. Ha. Going to go through that now.

FHE01:05:48

@U0DJ4T5U1 Can you shed any light on the 20MB (and 200ish folders and 1000ish files) installed in a fresh project folder by npx create-cljs-project my-project (as specified in the User Guide at the 1st link above)? ...whereas git cloning the quickstart folder+file set (as specified in the Quickstart at the 2nd link above) yields 5 folders and 7 files? Is the first, heavy installation just trying to guess at many, many libraries that a person might want?

FHE01:05:24

Oh...finishing the installation for the quick guide project actually results in another massive thing, slightly larger than the user guide one even. I guess my question about what the point of all those file is still stands, though.

Drew Verlee01:05:15

Npx is a way to localize Js, it puts it all on your directory, rather then globally. This is better for the obvious reasons. That's likely what your seeing.

Drew Verlee01:05:38

Well, I shouldn't say obvious, but I'm on my phone.

FHE01:05:54

OK. Maybe it will make more sense to me soon. 😉

Drew Verlee01:05:39

The files on your computer are used to build the files that will be sent to the browser, you don't have to be to concerned about the formers size.

Drew Verlee01:05:10

There are many steps to reduce size between the two.

Drew Verlee02:05:55

This isn't clojure ecosystem thing, it's more of a sensible way to handle deps. It's main stream, nearly every language does some version of it. Then again in assuming that's the issue, without seeing them files on question I might be leading you astray.

FHE02:05:17

Well in the first case, I'm not sure if the create-cljs-projectpart of the npx command is linked to shadow-cljs, but it seems like it's a pretty generic thing, so I did guess maybe everyone's JS or at least CLJS project folders start huge like that.

seancorfield02:05:33

@UH5SE3NM9 Are you talking about the node_modules folder?

seancorfield02:05:08

Yeah, you are, I just tried that command. Think of node_modules as the “Maven repository” of the JS world — go look in ~/.m2/repository for what Maven (and Leiningen/Clojure CLI) has installed on your system! 🙂

seancorfield02:05:45

That folders contains over 23,000 files for me in about 8,000 directories for me — it positively dwarfs what npm/`npx` lays down in node_modules! 😆

FHE02:05:50

@U04V70XH6 Yes, the node_modules folder.

seancorfield02:05:56

Just ignore it. Like I say, it’s the “Maven repo” of the JS world.

FHE02:05:06

I just took a peek in ~/.m2/repository folder. Yes..lots of stuff. Actually, I'm happy to see cider and hiccupthere. Both are things I thought I might want but would need separate installations later.

seancorfield02:05:15

It’s all just libraries — in both the JS world and the Java world. You don’t really “install” stuff in the Java world: the tools you use to run your code (or build your artifacts) automatically download the dependencies they need.

seancorfield02:05:38

package.json is the deps.edn of the JS world.

FHE02:05:50

You anticipated a question I was about to ask. Thanks. 😉

FHE02:05:40

...and I guess if I'm using shadow-cljs, I'm going to be manipulating (maybe not manually but still...) shadow-cljs.edn instead of deps.edn?

seancorfield02:05:16

Well, shadow-cljs.edn is all about the front end stuff you’d be doing with Shadow-cljs. If you also build a backend piece for the app, you’ll need deps.edn (or project.clj) for the Clojure part.

seancorfield02:05:55

Shadow-cljs is kind of its own “island”. But it’s an island that is very friendly to npm stuff if that’s what you need.

FHE02:05:11

Aha. But can't back-end stuff also be done with shadow-cljs? I thought the genesis of Node.js was for back-end stuff, and shadow-cljs seems pretty linked with node.

Drew Verlee03:05:02

Shadow is for producing JS. There are a lot of full stack frameworks in clojure. Try luminous, or fulcro. Both have options to use shadow. Your time learning shadow will pay off, it's widely adopted.

FHE03:05:53

So usable for server-side, but not without some other...what's the word...tooling?

FHE03:05:16

(like Luminus or Fulcro)

FHE03:05:36

I was going to try Luminus as my starting point, by the way (and did run into mention of Fulcro as well while trying to wrap my head around all this before actually setting anything up), but I was advised that might not be the best place to start.

FHE03:05:02

Maybe soon, though! I thought I could use shadow-cljs (and nothing more) to make a desktop app, by the way. If that's not true, then I may need Luminus or something like it sooner than I thought.

Drew Verlee11:05:13

A desk top app? I think you should have an idea of how you want to produce it first e.g are you doing to use electron?

Drew Verlee11:05:35

Most web development targets the browser, so that's what I assumed you were doing

FHE11:05:07

I am targetting the browser at first, to try to get something together (I think Reagent+Hiccup are called for for that but I just want to do some hot reload magic first). ...then I would like to try getting the same app runing stand-alone on desktop (not sure if I should look into cljc files (and branching with some Clojure code) or just node (shadow-cljs with a different target?)). ...and later also mobile (Reagent needed? and an extra piece ReactNative? Alternatively I've heard of NativeScript but that was a long while ago).

Elliot Stern19:05:10

Is there a more idiomatic way to write (if f (f x) nil) ?

localshred19:05:44

(when f (f x))?

6
👍 15
Henri Schmidt19:05:08

(if f (f x))

3