cherry 2026-07-28

We have a lib at work that we share on npm - atm using figwheel to compile it to an npm module with webpack. Is this a good usecase for cherry?

yes, or squint

Nice, thanks! How do you decide between them?

I guess squint is better for interop with the js side of things

and cherry if there’s a lot that depends on cljs semantics?

squint yields better bundle sizes, cherry is more CLJS compatible in that its data structures are the same as CLJS. but most of the time in squint you don't really notice

If you want an example or two: I published babashka.cli and babashka.fs to npm using squint while it's also consumable from CLJS and CLJ

Ah yeah, I just remembered this is a cljc library so I guess that rules out squint?

We want to use it on the backend too

no that would work perfect with squint, it supports the :squint + :cljs reader conditional

put :squint before :cljs if you want to override it for squint only

ooh interesting

just look at the bb.cli + bb.fs sources to get an idea

👍 1

nextjournal.clojure-mode is also published to npm via squint

A year ago I would have said cherry covers more edge cases and is more seamless but the last few months I've moved my cljc libraries to squint/jvm and means I don't need to worry about doing a clj->JS for any var which I might want the JS consumer to use externally

I didn't realize at the outset how often that boundary would be something I'd want to cross

I like the idea of not having to do clj->js everywhere

What do you do for promises? I’ve been using promesa in the current iteration, but I guess that’s not supported in squint - but I imagine now cljs has async/await there’s maybe a simpler way?

cljs async/await was invented in squint :) so it has the same syntax

no need for promesa

oho I got it backwards ha

Would you then use core.async in the cljc file? Is there a lil example I could peruse?

why would you need to use core.async?

Just thinking through if we switch to squint what to replace all the promesa calls with

tell me what you did in promesa and I'll tell you how to do it in async/await. Small examples please

Lots of p/let, p/then, p/catch and a bit of p/race (for cancellation or timeouts). e.g. (simplified)

(defn get-visualization [{:keys [device-ids period cancel-promise]]
     (-> (p/race [cancel-promise ;;passed in by user to cancel the operation
                  (p/let [devices (get-devices device-ids)  ;; api calls
                          data (get-data devices period)]
                    (visualize data) ;; just a regular fn
         (p/then (fn [result] 
                    (if (cancelled? result) :cancelled
                        result))

Not sure if that is exactly correct as typing into slack, but roughly the kind of thing

And then the API we exposed to js was mainly these kind of functions that return promises

p/let translates as:

(let [devices (await (get-devices))
      data (await (get-data devices period)]
  (visualize-data))
I think I'd put that expression in a separate top level fn or anonymous inner fn to be able to "race" it and stop it from execution immediately. race would just be Promise.race with a vector of promises I think p/then is just regular
(do (await this) (await that))
of if you need bindings, then it would just be a let + await again. does that make sense?

pretty much how you would write it in JS

oh wait, cancel-promise is an argument sorry

ohhh so await returns a promise. Ok that all sounds pretty straightforward. Makes total sense thanks. Just one more question though - in cljc, what would you do on the clojure branch? Because clojure doesn’t have the same async/await syntax, right? (that’s why I was thinking core.async) Use regular futures or completable futures or someting else? Because we consume the lib from clojure as well as exporting to js,

this simplifies things.

(defn ^:async get-visualization [{:keys [device-ids period cancel-promise]}]
  (let [result (await (js/Promise.race
                        [cancel-promise ;; passed in by user to cancel the operation
                         ((^:async fn []
                            (let [devices (await (get-devices device-ids)) ;; api calls
                                  data (await (get-data devices period))]
                              (visualize data))))]))]
    (if (cancelled? result) :cancelled result)))

❤️ 1

this might be a bit cleaner:

(defn ^:async fetch-visualization [device-ids period]
  (let [devices (await (get-devices device-ids))
        data    (await (get-data devices period))]
    (visualize data)))

(defn ^:async get-visualization [{:keys [device-ids period cancel-promise]}]
  (let [result (await (js/Promise.race [cancel-promise
                                        (fetch-visualization device-ids period)]))]
    (if (cancelled? result) :cancelled result)))