-
Notifications
You must be signed in to change notification settings - Fork 524
Interactive Development
If you want to reload your source files without needing to restart your adapter, you need to:
- Run your adapter in a background thread so it doesn't block your REPL.
- Pass your handler function to the adapter as a var, so it will be updated when you reload the namespace.
For example:
(future (run-jetty (var my-handler) {:port 8080}))
You can also use Lein-Ring. It's a Leiningen plugin for automating common Ring tasks. It provides a command to start a development web server that automatically reloads modified source files. Add it as a dependency to your project.clj
:
:dev-dependencies [[lein-ring "0.4.0"]]
You also need to add a new ring
key, which specifies your Ring handler function, like this:
:ring {:handler hello-world.core/handler}))
Now run the command lein ring server
to start the web server. For more information, see Lein-Ring's README.
Another solution is to use wrap-reload from the ring-devel library. It reloads selected libraries before each request. Update your project.clj
to include ring-devel as a dependency:
:dev-dependencies [[ring/ring-devel "0.3.5"]]
Next you need to wrap your handler function using wrap-reload. It takes a handler and a list of namespaces to be reloaded. You need to pass the handler inside a var. For example, here's an adapted version of the Getting Started tutorial:
(ns hello-world.core
(:use ring.middleware.reload))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/html"}
:body "Hello World"})
(def app
(wrap-reload #'handler '(hello-world.core)))
Run it from the REPL:
=> (use 'ring.adapter.jetty)
=> (use 'hello-world.core)
=> (run-jetty app {:port 3000})
Another method is to setup your routes in a way that it always references the var
and not the value of the symbol. We can accomplish this by using the var-quote #'
instead of the quote when passing our routes.
=> (use 'ring.adapter.jetty)
=> (use 'compojure.core)
=> (require ['compojure.handler :as 'handler])
=> (defroutes main-routes (GET "/" [] (str "Hello Webserver")))
=> (def app (handler/site #'main-routes)) ; Notice the #' here.
=> (defonce (run-jetty (var app) {:port 8080 :join? false}))
Now there is a web-server running with the routes main-routes. As soon as you define a new route in your repl (or slime) you can see the effect in your browser.
To assist with developing you can also use the following helper functions.
=> (defonce server (run-jetty (var app) {:port 8080 :join? false}))
=> (defn start-server []
(.start server))
=> (defn stop-server []
(.stop server))
=> (defn reload-server []
(do (stop-server)
(start-server)))