clojurescript

ClojureScript, a dialect of Clojure that compiles to JavaScript http://clojurescript.org | Currently at 1.10.879
2021-05-07T13:37:43.165700Z

Hi. What’s the recommended way to do logging in clojurescript?

👍 1
2021-05-07T13:47:25.165900Z

Seems https://github.com/lambdaisland/glogi is a good choice.

✅ 2
2021-05-07T15:12:21.166500Z

https://github.com/ptaoussanis/timbre also really good

Scott Meyers 2021-05-07T15:22:46.171700Z

When working with Reagent + Google Maps API, I've created a "Polyline" form 2 component, saving a reference of the shape (google.maps.Polyline) in an atom within the component. When Figwheel re-renders after a change, the lines disapear on the Map, but I can confirm they still exist. Does anyone have any advice for working with shapes in google maps w/ Reagent? I want to generate Polylines for each item in an array stored in my global app state. I want to then select one of them and have it styled slightly differently (stroke color).

valtteri 2021-05-08T07:01:07.191400Z

Yep. Google Maps is highly stateful and dealing with stateful js components is a bit painful. However this strategy has worked for me well https://github.com/day8/re-frame/blob/master/docs/Using-Stateful-JS-Components.md

valtteri 2021-05-08T07:01:29.191700Z

Google maps happens to be an example there. 🙂

Scott Meyers 2021-05-07T16:12:25.172700Z

I think this has something to do with defonce , since I'm storing state in a component w/ let , it is lost when Fighweel reloads. I need to figure out a way to retain a reference to each shape drawn on the map that will persist.

Karol Wójcik 2021-05-07T16:39:54.173900Z

Are there any alternatives to lumo which could support nodejs libraries?

Karol Wójcik 2021-05-08T07:45:29.192200Z

I'm looking for something that I can embedded in AWS Lambda runtime.

thheller 2021-05-08T08:14:54.193800Z

embed what? just use a random node library or cljs-eval?

Karol Wójcik 2021-05-08T10:28:47.198100Z

@thheller I would like to have the same capabilities as lumo for Clojurescript or ts-node for Typescript. I would like to just pack Clojurescript sources and node_modules in zip and run shadow-cljs bootstrapped-run entrypoint.cljs instead of compiling Clojurescript-> Javascript beforehand.

thheller 2021-05-08T10:59:58.198300Z

I don't know what you mean by "same capabilities". why use bootstrapped if you can just precompile it normally?

Karol Wójcik 2021-05-08T12:12:10.198500Z

For AWS Lambda it's convenient to have a bootstrapped Clojurescript, so you could change sources and see immediate change on Lambda.

valtteri 2021-05-07T16:44:59.174500Z

How does the code look like?

valtteri 2021-05-07T16:45:47.175700Z

I mean, it’s easier to help if you post relevant chunks of code here 🙂

Scott Meyers 2021-05-07T17:20:26.176Z

(defn polyline
  "Creates a Polyline on the Map"
  [path gmap]
  (let [ref (r/atom nil)]
    (fn [_ _ is-selected]
      ; if the polyline hasn't been created, create it
      (when (nil? @ref)
        (reset! ref (js/google.maps.Polyline.
           (clj->js {:path path
                     :geodesic true
                     :strokeColor "black"
                     :strokeWeight 6
                     :map gmap})))
      )
      ; if the polyline has been created and toggled
      ; set the appropriate strokeColor
      (when (some? @ref)
        (if (and is-selected (some? @ref))
          (.setOptions @ref (clj->js {:strokeColor "blue"}))
          (.setOptions @ref (clj->js {:strokeColor "black"})))
        )
      nil
      )))

Scott Meyers 2021-05-07T17:21:09.176200Z

In my App component, we iterate over each item that would render a Polyline:

(doall (for [activity (:activities @app-state)]
               ^{:key (util/get-activity-time activity)}
               [maptools/activity
                activity
                (:gmap @app-state)
                (util/is-selected? (:selected-activity @app-state) activity)
                ]))]]))

valtteri 2021-05-07T18:11:44.176500Z

How are you rendering the google map? Does that happen inside or outside React render tree? My guess is that on figwheel reload your whole google map gets initialised again

valtteri 2021-05-07T18:46:37.177100Z

(assuming you’re not using some react wrapper for google maps)

Scott Meyers 2021-05-07T20:31:22.177800Z

Yeah, I think that's the issue as well. I have a component for the Google Map, which looks like this:

Scott Meyers 2021-05-07T20:31:40.178Z

