How does shadow-cljs handle duplicates of the same dependency with difference versions on the shadow-cljs.edn file? - clojure

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.
In my shadow-cljs.edn, I have:
{:source-paths ["src" "dev"]
:dependencies [[testdouble/clojurescript.csv "0.5.2-LOCAL-FORK"]
[testdouble/clojurescript.csv "0.5.1"]]
.
.
.
As you see, there is a duplicate of the same dependency being used two
times.
How does shadow-cljs treat this?
Are both dependencies compiled? One over the other?
Just the latest one or the last one to be displayed on the file?

A library can only be added once, due to how the classpath works. In case of :dependencies in shadow-cljs.edn it'll pick the first one found.
But really you shouldn't ever use two versions of the same lib. It may have unexpected results and should be avoided. In fact I'm a little surprised that doesn't already throw an error.

Related

Configuring Clojurescript project for garden & hiccup compiled output

How to configure project.clj file to configure it to output html & css files from hiccup & garden on compiling, so that i can deploy to server without any dynamic css/html loading on client side ?
If you don't really need to use Leiningen, using Boot you can do it easily with perun.io, especially if website is the primary objective:
https://perun.io/guides/getting-started/
https://github.com/hashobject/perun.
I rewrote my website that way https://github.com/ArchieT/website-archiet.
If there is a need to use Lein, maybe I'll look at it later as I don't have much time right now.
It should not be hard to do.
You can use the lein-garden leiningen plugin: https://github.com/noprompt/lein-garden.
Here's an example config.
(defproject cash-money "1.1.1"
:plugins [[lein-garden "X.X.X"]]
:garden {:builds [{;; Optional name of the build:
:id "screen"
;; Source paths where the stylesheet source code is
:source-paths ["src/styles"]
;; The var containing your stylesheet:
:stylesheet cash-money.core/screen
;; Compiler flags passed to `garden.core/css`:
:compiler {;; Where to save the file:
:output-to "resources/screen.css"
;; Compress the output?
:pretty-print? false}}]})
Then you can run lein garden auto to watch for changes and automatically recompile.
If you want an example of a codebase using this: https://github.com/Dexterminator/spotify-data-extrapolator/tree/db8d6e16529940272409598c8ac0fdbbaf739646
To help you find stuff like this in the future, I'll describe a process for discovery.
I found this by going to the garden github repository (https://github.com/noprompt/garden) and looking through the code for a bit of text that looked like it would be unique to garden so that I could search all of github and find other repositories that used garden. The bit of text I chose was defpseudoelement. I scanned the projects that were already using garden and found one that mentioned running lein garden auto in the readme. Searching again for lein garden auto took me to the lein-garden leiningen plugin. In hindsight, it would probably make more sense to see what other libraries the author of garden has written. That would have taken us directly to the plugin. C'est la vie.

How do I add a library to LightTable so that when I use instarepl it will always have said library?

I'd like to add certain library dependencies to LightTable as a whole so that when I am messing around learning new stuff, I don't have to create a new project as a whole.
Let's say I want to always have access to these libraries: math.combinatorics and math.numeric-tower.
Lighttable seems to be calling a repl from leinigen, so am I really needing to add something there?
See https://github.com/LightTable/LightTable/blob/master/project.clj
It will be calling a repl of Leiningen. Rather than adding the dependencies to LightTable you could add them to your Leiningen Profile (~/.lein/profiles.clj)
The file would probably look something like this with your dependencies:
{:user {:dependencies [[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]]}}
Generally this is not a very good idea. It will be a global thing and will probably cause you problems in the future. If you create an application you might find that these two libraries are available when they won't be for other people or on difference computers.
What would be a better option would be to create a new project using Leiningen. You can then edit your project.clj file to look something like this
(defproject math-thing "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.6.0"]
[math.combinatorics "x.x.x"]
[math.numeric-tower "x.x.x"]])
Then when editing your clj file LightTable uses your project.clj file to start instrepl and will resolve any needed dependencies.
Use the leiningen profile e.g. ~/.lein/profiles.clj and define a :injections [ ... ] node which performs the (require '[ ]) and import, refer-clojure and other items you have. I generally prefer to have at least Alembic present in my dev profile (wrapping Maven/Sonatype) so I can download, install in maven then classpath and project reload in one go using a macro/function wrapper around distill* to prevent a long load time due to too many libraries included in the user space. Pretty much this is the only function I usually want present in any REPL or LT InstaRepl and I put development and debugging snippets in project ./dev/user.clj to keep most of the messy stuff project specific.

Interfacing Clojure and Clojurescript

I would like to make my existing Clojure libraries usable from clojurescript as well as create new applications which run in both Clojure and Clojurescript.
I understand Clojure and Clojurescript have their differences, and that there are metaprogramming solutions such as cljx. But, I have limited my Clojure code to a compatible subset of Clojurescript and I would simply like to call clojure from clojurescript (and possibly vice-versa). I have seen this possible in libraries such as core.match, but I am unable to replicate what is done there.
I am currently getting No such namespace, I am not sure if it is because it is not possible, or because my namespacing or directory structure is wrong, or some other reason.
For concreteness, I have a directory structure of the form
src/
clj/
clopjys/
vector.clj
cljs/
cljdemo.cljs
I am trying to use vector.clj from within cljdemo.cljs, i.e:
(:require
[clophys.vector :refer [coords std-uniform-vector]])
My project.clj has the following entries
...
:source-paths ["src/clj"]
:cljsbuild {
:builds [{
; The path to the top-level ClojureScript source directory:
:source-paths ["src/cljs"]
...
You can't include clj code in cljs at runtime. The clj files will get included for the macros (which are defined in clj and is probably what you saw in core.match).
The best solution is cljx really, and if your code is actually compatible with clj and cljs then you will have a cljx file that will look exactly like a normal clj file. It is pretty simple and cool, try it out!
Since this question has been written, Clojure reader conditionals have appeared in the core language (whereas .cljx is a library).

Where to find valid version numbers for dependencies in Leiningen

I'm new to Clojure and Leiningen, and I've determined that some of what I'll want to use is located in clojure.contrib.generic.math-functions. I found API information for that at http://richhickey.github.com/clojure-contrib/branch-1.1.x/math-api.html, but I can't find anything that helps me figure out what I should put into my project.clj file for that dependency.
I have tried [clojure.contrib.generic.math-functions "1.1"], [clojure.contrib.generic.math-functions "1.1.x"], and [clojure.contrib.generic.math-functions "1.1.0"]. For each of those, I get something like...
...
Caused by: org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException: Missing:
----------
1) clojure.contrib.generic.math-functions:clojure.contrib.generic.math-functions:jar:1.1
All clojure-contrib namespaces are shipped within a single jar file, for which the dependency has to be listed like:
[org.clojure/clojure-contrib "1.2.0"]
Please note that there are different versions available of that artifact. The 1.2.0 is the current stable release.
In order to use functions coming from the math-functions namespace in your clojure code, you need to either require or use such namespace, usually done within the ns form at the beginning of your source file:
(ns my.namespace
(:use [clojure.contrib.generic.math-functions]))
Have a look here to see the differences between use and require.
The next version of Leiningen will have a search task for precisely this purpose. It will search Clojars, Maven Central, and any other repositories your project has listed, provided they offer up downloadable indices. It's already implemented, so if you run Leiningen from git you can use it.
Also, the Leiningen tutorial covers this. Type "lein help tutorial".
You can generally find what you need at clojars.org - it's the default repository for leiningen. The current stable release of Clojure is 1.2.0, so you'd have this in your leiningen project.clj:
[org.clojure/clojure "1.2.0"]
[org.clojure/clojure-contrib "1.2.0"]
To use the generic math functions in your clojure, require or use it in your namespace declaration at the top of your source file:
(ns your-namespace
(:use [clojure.contrib.generic.math-functions :as mathf]))
This allows you to refer to the functions in that namespace like this:
(mathf/abs -10) ;; => 10
:use-ing namespaces with :as is the preferred way to use functions from other namespaces in your code. require is ok, but you'd have to prefix your functions with the entire namespace (e.g. clojure.contrib.generic.math-functions/abs) so that's not practical. Using a namespace without :as allows you to use these functions without any prefix at all (e.g. abs), but you're more likely to get namespace clashes and it might be difficult to see where functions come from, especially if you :use many libraries.
You can browse all libraries available from the default leiningen repository by checking out http://clojars.org/repo/. The structure of clojure-contrib will change when 1.3.0 is out, so you'll have to include the specific contrib library if you're using version 1.3.0-alpha-xx:
[org.clojure.contrib/generic "1.3.0-alpha4"]
Now that the clojure.contrib has been broken up, the math functions are in something called math.numeric-tower. The lein dependency is specified like this:
[org.clojure/math.numeric-tower "0.0.1"]
You can use or require as seems appropriate, for example
(use '[clojure.math.numeric-tower])

How to use my own versions of Clojure libraries?

Say I made a change to a Clojure library (eg. added a parameter to the request-token in clj-oauth) and want to use that changed library in my project. What's the best way to do this, short of compiling the new library as a JAR and copying that to my project lib?
I want to be able to tweak the library and my project at the same time (preferably in the REPL). If I were doing this in Ruby, I would download and 'require' the gem, then reopen that class in my own project source and add or override the methods as needed.
You can hack directly at the REPL. Suppose you've got incanter on your classpath.
Start a REPL. The first thing we need to do is bring the incanter classes into it.
user> (require 'incanter.core)
nil
Now we can see the function incanter.core/matrix?
user> (incanter.core/matrix? 2)
false
We can look at the original source code:
user> (require 'clojure.repl)
nil
user> (clojure.repl/source incanter.core/matrix?)
(defn matrix?
" Test if obj is 'derived' incanter.Matrix."
([obj] (is-matrix obj)))
nil
Let's go and screw it up:
First change to the incanter.core namespace:
user> (in-ns 'incanter.core)
#<Namespace incanter.core>
Then we can redefine it, using the old source code as a crib:
incanter.core> (defn matrix? [obj] "hello")
#'incanter.core/matrix?
Unit test:
incanter.core> (matrix? 2)
"hello"
Switch back to the user namespace:
incanter.core> (in-ns 'user)
#<Namespace user>
Try it out:
user> (matrix? 2)
; Evaluation aborted.
There is no definition of user/matrix. We redefined it in the incanter.core namespace.
user> (incanter.core/matrix? 2)
"hello"
For experimenting at the repl, it's ok just to change source files and re-compile the single file (C-C C-k in emacs), or if you're in the right namespace, just re-evaluate the definition.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Now, if we want to make our valuable change permanent and available to other projects, it depends on how everything is set up.
I use maven for dependency management, so it would be a question of modifying the source file, and then re-running the build process for the library to compile the new version and install it into the local maven repository.
With a maven project, that should be as simple as
$ mvn install
A note about version numbers:
If you do make permanent modifications and use dependency management to coordinate the differences, then you should change the version number of your library, from maybe 1.2.0 to 1.2.0-johnshack-SNAPSHOT, or something that is unlikely to collide with the real thing when you want to use an unperverted version in another project. You wouldn't want a modified version finding its way into projects where it isn't welcome.
Then you modify your own project files to make sure that you use the hacked version where you want to, and the next time you start your repl, it should pull in the last hack that you installed.
You will need to reinstall again every time you want your changes to make their way into the repository, but that's actually probably a good thing.
Unfortunately, (and it was at this point that I started to wish that I had chosen a different example) Incanter turns out to be a leiningen project which is split into sub-modules in an ad-hoc scripty sort of way, so we need to figure out how it expects to be installed. The figuring out turned out to be quite hard, although the answer is easy. Leiningen sets my hair on fire.
You can get incanter's source here:
$ git clone http://github.com/liebke/incanter.git
and the relevant source file is:
~/incanter/modules/incanter-core/src/incanter/core.clj
Modify it to break the matrix? function, and then it turns out that what you have to do is:
Change the version numbers in both the top level project.clj, and also in the submodule project.clj.
Then you run lein install in the incanter-core directory, and then again in the top-level directory, and you have to do it in that order. I don't quite understand why.
At the moment all this seems needlessly complicated. I'm (fairly) sure that it will settle down as the tools mature.
If you're using (or wouldn't mind using) cake, check out the subproject dependencies section of the README. I think it might be exactly what you're looking for.
You upload it to clojars under a different name depend on that.