How can I conditionally load functionality in a clojure web-app

六眼飞鱼酱① 提交于 2019-12-12 06:17:15

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!