Skip to content

Instantly share code, notes, and snippets.

@joinr
Last active June 20, 2019 22:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joinr/6ff4a9ad39f8c730621a7aee81178b0f to your computer and use it in GitHub Desktop.
Save joinr/6ff4a9ad39f8c730621a7aee81178b0f to your computer and use it in GitHub Desktop.
example of a main shim namespace for clojure to avoid AOT'ing everything and allow fast starts
;;Shim class for running app without
;;aot compilation issues.
;;entrypoint for some gui.
(ns blah.main
(:gen-class :main true))
;;This is the main entry point for the app.
;;It's a good example of a shim-class, and
;;requires some arcane features to get things
;;working to avoid aot compilation of dependent
;;namespaces, and to load them at runtime.
(defn -main [& args]
;;clojure.set isn't imported by default, causing errors when
;;aot-compiling in some places.
(require 'clojure.set)
;;if we don't use this, i.e. establish a root binding
;;for the *ns* var, we can't use in-ns later....
;;which leads to compile-time and run-time errors..
;;[optional]
;;I like to use splash screens for gui stuff; e.g. splasher is a dependency. You can elide this.
(require 'splasher.core)
;;[optional]
;;if you're loading a logo for splasher you need to get io loaded as well.
(require 'clojure.java.io)
(if (seq args)
;;You can change this to process your args, or pass them on to something,
;;like say a blah.cli/cli processor for your app.
;;In this case, I just divert to the REPL
(clojure.main/repl)
;;otherwise, we invoke some runtime resolve magic to load our
;;namespace, with a splashscreen.
(binding [*ns* *ns*]
;;rather than :require it in the ns-decl, we load it
;;at runtime, let it hang out for 20 seconds or some time while we
;;load more stuff in the background.
(future ((resolve 'splasher.core/splash!)
(clojure.java.io/resource "logo.png")
:duration 20000))
;;
(require 'blah.core)
(in-ns 'blah.core)
;;if we don't use resolve, then we get compile-time aot
;;dependency on blah.core. This allows us to shim the
;;class. Assume blah.core/hub is a function that
;;launches a GUI frontend based in swing and
;;takes an :exit? arg. So we replace the typical
;;-main function, say what leiningen's default template
;;populates in our blah.core namespace, and eliminate
;;the gen-class from blah.core. In project.clj
;;we'd change the main to this class, blah.main,
;;and remove aot-all if it exists. We can now launch
;;much faster e.g. even if doing repl development (no need to AOT compile
;;the blah.core namespace, which could involve compiling a boatload of
;;stuff which takes too long for my taste (especially if I've already
;;tested it at the REPL anyway). Note: you can still AOT everything
;;if you want to.
((resolve 'blah.core/hub) :exit? true))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment