User Guide
Clojurephant (GitHub Repo) is a Gradle plugin providing support for Clojure and ClojureScript projects.
clojurephant should not be considered stable before v1.0. Until then, minor versions will often contain breaking changes. |
Rationale
Gradle is a popular build tool in the JVM ecosysytem with a rich plugin ecosystem and support for polyglot projects.
In particular, if you have a need to interop with Java code (maybe even other JVM languages), Gradle provides a good base of support.
Features
Gradle
Features provided by Gradle (or its ecosystem) that are useful for Clojure programmers.
-
Packaging into ZIPs, JARs, or Uberjars (via the third-party Shadow plugin)
-
Multi-project builds
-
Publishing to Maven repositories (such as Clojars or Maven Central)
Clojure/ClojureScript
Unique features provided by Clojurephant.
-
Running clojure.test tests with Gradle’s out-of-box
Test
task (via the jovial Junit Platform Engine) -
Clojure AOT compilation
-
ClojureScript compilation (supporting multiple builds)
-
Running an nREPL server (supporting custom middleware or handlers)
ClojureScript features, in particular, are not fully settled and may change before 1.0. |
Release Notes
See the GitHub releases for the changelog of each version.
Quick Start
Look at our sample projects:
If the samples or our documentation doesn’t answer your questions, please ask in Clojurephant Discussions.
Plugins
clojurephant uses the common Gradle pattern of providing capability plugins and convention plugins. Capability plugins provide the basic machinery for using the language, but leaves it to you to configure. Convention plugins provide configuration on top of the capabilities to support common use cases.
Convention | Capability |
---|---|
|
|
|
|
dev.clojurephant.clojure-base
-
Applies
java-base
, which lets you configure source sets. Each source set will get:-
A Java compilation task
-
Configurations for compile (
implementation
,compileOnly
) and runtime (runtimeOnly
) dependencies
-
-
Adds a
clojure
extension which allows you to configure builds of your Clojure code.-
A build is added for each source set (with the same name as that source set)
-
Additional builds can be configured by the user
-
Each build gets a
check<Build>Clojure
task that can be used to ensure namespaces compile, and optionally warn or fail on reflection. (by default no namespaces are compiled) -
Each build gets a
compile<Build>Clojure
task that can be used for AOT compilation. (by default no namespaces are AOTd) -
If any namespaces are configured to be AOTed for the source sets build, the source sets output will be the AOTd classes. Otherwise, the Clojure source will be the output (i.e. what would get included in a JAR)
-
gradlew tasks --all shows all these created tasks. Beware: The main build is somewhat special and its name is not included in the task names so it has e.g. compileClojure .
|
Clojure Builds
You can define a custom build:
clojure {
builds {
// Defaults noted here are for custom builds, the convention plugin configures the builds it adds differently
mybuild {
sourceSet = sourceSets.mystuff // no default
// Configuration of the check<Build>Clojure task
reflection = 'fail' // defaults to 'silent', can also be 'warn'
checkNamespaces = ['my.core', 'my.base'] // defaults to no namespaces checked
checkNamespaces.add('my-core') // just add a single namespace
checkAll() // checks any namespaces found in the source set
// Configuration of the compile<Build>Clojure task
compiler {
disableLocalsClearing = true // defaults to false
elideMeta = ['doc', 'file'] // defaults to empty list
directLinking = true // defaults to false
}
aotNamespaces = ['my.core', 'my.base'] // defaults to no namespaces aoted
aotNamespaces.add('my-core') // just add a single namespace
aotAll() // aots any namespaces found in the source set
}
}
}
You can also modify the configuration of the auto-added builds, f.ex. the "main" one:
clojure { builds { main { reflection = 'warn' } } }
dev.clojurephant.clojure
-
Applies the
dev.clojurephant.clojure-base
plugin (see above) -
Applies the
java
plugin:-
Creates a main source set, whose output is packaged into a JAR via the
jar
task. -
Creates a test source set, which extends the main source set.
-
Creates a
test
task that runs tests within the test source set.
-
-
Applies the internal
ClojureCommonPlugin
which:-
Creates a dev source set, to be used for REPL development, which extends the test source set.
-
Adds 'nrepl:nrepl' as a dependency of that source set.
-
Adds a
clojureRepl
task which will start an nREPL server. -
Configures dependency rules to indicate that:
-
org.clojure:tools.nrepl
is replaced bynrepl:nrepl
-
If you are using a Java 9+ JVM, any
org.clojure:java.classpath
dependency must be bumped to at least 1.0.0 to support the new classloader hierarchy.
-
-
-
Configures the
main
Clojure build tocheckAll()
namespaces. -
Configures any build whose name includes
test
to:-
aotAll()
namespaces (required for the current JUnit4 integration)
-
-
Configures the
dev
Clojure build tocheckNamespaces = ['user']
(if you have a user namespace). This ensures that your REPL will start successfully.
dev.clojurephant.clojurescript-base
-
Applies
java-base
, which lets you configure source sets. Each source set will get:-
A Java compilation task
-
Configurations for compile (
implementation
,compileOnly
) and runtime (runtimeOnly
) dependencies
-
-
Adds a
clojurescript
extension which allows you to configure builds of your ClojureScript code.-
A build is added for each source set (with the same name as that source set)
-
Additional builds can be configured by the user
-
Each build gets a
compile<Build>ClojureScript
task that can be used for compilation. (by default no compiler options are set) -
If
outputTo
is configured (either the top level one or for a module) for the source sets build, the source sets output will be the compiled JS. Otherwise, the ClojureScript source will be the output (i.e. what would get included in a JAR).
-
ClojureScript Builds
See ClojureScript compiler options for details on what each option does and defaults to.
clojurescript {
builds {
// Defaults noted here are for custom builds, the convention plugin configures the builds it adds differently
mybuild {
sourceSet = sourceSets.mystuff // no default
// Configuration of the compile<Build>ClojureScript task (defaults match what is defaulted in the ClojureScript compile options)
compiler {
outputTo = 'public/some/file/path.js' // path is relative to the task's destinationDir
outputDir = 'public/some/path' // path is relative to the task's destinationDir
optimizations = 'advanced'
main = 'foo.bar'
assetPath = 'public/some/path'
sourceMap = 'public/some/file/path.js.map' // path is relative to the task's destinationDir
verbose = true
prettyPrint = false
target = 'nodejs'
// foreignLibs
externs = ['jquery-externs.js']
// modules
// stableNames
preloads = ['foo.dev']
npmDeps = ['lodash': '4.17.4']
installDeps = true
checkedArrays = 'warn'
}
}
}
}
dev.clojurephant.clojurescript
-
Applies the
dev.clojurephant.clojurescript-base
plugin (see above) -
Applies the
java
plugin:-
Creates a main source set, whose output is packaged into a JAR via the
jar
task. -
Creates a test source set, which extends the main source set.
-
Creates a
test
task that runs tests within the test source set.
-
-
Applies the internal
ClojureCommonPlugin
which:-
Creates a dev source set, to be used for REPL development, which extends the test source set.
-
Adds 'nrepl:nrepl' as a dependency of that source set.
-
Adds a
clojureRepl
task which will start an nREPL server. -
Configures dependency rules to indicate that:
-
org.clojure:tools.nrepl
is replaced bynrepl:nrepl
-
If you are using a Java 9+ JVM, any
org.clojure:java.classpath
dependency must be bumped to at least 1.0.0 to support the new classloader hierarchy.
-
-
-
Wires your ClojureScript build configuration into the nREPL for use by Figwheel.
-
Configures the REPL for Piggieback:
-
Adds a dev dependency
cider:piggieback
-
Adds the Piggieback middleware:
cider.piggieback/wrap-cljs-repl
-
Project Layout
<project>/ src/ main/ clojure/ sample_clojure/ core.clj clojurescript/ sample_clojure/ main.cljs test/ clojure/ sample_clojure/ core_test.clj clojurescript/ sample_clojure/ main_test.cljs // right now we don't support cljs.test dev/ clojure/ user.clj clojurescript/ user.cljs gradle/ wrapper/ gradle-wrapper.jar gradle-wrapper.properties build.gradle gradlew gradlew.bat
Task Configuration
ClojureNRepl
clojureRepl {
port = 55555 // defaults to a random open port (which will be written to a .nrepl-port file)
// handler and middleware are both optional, but don't provide both
handler = 'cider.nrepl/cider-nrepl-handler' // fully-qualified name of function
middleware = ['my.stuff/wrap-stuff'] // list of fully-qualified middleware function names (override any existing)
middleware 'dev/my-middleware', 'dev/my-other-middleware' // one or more full-qualified middleware function names (append to any existing)
// clojureRepl provides fork options to customize the Java process for compilation
forkOptions {
memoryMaximumSize = '2048m'
jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005', '-Djava.awt.headless=true']
}
}
The ClojureNRepl
task also supports command-line options for some of it’s parameters. Multiple middleware
must be specified as separate options.
./gradlew clojureRepl --port=1234 --handler=cider.nrepl/cider-nrepl-handler ./gradlew clojureRepl --port=4321 --middleware=dev/my-middleware --middleware=dev/my-other-middleware
check or compile tasks
Always configure compiler options and reflection settings via the clojure
or clojurescript
extensions. These options may be immutable on the tasks at some point in the future.
The only settings you should configure directly on the tasks are the forkOptions, if you need to customize the JVM that is used.
checkClojure {
// to customize the Java process for compilation
forkOptions {
memoryMaximumSize = '2048m'
jvmArgs = ['-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005', '-Djava.awt.headless=true']
}
}