Fork me on GitHub

What are leiningen vs figwheel vs shadow cljs good at in a nutshell? Figwheel is replaced by shadow I guess in community now? Pretty basic question, did some research but wanted to ask nutshells here.


Leiningen and Clojure CLI (with community add-ons) are general Repl / project / build tools for Clojure and ClojureScript Figwheel-main (replacing figwheel) and Shadow-cljs are specific tooling to work with ClojureScript (and use Leiningen or Clojure CLI) Figwheel-main and shadow-cljs take different approaches to managing JavaScript libraries, with Shadow-cljs deeply integrated into npm ecosystem. They serve different needs and have different learning curves, therefore it's unlikely one will replace the other.

🙏 1
👍 2

@U05254DQM thanks! a) you are from practicalli group I guess. can't see 'about' page in Whats about it? Its a free community movement? b) can figwheel and shadow cljs be used with clojure (not clojurescript)? would it make sense to just use one tool for all jobs? c) I heard theres clojure CLI and CLR or something (don't recall correct name). Whats the difference? one is closed source and one is open? d) well I wonder why people moved from figwheel to shadow. e) I also heard about light table but I am a vim user. Will see what can be done here.


Clojure cli is command line tool for clojure, clojure clr is a port of clojure to .net as the compile target.


At this point, I would suggest not to bother with Leiningen. It's a great dependency manager and build tool, but Clojure itself now comes with its own dependency manager and build tool, and you're best learning that. It's a bit confusing, but people will say Clojure CLI and they refer to what you might just think of as Clojure itself, that is when you type clj or clojure at the command line. Specifically the official Clojure dependency manager is called Tools.deps and the official build tool is called , but since both are included with Clojure you'll interact with them through the standard Clojure command-line, aka Clojure CLI, aka clj and clojure commands at the terminal. With this you can download and use all Java and Clojure libraries in your own projects, as well as setup build tasks like compilation, run tests, clean, generate doc, package, bundle, publish, etc. Now if you want to use ClojureScript, you can also do so using this, but Tools.deps cannot download and use NPM JavaScript libraries. But it can download and use ClojureScript libraries and any JavaScript libraries published to Clojars for use by Clojurescript as well, which people call cljsjs libraries as seen here: The problem is that if you're doing anything with ClojureScript, it's highly likely you'd want to use a JS library from NPM. Now it turns out Clojurescript can use NPM JS libraries, but sometimes it's a little complicated and requiring certain things depending on what type of JS lib the library is can get a bit tricky. This is where shadow-cljs comes in. It makes the process of using NPM libs a lot simpler. That means though you'll be specifying which NPM lib you want using Shadow-cljs and not Tools.deps, and you'll then have to use Shadow-cljs to perform all Clojurescript related build tasks like compilation and bundling. Now in Clojurescript you'll also probably want in-browser hot-reload, because it's really awesome. That's where Figwheel-main comes in. As a convenience, Figwheel-main also offers a layer on top of Clojurescript itself to make building and compiling and starting a REPL with hot-reload easier. So you'll use it to declare Clojurescript specific build tasks, but you won't use it for dependencies, you'd still use Tools.deps and NPM directly. Shadow-cljs also offers a hot-reload feature, so if you're already using Shadow-cljs for your dependencies and build you don't need Figwheel-main.


So basically I would say, if you want to do Clojure, don't bother with lein, just use what comes with Clojure already, that is, Tools.deps and which you operate through the Clojure CLI clj and clojure commands. If you want to do Clojurescript and use NPM libs, you have two options: 1. Use Tools.deps and Fighwheel-main together. 2. Or use Shadow-cljs


@U0K064KQV I see. that was very informative and clear. I guess no need for lein then. For clojure you also mean or it will involve deps.edn I guess along with tools.deps. I will have to read this. For clojurescript I will go with shadow-cljs


deps.edn is the filename of the config file that is used by Tools.deps


Is there a vim based thing that does "inline evaluation" like lighttable?


@U04V4KLKC @U11EL3P9U This is wonderful. I guess these do not do "inline evaluation" like the light table does?


