问题
I have a clojure web app (standard ring handlers and compojure routes on a jetty server) for which I enabled live asset recompilation as middleware, which has been very very handy in development. As we get closer to production I would like to find a way not to load that code in production and instead read the pre-compiled assets (which I am able to generate as a lein task).
Currently the asset compilation machinery lives in the project code - it can be loaded from the lein task using eval-in-project, so I am able to reuse the same code in both places. However this means that the un-needed files are compiled and included in the production app.
The other issue is that there is one asset compilation tool I'm using that causes the app to fail to load at initialisation time if uberjar'ed since it makes use of native bindings to v8, which are not available (and not needed) when the precompiled assets are available.
How can I avoid loading this code in a production uberjar, but still benefit from dynamic re-compilation at run-time during development and testing?
回答1:
Your :source-paths
key in Leiningen decides which directories are checked for Clojure source code. With per-environment settings of :source-paths
you can prevent unwanted namespaces from being included in your depoloyed uberjar.
The next piece of the puzzle is to ensure your code does not rely on the dev code on the production instance. This can be done with the help of the environ lib.
; excerpt of project.clj
(defproject your-org/your-project "version"
:source-paths ["src"] ; the main source location
:profiles {:dev {:source-paths ["dev-src"] ; added directory
:env {:dev "true"}}}
...)
; excerpt of project code for src/your_org/your_project.clj
(ns your-org.your-project
(:require environ.core :refer [env]))
(def maybe-launch-optional-thing
(if (= (env :dev) "true") ; checking a profile specific value
(do (require 'dev-only-dep.core)
(resolve 'dev-only-dep/launch))
(constantly nil))
...
(defn -main
[& args]
(maybe-launch-optional-thing)
...)
The if
wrapped require
, and the usage of resolve
, ensure that this code is valid whether dev-only-dep.core
is an available or not. maybe-launch-optional-thing
is bound to the appropriate function in the optional namespace under a :dev
profile, and is otherwise a no-op.
来源:https://stackoverflow.com/questions/29451457/how-can-i-conditionally-load-functionality-in-a-clojure-web-app