Fork me on GitHub
#clojurescript
<
2023-12-28
>
Noah Bogart06:12:35

i'm looking for a hiccup library in clojurescript. i'm not looking to use something as heavy as reagent, i just want to convert [:div ...] to <div>...</div> in plain clojurescript for use in a simple app (modify the dom lightly). which is the best hiccup library for something with no backend?

p-himik09:12:23

I ended up writing my own code for this, it's like 20 lines, although for XML.

๐Ÿ‘ 2
sergey.shvets16:12:31

take a look at hicada if you target jsx/react.

sergey.shvets16:12:23

It's also a nice "template" on how to write your own, as Eugene said above it's relatively easy half a day project.

p-himik16:12:04

> half a day Barely an hour. :) It really doesn't require that much. Here's the code that I have, that also supports fragments to make some things easier:

(defrecord Fragment [children])

(defn fragment? [x]
  (instance? Fragment x))

(defn append-child! [^js el child]
  (if (fragment? child)
    (doseq [child (:children child)
            :when (some? child)]
      (append-child! el child))
    (.append el child)))

(defn hiccup->element [hv ^js doc]
  (if (vector? hv)
    (let [[tag attrs-or-child & children] hv
          attrs (when (map? attrs-or-child) attrs-or-child)
          children (cond->> children (nil? attrs) (cons attrs-or-child))]
      (if (= tag :<>)
        (do
          (assert (nil? attrs))
          (->Fragment (mapv #(hiccup->element % doc) children)))
        (let [el (.createElement doc (name tag))]
          (doseq [[attr val] attrs]
            (.setAttribute el (name attr) (str val)))
          (doseq [child children
                  :let [child-el (hiccup->element child doc)]
                  :when child-el]
            (append-child! el child-el))
          el)))
    hv))

(defn hiccup->document [hv]
  (let [doc (.createDocument js/document.implementation nil nil)
        el (hiccup->element hv doc)]
    (when el
      (append-child! doc el))
    doc))

๐Ÿ˜ 2
๐Ÿ‘ 1
Noah Bogart18:12:53

Dang, thank you!

i like the slack19:12:47

just write it yourself, takes maybe 50 lines tops

p-himik19:12:04

You should check the thread. ;)

cjohansen20:12:42

What's the fastest/most direct way to loop a collection for side effects in ClojureScript?

(doseq [x ["a" "b" "c" "d" "e" "f"]]
  (js/console.log x))
This generates a surprising amount of code, I'm guessing because of the vector.

Sam Ferrell20:12:38

Theres a large constant overhead for even the shortest CLJS programs

Sam Ferrell20:12:24

doseq is the most idiomatic way to iterate through a collection for side effects

p-himik20:12:04

The amount of code is not because of the vector but because of doseq. Although I've checked only the CLJS compiler output and I suspect a lot of that code will be removed by GCC during a production build. You can try using run! instead if all you need is to call a function. loop is another alternative.

hifumi12320:12:29

yup, i agree โ€” in general, macros like for and doseq have high overhead and are only worth it IMO when you actually use list comprehensions

hifumi12320:12:21

I would expect the lowest-overhead alternative, without writing JS interop, is to use loop, followed by run!, and then doseq

thheller20:12:44

fastest is reduce/`run!` by far, if talking specifically about a vector

โž• 1
cjohansen21:12:51

Cool, thanks!

cjohansen21:12:18

My "surprising amount of code" comment on doseq was based on a production build btw

hifumi12321:12:54

yeah, in CLJS codebases I avoid for and doseq for similar reasons โ€” Iโ€™ve found them to have ridiculous overhead in simple cases like (for [x xs] (do thing with x))

hifumi12321:12:18

thatโ€™s why I personally avoid these macros unless I am using more complex list comprehensions

cjohansen21:12:59

Related: I have a loop that loops two collections. It currently uses first and next to process each item and recur, but I also occasionally need to perform .indexOf style searches in them. Would it be better to write this with vectors, a separate n and use nth for lookup?

p-himik21:12:17

If you already have a vector, it has .indexOf. FWIW, I myself don't really try to limit myself in terms of constructs that I use. A single NPM dep will almost certainly increase the bundle size by much more than all the doseqs that I can use in my code.

Sam Ferrell21:12:19

cljs is not a great choice if your priority is tiny bundle sizes

cjohansen21:12:36

I know all this ๐Ÿ™‚

cjohansen21:12:05

I'm working on a library, and I am running a benchmark, trying to shave off some milliseconds here and there

cjohansen21:12:42

I generally try to avoid even a single npm dep ๐Ÿ˜„

cjohansen21:12:31

I wasn't that worried about the amount of code in itself, but I was hoping for something performing close to a JS loop, and I did not have a lot of faith in the amount of code I saw from a simple doseq.