Yup, Conjure does (can't speak for Fireplace).


I guess its on the right side separated. Not like light table but I wonder until I use it


It's all in the docs 🙂


Oh wonderful. It does do like lighttable


Thank you! 🙂 any other plugin you use?


Great if you send me your favourite ones


ok. checking


If you are interested in Conjure (I would encourage evaluating fireplace too, and make your own decision), then there is #conjure and also on discord (


@U11EL3P9U thank you! I guess the plugs you use for clojure specifically are • Plug 'Olical/conjure', {'branch': 'develop', 'for': ['clojure', 'fennel']} • Plug 'clojure-vim/clojure.vim', {'for': ['clojure', 'fennel']} • Plug 'guns/vim-sexp', {'for': ['clojure', 'fennel']} • Plug 'tpope/vim-sexp-mappings-for-regular-people', {'for': ['clojure', 'fennel']} • Plug 'guns/vim-clojure-highlight', {'for': ['clojure', 'fennel']} Ignoring coc as I do not use it


@U11EL3P9U Did you found discord more beneficial than slack? (I am just new at both)


There's also vim-iced but not sure if it does inline eval

quan xing10:05:15

How can I generate dynamic columns for insert / update sql , Which lib can I use.? like this means:

insert into t1  if need col1 then col1, if need col2 then col2 values  (if need col1 then col1_val, if need col2 then col2_val).

Ben Sless10:05:45

#honeysql is probably the library you're looking for


Hi, everyone Why am I getting this exception :

class clojure.lang.Keyword cannot be cast to class java.util.Map$Entry
on this piece of code :
(def a [["Active" :Transit-RLC "Active"]])

(->> a

       (comp (map drop-last)
             (map reverse))
       conj []
     (into {}))

Ben Sless14:05:43

What comes out without the final into {}?


[(:Transit-RLC "Active")]

Bob B21:05:38

the most pertinent answer is that conj'ing onto a map takes 2-element vectors as map entries (and not seqs) - the slightly deeper detail is (I believe) that conj'ing onto a map takes a Map.Entry or a 2-element vector or a seq of Map.Entry objects - since (:Transit-RLC "Active") is a seq, clojure tried to treat the keyword as a Map.Entry, and there's the class cast exception originally mentioned


Thanks, @U013JFLRFS8 Yeah you're right. Changing the (map drop-last) to (map #(-> [(second %) (first %)])) and removing the (map reverse) fixed the issue ... Isn't it a little weird ? Should I file it somewhere?

Ben Sless08:05:11

Maybe not an issue, but you should at least post in ask.clojure


hello, how can i format the string “Wed Aug 19 23:06:10 +0000 2020” to “2020-08-19 23-06-10" in clojure

Martin Půda17:05:23

    "Wed Aug 19 23:06:10 +0000 2020"
    (DateTimeFormatter/ofPattern "EEE MMM dd HH:mm:ss xxxx yyyy" (Locale. "US")))
  (DateTimeFormatter/ofPattern "yyyy-MM-dd HH-mm-ss" (Locale. "US")))


@U01RL1YV4P7 hello, how to convert this string to timestamp?

Martin Půda06:05:11

@UCD54AV63 Do you mean java.sql.Timestamp? Note that this class is obsolete and you should use Instant from java.time.

Martin Půda06:05:37

(->> "2020-08-19 23-06-10"
     (.parse (SimpleDateFormat. "yyyy-MM-dd hh-mm-ss"))


no, just this, 2022-05-10 12:21:41 convert to 1652156501


i use clojure java-time, i know

(.toEpochMilli (java-time/instant))
  (.getEpochSecond (java-time/instant))
this could, but i don’t how to convert localdatetime -> insant

Martin Půda06:05:53

(-> "2022-05-10 12:21:41"
    (LocalDate/parse (DateTimeFormatter/ofPattern "yyyy-MM-dd hh:mm:ss"))
    (.toEpochSecond LocalTime/MIN ZoneOffset/MIN))

Martin Půda07:05:30

@UCD54AV63 But results are different- maybe post this question into new thread, so more people can look at it.


thanks, i wll

Anders Eknert20:05:23

Hey everyone! Total noob question here, but if I have a list of arbitrary nested lists and/or vectors, like:

((1 2 3) ((("a" "b") ([1] ("foo" "bar"))) [10 20])
And from this would want to create a sequence of lists/vectors (original type not important here) of the lists containing something which is not another list/vector:
((1 2 3) ("a" "b") (1) ("foo" "bar") (10 20))
What would be the most straightforward way to accomplish that?

Anders Eknert20:05:21

Thanks @U0NCTKEV8! I did encounter that in my search, but probably failed to use it properly. Given the input provided above, what would a call to produce my desired result look like?


Tree-seq to pull everything apart, filter to remove single elements and collections of collections


Something to keep in mind, if you are generating the sequence, usually as you generate it you have exactly the information you need to remove the nesting you want to remove, while keeping what you want


(that information is usually at least implicit in the callstack when generating)


If you restructure after generating it is more of a pain because you have to try and recover that information


(same as using flatten)

Anders Eknert20:05:30

the nesting is created by calling a function recursively — there’s probably a more elegant solution where that is avoided to begin with, but I’d be fine with simply dealing with the mess of the result after the fact at this point

Anders Eknert20:05:06

still not sure what two functions I’d provide to tree-seq to have it flatten that structure like I want it to


Use for in a pattern like (fn f [...] (for [x ... i (f ...)] i))


The i iterating over the result of the recursive call acts like concat


Something like (tree-seq coll? seq ...)

Anders Eknert21:05:39

Thanks! Bedtime here but I’ll take a closer look tomorrow. Appreciate your support :thumbsup:

Martin Půda07:05:49

(->> '((1 2 3) ((("a" "b") ([1] ("foo" "bar"))) [10 20]))
     (tree-seq coll? identity)
     (filter #(and (coll? %)
                   (every? (complement coll?) %))))

=> ((1 2 3) ("a" "b") [1] ("foo" "bar") [10 20])

Martin Půda08:05:36

Can you also post the source code of function that produces this result? What were you trying to achieve?