-
Notifications
You must be signed in to change notification settings - Fork 520
Setup for development
There are different options to optimize your development workflow:
- Reload namespaces on source file changes
- Setup with lein-ring plugin
- Setup with boot
- Use a module lifecycle library Interactive Development
The first approach is fast, simple to setup. The ring-devel library provides middleware for this purpose.
Downside, namespace reloading does not reload application state. Consequently, there can be situation requiring to restart the server.
The Lein-Ring plugin is the most straightforward way. Create two files
- src/sample.clj
- project.clj
A simple service returning 'Hello World' in src/sample.clj
(ns sample)
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello world."})
Add lein-ring and configure the ring handler to your project file, project.clj:
:ring {:handler sample/handler}
A minimal project.clj:
(defproject lein-demo "0.1.0-SNAPSHOT"
:dependencies [[org.clojure/clojure "1.8.0"]
[ring/ring-core "1.6.3"]
[ring/ring-jetty-adapter "1.6.3"]
[ring/ring-devel "1.6.3"]]
:ring {:handler sample/handler}
:plugins [[lein-ring "0.12.5"]])
Start a development server:
lein ring server
Visit the server at http://localhost:3000
The server will automatically reload any modified files in your source directory.
Clojure provides command line tools for transitive dependency graph expansion and the creation of classpaths. Visit https://clojure.org/guides/deps_and_cli for more information.
Create the following project file structure:
.
├── deps.edn
├── dev
│ └── hotreload.clj
└── src
└── sample
└── server.clj
Describe the dependencies and classpaths.
;; deps.edn
{:paths ["src"]
:deps
{org.clojure/clojure {:mvn/version "1.9.0"}
ring/ring-core {:mvn/version "1.6.3"}
ring/ring-jetty-adapter {:mvn/version "1.6.3"}}
:aliases
{:dev
{:extra-paths ["dev"]
:extra-deps {ring/ring-devel {:mvn/version "1.6.3"}}
:main-opts ["-m" "hotreload"]}}}
Create the production server.
;; src/sample/server.clj
(ns sample.server
(:require [ring.adapter.jetty :refer [run-jetty]])
(:gen-class))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/plain; charset=UTF-8"}
:body "hello world!\n"})
(defn -main [& args]
(run-jetty handler {:port 3000}))
Start the server with clojure -M -m sample.server
. Visit
http://localhost:3000 and confirm the string "hello world!" displays.
Create the development server.
;; dev/hotreload.clj
(ns hotreload
(:require [ring.adapter.jetty :refer [run-jetty]]
[ring.middleware.reload :refer [wrap-reload]]
[sample.server :refer [handler]])
(:gen-class))
(def dev-handler
(wrap-reload #'handler))
(defn -main [& args]
(run-jetty dev-handler {:port 13000}))
Start the server with clojure -A:dev -M:dev
. Visit
http://localhost:13000 and confirm the string "hello world!" displays.
Note, newer Clojure CLI versions do to need the extra -A:dev
part.
The server will automatically reload any modified files in your source directory.
Boot is a build tool for Clojure', https://boot-clj.github.io/
Create two files
- build.boot
- src/sample.clj
A minimal build.boot
(set-env!
:resource-paths #{"src"}
:dependencies '[[org.clojure/clojure "1.8.0"]
[ring/ring-core "1.6.3"]
[ring/ring-jetty-adapter "1.6.3"]
[ring/ring-devel "1.6.3"]])
(deftask dev
"Run server hot reloading Clojure namespaces"
[p port PORT int "Server port (default 3000)"]
(require '[sample :as app])
(apply (resolve 'app/run-dev-server) [(or port 3000)]))
A simple service returning 'Hello World' without reloading in src/sample.clj
(ns sample
(:require
[ring.adapter.jetty :refer [run-jetty]]))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello world"})
(defn run-dev-server
[port]
(run-jetty handler {:port port}))
Inspect your boot task
boot dev -h
Run the server
boot dev
Visit http://localhost:3000
Next, we can add hot reloading. Check that the dependencies in build.boot include ring/ring-devel. Wrap the handler into a wrap-reload handler.
(ns sample
(:require
[ring.adapter.jetty :refer [run-jetty]]
[ring.middleware.reload :refer [wrap-reload]]))
(defn handler [request]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello world"})
(def dev-handler
(wrap-reload #'handler))
(defn run-dev-server
[port]
(run-jetty dev-handler {:port port}))
Restart the server and visit http://localhost:3000
Now, the server will automatically reload any modified files in your source directory.