Circumnavigating Watch and AOT Compilation Limitations - boot-clj/boot GitHub Wiki
The problem: When one wants to have an executable recompiled each time a source file is changed, the waiting required is practically immeasurable. AOT is the culprit and can be reduced to interfering with one's life by the folliwing means. The jist is to create a shim that acts as an entry point to your application.
The structure (upon completion):
├── build.boot
├── src
│ ├── clj
│ │ └── foo
│ │ ├── core.clj <-- where -main is located
│ │ ├── bar.clj <-- a source file referenced in core.cljs
│ │ └── main.clj <-- the shim (entry point) of the app
│ └── cljc
│ └── foo
│ ├── schema.cljc
│ └── utils.cljc
└── target
└── project.jar
First, include the src
directories in resource-paths
within build.boot:
(set-env!
:resource-paths #{"src/cljc" "src/clj"}
...)
core.clj
looks something like the following (and notice :gen-class
is not present, as it goes in main.clj
):
(ns foo.core
(:require [clojure.tools.cli :as cli]
[foo.bar :refer [quux]]))
(defn -main [& argv]
...)
And main.clj
:
(ns foo.main
(:gen-class))
(defn -main [& args]
(require 'foo.core)
(apply (resolve 'foo.core/-main) args))
The time consuming problem with building is aot if it is applied to the whole source tree. With the method just described, the aot task can only be applied to main.clj
. More from build.boot:
(task-options!
aot {:namespace '#{foo.main}} ;; the only namespace touched
jar {:main 'foo.main} ;; the entry point
)
Now, from the command line boot aot uber jar target
builds the project. To leave only project.jar in the target
directory, add sift: boot aot uber jar sift --include '\.jar$' target
.
Or fashion a boot task:
(deftask bundle []
(task-options!
sift {:include #{#"\.jar$"}})
(comp (aot) (uber) (jar) (sift) (target)))
(deftask dev []
(comp (watch) (repl) (bundle)))
The latter task enables recompilation if a file is changed in the source directories.