(compile 'my.namespace) ;; writes .class files to *compile-path*
Did you know:
Most libraries are distributed as source and you compile them over and over
You can compile namespaces explicitly using compile
Namespace compilation is transitive
compile
writes these files to disk and require
will use them
You can use compile
on the namespace you load when you start development, or on your user.clj
, or on the main namespace you run as a server to improve your startup time
The compile
function takes a namespace symbol and compiles that namespace and all the namespaces it requires into *compile-path*
(which defaults to classes
). That directory must exist and be on your classpath:
(compile 'my.namespace) ;; writes .class files to *compile-path*
Subsequently, when any of those compiled namespaces are required, the class file will be loaded, rather than the original .clj
file. If a source file is updated (and thus newer), it will be loaded instead. Periodically, you will need to re-compile to account for new dependencies or changing code.
One special case is the user.clj
file loaded automatically by the Clojure runtime, before any other code is loaded. If you are using a user.clj
in dev, you need to force a reload because it has already been loaded automatically:
(binding [*compile-files* true] (require 'user :reload-all))
That’s it! This technique can substantially reduce your startup time during development, particularly as the number of dependencies you load increases.
In a deps.edn project, you should create a development alias (like :dev
) that includes the classes
directory:
{:deps { ... }
:aliases
{:dev {:extra-paths ["classes"]}}}
You will also need to ensure the classes
directory exists. It may be useful to include the empty classes
directory as part of your version controlled project structure (make sure to ignore and NOT include the compiled .class files).
You can then start your REPL with the alias and compile
to populate your classes
directory and start seeing the benefits:
$ clj -A:dev
Clojure 1.10.1
user=> (compile 'my.namespace)
If you want to use an automatically loaded user.clj, you should incorporate that into your dev alias by adding a source path dev
:
{:deps { ... }
:aliases
{:dev {:extra-paths ["dev" "classes"]}}}
And then create dev/user.clj
:
(ns user
(:require ... ))
;; dev-only functions, etc
Remember to use the modified compilation process for user.clj:
$ clj -A:dev
Clojure 1.10.1
user=> (binding [*compile-files* true] (require 'user :reload-all))
Original author: Alex Miller