clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
Trevor Martin 2021-03-31T03:24:46.389500Z

Hi 👋, I'm new to Clojurescript and I've written a neat little reagent app that makes a call to an API, stores the result in an ratom and renders the information accordingly. super-cool stuff. I'm loving it. I've become accustomed to storing things like the BASE_URL to any given API within process.env.VARIABLES how do I access these from cljs ? or is there a better way to do this ? is it build-tool specific ?

tvirolai 2021-03-31T11:41:20.392500Z

Environ (https://github.com/weavejester/environ) is a good option for doing this. It combines parameters from different sources into a single map for processing in the application.

p-himik 2021-03-31T13:38:52.393500Z

That will work only if process.env is set correctly. And you can access keys within process via goog.object - no need to extra libraries unless you need to share the same code with CLJ. As an alternative approach, you can use goog-define and set its values in compile time. This would depend on the build tool. Relevant documentation for shadow-cljs: https://shadow-cljs.github.io/docs/UsersGuide.html#shadow-env

Trevor Martin 2021-03-31T20:20:55.415700Z

thanks for that insight, if I understand correctly,

(goog-define BASE_URL "<http://localhost:8080/api>")
will set a default value to be overwritten at compile time ... and that value is read from shadow-cljs.edn
...

 :builds
 {:app
  {:target     :browser
   :output-dir "public/js"
   :closure-defines {my.app.core/BASE_URL "<https://fully-qualified-domain-name/api>"}

p-himik 2021-03-31T20:59:28.416700Z

Yes. And that value, in turn, can be overridden via a CLI parameter, which can accept a real environment variable value.

🙏 1
vanelsas 2021-03-31T14:47:01.395600Z

Has anyone worked with https://github.com/recharts/recharts in Clojurescript/Reagent? Looking for a way to draw custom graphs. I looked at react-vis (it works) but it isn't maintained anymore. Can't find any examples with recharts.

vanelsas 2021-04-01T07:24:06.430100Z

I'll take a look thanks!

vanelsas 2021-04-02T06:56:20.445200Z

thx! will take a look. At my first attempt I ran into all kinds of compiling issues. Hopefully your example can help me to get that right!

macrobartfast 2021-03-31T18:00:35.396400Z

take a look at https://github.com/metasoarous/oz

vanelsas 2021-04-01T07:24:20.430300Z

Will do thanks!

macrobartfast 2021-03-31T18:00:50.396700Z

very nice looking charts

macrobartfast 2021-03-31T18:01:17.397Z

(and I’ll look at recharts)

macrobartfast 2021-03-31T18:03:43.398400Z

I also am curious for an answer to your question (if anyone has looked at recharts in cljs) and and/or if there are other D3 type integrations for cljs.

macrobartfast 2021-03-31T18:04:16.399Z

I looked around and it seemed like there were a couple options that weren’t too current (but maybe they just still work).

macrobartfast 2021-03-31T18:05:30.399200Z

recharts looks really nice.

macrobartfast 2021-03-31T18:27:35.399300Z

if you try Oz and get the example project running, let me know the steps to get it running…

macrobartfast 2021-03-31T18:28:01.399500Z

running into errors starting the project (due to my lack of knowledge, I’m sure)

2021-03-31T19:32:21.403700Z

I'm trying to learn re-frame and having a bit of issue with the basics. I have a little hello, world style app that lets me increment / decrement some numbers. Then when I click Start I want it to show the selected number and make the selector part dissappear: I have this for my selector bit:

(defn countdown-initiator []
  (let [time-entered (reagent.core/atom 0)
        visible @(rf/subscribe [:initiator-visible])]
    (fn []
      [:div.initiator {:style {:visibility (if visible :visible :hidden)}} ;; &lt;&lt;&lt; I don't understand why this isn't triggering it to be invisible.
       [:div.timer @time-entered]
       [:div
        [:button.btn.up
         {:on-click #(swap! time-entered inc)}
         [:i.fas.fa-chevron-up]]
        [:button.btn.down
         {:on-click #(if (&gt; @time-entered 0)
                       (swap! time-entered dec))}
         [:i.fas.fa-chevron-down]]]
       [:div
        [:button.btn.btn-danger {:on-click #(rf/dispatch [:start @time-entered]) ;; &lt;&lt;&lt; On Clicking start, fire the :start event (I've put this below)
                                 :style    {:margin-top 10}} "Start"]]])))
My event that is changing :initiator-visible in my appdb and subscription:
(rf/reg-sub
 :initiator-visible
 (fn [db _]
   (db :initiator-visible)))

(rf/reg-event-db
  :start
  (fn [db [_ time]]
    (-&gt; db 
        (assoc :time-remaining time)
        (assoc :countdown-visible true)
        (assoc :initiator-visible false)))) ;; &lt;&lt; Set initiator-visible to false.
Re-Frame-10x shows the value appdb is false. Can someone see what I'm doing wrong? If I make a change to the code and it causes a hot-reload, it dissapears, so it's like I'm a step behind or something?

2021-03-31T19:33:57.404Z

Have a gist of the full page https://gist.github.com/stuartstein777/a1e9e40146489392cca4af97b7bfb23d

2021-03-31T19:44:34.405700Z

OK, have it working. Rather than doing

(let [visible @(rf/subscribe [:initiator-visible])]
    ,,,
    {style {:visibility (if visible ,,,)}})
I do
(let [visible (rf/subscribe [:initiator-visible])]
    ,,,
    {style {:visibility (if @visible ,,,)}})
And de-ref in the form-2 render function, it works but I'm not sure if this is the correct thing to do

2021-03-31T19:45:04.406200Z

I guess the de-ref has to happen in the render to make re-frame realise that render function needs re-run ???

2021-03-31T19:49:53.406600Z

Yes, that’s it exactly.

2021-03-31T19:50:44.407200Z

You can also put the @(rf/subscribe [:initiator-visible]) inside your rendering function and skip the let completely.

2021-03-31T19:51:23.407800Z

Ah ok, I thought if had a re-agent form that had state I should use this let and fn to make it a form-2

2021-03-31T19:52:14.409Z

btw, re-frame-10x is wonderful for debugging as a beginner in this framework!

2021-03-31T19:52:29.409400Z

Originally that was the idea, but re-frame now has a caching scheme for subscriptions that makes it work correctly if you throw the @(subscribe ,,,) directly in a form-1

2021-03-31T19:52:41.409700Z

Simplifies things a bit

2021-03-31T19:52:52.410100Z

cool, thank you! I didn't know that.

2021-03-31T19:52:56.410200Z

And yeah, 10x is great 😄

Kira McLean 2021-03-31T20:04:49.415600Z

How are people writing big cljs apps testing them? Any open source examples out there? I’m curious what people have found works well. Some things I want/need for my cljs test suite: • easy to run (either a keyboard shortcut to run them in a repl, like I do for clj, or a watcher I can spin up that will auto-run any tests that change) • runner for CI (could be the same way the tests run in development but doesn’t have to be, but either way need a way to run a single command and get an exit code indicating test suite pass/fail) I guess that’s really all. I’ve cobbled together some things from random blog posts and docs, but so far everything’s still very janky. I’m trying to fix this and find a way to develop a large cljs project that’s not painful to test, so curious about others’ experiences.

simongray 2021-03-31T20:22:14.415900Z

@kiraemclean I just use the built-in reactive test runner in shadow-cljs and always have a tab open with my tests. When the favicon turns the wrong colour I go and check which test is failing.

Kira McLean 2021-03-31T20:23:02.416300Z

that sounds pretty ideal.. what do you mean by “built-in” to shadow-cljs? the browser tests as described here? https://shadow-cljs.github.io/docs/UsersGuide.html#target-browser-test

simongray 2021-04-01T07:08:39.429900Z

Yes. It's really easy to get going and works very well.

👍 1
Kira McLean 2021-03-31T20:23:16.416500Z

and do you run the tests in ci?

Heather 2021-03-31T21:13:13.417700Z

Our clojurescript tests are all integration tests; we don’t have any unit cljs tests.

Kira McLean 2021-03-31T21:13:36.418100Z

do you mean using etoain against a server running your whole app?

Ronny Li 2021-03-31T21:34:24.418200Z

that's exactly the guide that I followed

Ronny Li 2021-03-31T21:35:44.418400Z

then npx shadow-cljs watch test to start the test in another tab.

Ronny Li 2021-03-31T21:38:08.419900Z

Hi everyone, what's the CLJS equivalent for the following:

let alpacaUrl = new URL('<https://app.alpaca.markets/oauth/authorize>');
alpacaUrl.searchParams.set('response_type', 'code');
alpacaUrl.searchParams.set('state', state);
I'm mostly getting tripped up by repeatedly running alpacaUrl.searchParams.set to modify the original alpacaUrl inplace. (In my actual code I'm calling set on searchParams 6-7 times)

dpsutton 2021-03-31T21:46:52.420400Z

(let [url (js/URL. "<https://app.alpaca.markets/oauth/authorize>")]
  (doseq [[k v] [["response_type" "code"]
                 ["state" "state"]]]
    (.. url -searchParams (set k v)))
  url)
#object[URL <https://app.alpaca.markets/oauth/authorize?response_type=code&amp;state=state>]

🙏 1
p-himik 2021-03-31T21:55:18.421100Z

And if you need to set only two parameters, then use doto instead of doseq.

lilactown 2021-03-31T22:38:10.423Z

yeah imo this is slightly more idiomatic:

(let [alpaca (doto (js/URL. "<https://app.alpaca.markets/oauth/authorize>")
                (.. url -searchParams (set "response_type" "code")
                (.. url -searchParams (set "state" "state"))]
  ,,,)

🙏 1
dpsutton 2021-03-31T22:46:27.423700Z

(doto (js/URL. "<https://app.alpaca.markets/oauth/authorize>")
              (.. -searchParams (set "response_type" "code"))
              (.. -searchParams (set "state" "state")))
(the url needs to be omitted in the doto)`. And that's fine for 2 but they mentioned it goes a bit higher to 6 or 7

🎯 1
🙏 1
Azzurite 2021-03-31T23:09:31.424600Z

is there something special I have to watch out for when using macros in cljc? I created a macro and used it in the same file, however shadow-cljs tells me

31 | (def-styled-component  page [contents]
--------^-----------------------------------------------------------------------
 Can't take value of macro azzurite.web.content.homepage/def-styled-component
--------------------------------------------------------------------------------
does that need the code or is there just something I'm missing from the start?

Azzurite 2021-03-31T23:10:40.425100Z

looks to me like I'm not "taking the value" but actually using the macro

lilactown 2021-03-31T23:22:27.425400Z

@azzurite is this a CLJC file?

lilactown 2021-03-31T23:22:40.425600Z

whoops skimmed your message sorry

lilactown 2021-03-31T23:23:16.426500Z

in your namespace, you'll want to require-macros the macro namespace in a reader conditional

Azzurite 2021-04-01T14:29:13.434Z

why would I want to require the same namespace that the macro and the place where I use the macro are both in?

Azzurite 2021-04-01T14:29:43.434300Z

> I created a macro and used it in the same file

lilactown 2021-04-01T14:38:02.434500Z

it's a quirk of the compiler. there are two namespaces: your ClojureScript namespace, and the Clojure macro namespace

lilactown 2021-04-01T14:44:47.434700Z

even though your Clojure namespace is loaded in the process of the compiler, it doesn't know to include its context in the compilation process of your ClojureScript namespace unless you declare it

Azzurite 2021-04-01T14:57:17.434900Z

thank you very much! 😄

mfikes 2021-04-01T21:28:30.436500Z

Even though you can use .cljc to try to put everything in one file, I've found it simple enough just to have two files. TBH, macros aren't being authored that frequently anyway. Here is what I do: https://blog.fikesfarm.com/posts/2018-08-12-two-file-clojurescript-namespace-pattern.html

mfikes 2021-04-01T21:31:14.436700Z

I've even gone down the rathole of trying to actually define macros in the same file, using them just like you might in Clojure (even in the same REPL session): https://github.com/mfikes/chivorcam

mfikes 2021-04-01T21:31:27.437Z

But, IMHO, the two-file pattern is just simpler. 🙂

lilactown 2021-03-31T23:23:55.427500Z

(ns azzurite.web.content.homepage
  ,,,
  #?(:cljs (:require-macros [azzurite.web.content.homepage])))

,,,

👆 1
lilactown 2021-03-31T23:24:40.428Z

I think that if you :refer [def-styled-component] you can use them without namespace qualifying them too

Heather 2021-03-31T23:26:04.428100Z

We have an acceptance version of our app up on the web and we use selenium tests. Our clojurescript is all webpage/js code, so we have the tests click around there.

👍 1