Search code examples
clojureclojurescriptleiningenshadow-cljsdeps-edn

How to avoid duplication of dependency declaration in a Clojure/ClojureScript project?


I have been using Clojure, ClojureScript, lein, shadow-cljs, re-frame, reagent, Emacs, and CIDER to work on a Clojure/ClojureScript dynamic web app project.

Currently, dependencies are being declared on project.clj, on shadow-cljs.edn, and on deps.edn.

0 - I would like to ditch deps.edn

1 - I would like to avoid Boot and optimize for lein

2 - I would like to avoid duplication of dependency declaration. Ideally, I would like to have the dependencies all declared just in one file, maybe with a pointer in the other! If not possible in just one file, use two - without deps.edn.

(i) - Dependencies on project.clj:

  :dependencies
  [[org.clojure/clojure        "1.11.1"]
   [org.clojure/tools.logging  "1.2.4"]
   [org.clojure/clojurescript  "1.11.60"]
   [reagent                    "0.10.0"]
   [re-frame                   "0.12.0"]
   [garden                     "1.3.10"]
   [metosin/malli              "0.8.4"]
   [metasoarous/oz             "1.6.0-alpha35"]

   [hiccup                      "1.0.5"]] ; html parsing and manipulation

(ii) - Dependencies on shadow-cljs.edn:

 :dependencies
 [[reagent "1.1.0"]
  [re-frame "1.2.0"]
  [day8.re-frame/tracing "0.6.2"]
  [garden "1.3.10"]
  [metosin/malli "0.8.3"]

  [binaryage/devtools "1.0.3"]
  [day8.re-frame/re-frame-10x "1.1.11"]]

(iii) - Dependencies on deps.edn:


{:deps
 {org.clojure/clojure {:mvn/version "1.10.3"},
  reagent {:mvn/version "0.10.0"},
  org.clojure/tools.logging {:mvn/version "1.1.0"},
  org.clojure/clojurescript {:mvn/version "1.10.866"}, 
  ring {:mvn/version "1.9.0"}, 
  garden {:mvn/version "1.3.10"}, 
  metosin/malli {:mvn/version "0.5.1"}, 
  hiccup {:mvn/version "1.0.5"}, 
  metasoarous/oz {:mvn/version "1.6.0-alpha35"}, 
  re-frame {:mvn/version "0.12.0"}}

 :source-paths ["src" "test"]}

How would you do it?


Solution

  • Generally I do recommend keeping your CLJS dependencies in shadow-cljs.edn and your CLJ dependencies in project.clj. It avoids a couple pitfalls and footguns. It is fine to keep everything in project.clj though, just need to be careful to avoid some mistakes.

    You change your shadow-cljs.edn to add :lein true but remove :dependencies and :source-paths completely. You then add all the :dependencies that aren't already in project.clj and in addition add thheller/shadow-cljs (latest version "2.20.10"). Thats it.

    When doing this you must make sure not to introduce dependency conflicts in the future. So, a common problem is trying to update shadow-cljs but keeping an older clojurescript version, or vice versa. The problem of doing this is that shadow-cljs will inherit all the CLJ dependencies of your CLJ side, which may or may not cause conflicts/problems when trying to run shadow-cljs. These are all solveable problems, but problems you need to solve since shadow-cljs no longer can. It only can when dependencies are managed via shadow-cljs.edn.

    You may also opt to move the CLJS dependencies into a lein alias if you want. You then change the shadow-cljs.edn to :lein {:aliases [:cljs]} (or whatever alias you choose).