What are the Clojure Tools?
The Clojure Tools
are a group of convenience tools which currently consist of:
Clojure CLI
tools.build
The Clojure Tools
.
were designed to answer some of the following questions:
- How do I install Clojure? (
Clojure CLI
) - How do I run a Clojure program? (
Clojure CLI
) - How do I manage Clojure packages (dependencies)? (
Clojure CLI
) - How do I configure a Clojure project? (
Clojure CLI
) - How do I build Clojure for production? (
tools.build
)
The rest of this post will dig into each of these tools.
Clojure CLI
The Clojure CLI
is a CLI program. Here is what it looks like to use the
Clojure CLI
and some of the things it can do:
Run a Clojure repl
clj
Run a Clojure program
clj -M -m your-clojure-program
manage Clojure dependencies
clj -Sdeps '{:deps {bidi/bidi {:mvn/version "2.1.6"}}}'
Like all Clojure
programs, the Clojure CLI
is built on a few libraries:
- clj/clojure - a bash script
- tools.deps a clojure library (commonly referred to as
deps
) - deps.edn - an edn file with a specific structure
The following sections will provide overviews of each of the above tools.
The Clojure CLI
is invoked by calling either clj
or clojure
shell commands:
# clj
clj -M -m your-clojure-program
# clojure
clojure -M -m your-clojure-program
Under the hood, clj
actually calls clojure
. The difference is that clj
wraps the clojure
command with a tool called rlwrap. rlwrap
improves the developer experience by making it easier for you, a human, to type
in the terminal while you're running your Clojure REPL. However, even though
it's easier for you to type, rlwrap
can make it hard to compose the clj
command with other tools. As a result, it's a common practice to use clojure
in production/ci environments .
Additionally, not all environments have access to rlwrap
so it's another
dependency you have to install.
Okay, so they do the same thing. What do they do? clj/clojure
has one job:
run Clojure programs against a classpath.
The next sections will outline the tools that make up the Clojure CLI
tool.
clj/clojure
If you dig into the clj/clojure
is just a bash script which ultimatley calls
a command like this:
java [java-opt*] -cp classpath clojure.main [init-opt*] [main-opt] [arg*]
Thus, the Clojure CLI
tool makes it easier to run Clojure programs. It saves
you having to type out a gnarly Java
command and make it work on different
environments (windows, linux, mac etc). However, it orchestrates the building
of the classpath by calling out to tools.deps
.
tools.deps
tools.deps
is a Clojure libary responsible for managing your dependencies.
It does the following things:
- reads in dependencies from a
deps.edn
file - resolves the dependencies and their transitive dependencies
- builds a classpath
What's interesting about this program is that it's just a Clojure library.
This means that you can use it outside of the Clojure CLI
.
The other thing that makes tools.deps
great is that it's a small and
focused library. Why this is great is that if something goes wrong it's easy
to read and learn the library in a short period of time.
deps.edn
deps.edn
is just an edn file where you configure your project and specify
project dependencies. You can think of it like Clojure's version of
package.json
. The deps.edn
file is a Clojure map
with a specific structure. Here's an example of some of the properties of
a deps.edn
file:
{:deps {...}
:paths [...]
:aliases {...}}
As you can see, we use the keywords :deps
, :paths
and :aliases
and more
to start to describe your project and the dependencies it requires.
As we noted above, deps.edn
is read in when you run clj/clojure
and tells clj/clojure
which dependencies are requires to run your project.
Tools.Build
tools.build
is a Clojure library with functions for building clojure projects.
For example, build a jar
or uberjar
.
The way you would use tools.build
is by writing a separate program inside
your app which knows how to build your app. The convention is to create a
build.clj
file in the root of your project. Import tools.build
and use
the functions provides by tools.build
to build your program.
The 3 main types of Clojure programs one might build into 3 sub categories:
- A
tool
- A
library
- An
app
When you run your build.clj
file, you will use Clojure CLI
's -T
switch.
The -T
switch is meant to run general clojure programs via the Clojure CLI
and since build.clj
is a separate program, distinct form the app you are
writing, you would run it via the -T
switch.
You would use -T
for Clojure programs that you want to run as a "tool". For
example, deps-new is a Clojure library which creates new Clojure projects
based on a template you provide. This is a great example of a Clojure project
which is built to be a "tool".
I don't want to go into more detail about -T
now because that means we would
have to dive into other Clojure CLI
switches like -X
and -M
. That's for
another post. On to the Installer!
Installer
The "Clojure CLI Installer" is a fancy way of referring to the brew tap
used
to install Clojure on mac and linux machines. As of February 2020, Clojure
started maintaining their own brew tap. Thus, if you installed the
Clojure CLI
via
brew install clojure
you will likely want to uninstall clojure
and install the following:
brew install clojure/tools/clojure
In all likelihood, you would probably be fine with brew install clojure
as it
will recieve updates. However, while brew install clojure
will still see some
love, it won't be as active as the clojure/tools/clojure
tap.
clj v lein v boot
This section will provide a quick comparison of clj
, lein
and boot
.
Firstly, all of the above tools are more or less addressing the same problems in their own way. Your job is to choose the one you like best.
If you're curious which to choose, my answer is the Clojure CLI
.
The reason I like the Clojure CLI
is because the tool is simple.
You can read through clj
and tools.deps
in an afternoon and understand
what they are doing. The same (subjectively of course) cannot be
said for lein
or boot
. I will note that Clojure CLI
's API is not
straightforward and can be confusing.
Secondly, the Clojure Tools
promote libraries over frameworks. This is
important when working with a language like Clojure because it really does
reward you for breaking down your thinking.
Finally, the Clojure community is really leaning into
building tools for Clojure CLI
. For example, where lein
used to have significantly
more functionality, the community has built a ton of incredible tools that
will cover many of your essential requirements.