(defn google-map [app-state set-error]
  (let [api-key (subs (-> js/document .-location .-search) 1)
        center (clj->js {"lat" 40.730610
                         "lng" -73.935242})
        loader (google.maps.plugins.loader.Loader.
                (clj->js {:apiKey api-key
                          :version "weekly"}))]
    (fn []
      (.addEventListener
       js/window
       "DOMContentLoaded"
       (-> (.load loader)
           (.then (fn []
                    (swap! app-state assoc :gmap (google.maps.Map.
                                                  (. js/document (getElementById "map"))
                                                  (clj->js
                                                   {:center center
                                                    :zoom 8
                                                    :fullscreenControl false
                                                    :clickableIcons false
                                                    :disableDoubleClickZoom true})))))
           (.catch #(set-error "Unable to load Google Maps"))))
      [:div {:id "map"}])))

Scott Meyers 2021-05-07T20:32:21.178200Z

I can confirm that it re-renders each time I save a change in the project directory.

2021-05-07T20:34:07.178500Z

Vanilla CLJS can. So Shadow-CLJS / FIgwheel-main too: • https://figwheel.org/docs/nodejs.htmlhttps://clojurescript.org/guides/quick-start#running-clojurescript-on-node.js

2021-05-07T20:43:48.179900Z

Dymanic import import('foo').then(module => console.log(module)); seems now supported by the last Google Closure compiler: https://github.com/google/closure-compiler/issues/2770#issuecomment-834744931

thheller 2021-05-08T08:10:29.192400Z

the dynamic+dynamic import style isn't supported by the closure-compiler and likely will never be, webpack also has issues with it.

thheller 2021-05-08T08:10:46.192600Z

so import(someVariable).then ... will always be a problem for bundlers when they are supposed to bundle stuff

thheller 2021-05-08T08:11:30.193Z

it is fine to do at runtime when you don't expect the bundler to bundler stuff but instead import already bundled stuff like code-split modules

thheller 2021-05-08T08:12:14.193200Z

I had an example for truly dynamic import here https://clojureverse.org/t/generating-es-modules-browser-deno/6116

thheller 2021-05-08T08:13:42.193600Z

webpack has a partial interpreter to figure out some dynamic imports but it is fairly limited and usually requires a bunch of build configuration

p-himik 2021-05-08T08:27:24.194Z

@thheller Your example tackles truly dynamic imports whereas cljs.loader/load requires for the imported thing to be a predefined module. Are there some other differences that are important?

thheller 2021-05-08T08:27:52.194200Z

you'd use the dynamic-import instead of cljs.loader (in case of an :esm build). so no cljs.loader included at all, just purely build-in import

thheller 2021-05-08T08:30:17.194600Z

the import variant that can be rewritten I have not tried yet. not sure what the closure-compiler turns it into or how it needs to be configured

2021-05-08T12:40:49.198700Z

Thanks both for these replies and useful informations...very interresting. 👍

p-himik 2021-05-07T20:46:42.180400Z

You can already do the same thing in CLJS with code splitting.

p-himik 2021-05-07T20:46:45.180600Z

https://clojurescript.org/guides/code-splitting

2021-05-07T20:46:58.180900Z

Is it something interresting for CLJS in the futur?

joshmiller 2021-05-07T20:59:22.184100Z

I’m having an issue with eval in Clojurescript. My use case is that I’m importing a bunch of rules as s-expressions and executing them against the current state of the app. I have a function called present? that is kind of like (complement nil?) but for JS input fields, i.e. it checks to see if a field’s value is "" or js/NaN, that kind of thing. When I eval (present? 1), I get true. When I eval (or (present? 1)), I get true. When I eval (or (present? 1) true) I get nil.

joshmiller 2021-05-07T20:59:38.184400Z

Here is a gist with the minimal steps to get there: https://gist.github.com/joshuamiller/20773273a234948013358f91e74c0392

joshmiller 2021-05-07T21:01:02.185Z

Does anyone have any ideas what I might be doing wrong?

2021-05-07T21:28:32.185500Z

Thanks. Rather, I saw the use to import another file dynamically like in these examples: https://inertiajs.com/pages#default-layouts But hey, this goes a bit against namespaces so I don't think so...

👍 1
2021-05-07T21:31:49.185700Z

At the moment, the only solution I have found is to list the pages manually: https://github.com/prestancedesign/reagent-inertia-reitit-integrant-fullstack/blob/main/front/src/reagent/inertia.cljs#L112-L121

p-himik 2021-05-07T21:39:48.186100Z

The JS example can be adapted just fine to work with namespaces.

p-himik 2021-05-07T21:40:03.186300Z

At least, it seems to me so.

p-himik 2021-05-07T21:45:44.186600Z

Just as an idea - you can try supplying a custom logging js-eval to see what actually gets evaluated. Maybe it it will shed some light.

joshmiller 2021-05-07T22:10:41.186900Z

Good idea, I’ll give that a shot.

joshmiller 2021-05-07T22:21:19.187100Z

My or with branches seems to not be returning anything, here’s the source it generates:

joshmiller 2021-05-07T22:21:23.187300Z

var or__43529__auto___44 = cljs.js.get_fn( 97 ).call(null,(1));
if(cljs.core.truth_(or__43529__auto___44)){
} else {
}

p-himik 2021-05-07T22:49:36.188200Z

A statement is something purely imperative - it has no value. An expression is anything that has a value. In CLJ(S) world, everything is an expression. In JS world, sometimes something has to be a statement to work.

👍 1
joshmiller 2021-05-07T22:53:52.188500Z

That makes sense in retrospect. I have played around with the code each context generates and you can see the difference.

p-himik 2021-05-07T22:55:48.188700Z

At the same time, it's interesting how (present? 1) still returns a value when using :statement.

joshmiller 2021-05-07T23:02:19.188900Z

I guess that when it’s not embedded in a conditional, it doesn’t matter whether it’s side-effecting or whatever, so it just calls it and you get what JS gives you.

p-himik 2021-05-07T23:07:11.189100Z

Yeah, but it should not have a return there if it's a statement. Otherwise, it could break some things. But I've never dealt with eval before, so I can be completely wrong.