Howdy Clojurians,
I recently started developing a new Clojure+Clojurescript web application,
and I wanted to see if I could set up my development environment using just
the Clojure CLI tools. After a good deal of digging around through
tutorials on a number of different websites and a fair amount of
experimenting, I've managed to create a very simple (IMHO) configuration
that provides me with both development and production mode CLJS->JS
compilation, development and production mode ring handlers, and the always
delightful FIgwheel development environment all from just the simple
"clojure" command. Since I haven't seen this before, I thought I'd share it
with all of you in case it helps someone else out there who doesn't need
(or want) all of leiningen or boot to develop a simple web app.
Here goes:
Step 1: Create your project structure like so:
├── cljsbuild.edn
├── deps.edn
├── figwheel.edn
├── resources
│ └── public
│ ├── cljs
│ ├── css
│ │ ├── style.css
│ ├── images
│ └── js
├── src
│ ├── clj
│ │ └── my_project
│ │ ├── handler.clj
│ │ ├── server.clj
│ │ ├── views.clj
│ └── cljs
│ └── my_project
│ ├── client.cljs
Step 2: Make the deps.edn file (replace :deps and my-project.server
namespace as necessary for your project)
{:paths ["src/clj" "resources"]
:deps {org.clojure/clojure {:mvn/version "1.9.0"}
org.clojure/clojurescript {:mvn/version "1.10.312"}
ring {:mvn/version "1.7.0-RC1"}
ring/ring-defaults {:mvn/version "0.3.2"}
prone {:mvn/version "1.6.0"}
compojure {:mvn/version "1.6.1"}
hiccup {:mvn/version "1.0.5"}
reagent {:mvn/version "0.8.1"}}
:aliases {:run {:main-opts ["-m" "my-project.server"]}
:cljsbuild {:extra-paths ["src/cljs"]
:main-opts ["-m" "cljs.main" "-co" "cljsbuild.edn"
"-c"]}
:figwheel {:extra-deps {org.clojure/tools.nrepl {:mvn/version
"0.2.13"}
cider/cider-nrepl {:mvn/version
"0.17.0"}
com.cemerick/piggieback {:mvn/version
"0.2.2"}
figwheel-sidecar {:mvn/version
"0.5.14"}}
:main-opts ["-e"
"(use,'figwheel-sidecar.repl-api),(start-figwheel!)"]}}}
Step 3: Make the cljsbuild.edn file (replace :main for your project)
{:main "my-project.client"
:output-dir "resources/public/cljs"
:output-to "resources/public/cljs/app.js"
:source-map "resources/public/cljs/app.js.map"
:optimizations :advanced
:pretty-print false}
Step 4: Make the figwheel.edn file (replace :ring-handler, :on-jsload, and
:main for your project)
{:nrepl-port 7000
:nrepl-middleware ["cider.nrepl/cider-middleware"
"cemerick.piggieback/wrap-cljs-repl"]
:server-port 3000
:ring-handler my-project.handler/development-app
:http-server-root "public"
:css-dirs ["resources/public/css"]
:builds [{:id "dev"
:source-paths ["src/cljs"]
:figwheel {:on-jsload "my-project.client/mount-root"}
:compiler {:main "my-project.client"
:output-dir "resources/public/cljs/out"
:output-to "resources/public/cljs/app.js"
:asset-path "/cljs/out"
:source-map true
:optimizations :none
:pretty-print true}}]}
Step 5: Write server.clj
(ns my-project.server
(:require [ring.adapter.jetty :refer [run-jetty]]
[my-project.handler :refer [development-app production-app]])
(:gen-class))
(defonce server (atom nil))
(defn start-server! [& [port mode]]
(reset! server
(run-jetty
(case mode
"dev" #'development-app
"prod" #'production-app
#'production-app)
{:port (if port (Integer/parseInt port) 3000)
:join? false})))
(defn stop-server! []
(when @server
(.stop @server)
(reset! server nil)))
(def -main start-server!)
Step 6: Write handler.clj
(ns my-project.handler
(:require [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
[ring.middleware.reload :refer [wrap-reload]]
[prone.middleware :refer [wrap-exceptions]]
[compojure.core :refer [defroutes GET]]
[compojure.route :refer [not-found]]
[my-project.views :refer [render-page]]))
(defroutes routes
(GET "/" [] (render-page))
(not-found "Not Found"))
(def development-app (wrap-reload
(wrap-exceptions
(wrap-defaults #'routes site-defaults))))
(def production-app (wrap-defaults #'routes site-defaults))
Step 7: Write views.clj
(ns my-project.views
(:require [hiccup.page :refer [html5 include-css include-js]]))
(defn render-page []
(html5
[:head
[:title "My Project"]
[:meta {:charset "utf-8"}]
[:meta {:name "viewport" :content "width=device-width, initial-scale=1"
}]
(include-css "/css/style.css")
(include-js "/cljs/app.js")]
[:body
[:div#app]
[:script {:type "text/javascript"} "my_project.client.mount_root();"]))
Step 8: Write client.cljs (replace Reagent with whichever front-end library
you prefer)
(ns my-project.client
(:require [reagent.core :as r]))
(defn root-component []
[:div [:h1 "Hello world!"]])
(defn ^:export mount-root []
(r/render [root-component]
(.getElementById js/document "app")))
Step 9: Write some CSS in resources/public/css/style.css
#app {
border: 2px solid green;
}
Step 10: Try out your new dev tools!
At this point, your project setup is complete, and you are ready to start
developing your awesome new Clojure+Clojurescript web app. You have the
following 3 project management commands available at your command prompt:
*1. Compile Clojurescript to Javascript*
To compile the Clojurescript files under src/cljs to Javascript under
resources/public/cljs, navigate to the toplevel project directory and run:
$ clojure -A:cljsbuild
The main Javascript entry point file will be written to
resources/public/cljs/app.js. The Clojurescript build options are read from
the toplevel cljsbuild.edn file. They are set to use advanced compilation
mode for a production build.
*2. Run your Web Application *
To compile and run your web application, navigate to the toplevel project
directory and run:
$ clojure -A:run [port] [dev|prod]
The website will then be available at http://localhost:3000 or on whichever
port you specified. In dev mode, server-side exceptions will be displayed
in the browser and Clojure source files will be reloaded whenever you
refresh the page. These features are disabled in prod mode. If the second
argument to run is omitted, it will default to prod mode.
*3. Launch Figwheel*
To start the Figwheel server, navigate to the toplevel project directory
and run:
$ clojure -A:figwheel
This will start an http-kit webserver on http://localhost:3000, which
serves up the website in dev mode. It will also open an nREPL on port 7000,
which provides the special command "(cljs-repl)" to switch from a Clojure
REPL to a Clojurescript REPL. Finally, any changes to CLJS or CSS files
will automatically be pushed to the browser when the
files are saved.
Okay, folks. That's all from me for now. Setting this all up was quite an
interesting learning exercise, but I'm very happy with the results. I hope
someone out there finds this setup useful for your next Clojure project. If
someone has the power to add this tutorial to the Clojure website (or other
documentation site), I think it would be a great addition.
Also, someone should definitely make a *clj-new* project template from this
setup. *I'm looking at you, Sean Corfield.* ;-D
Have fun, everyone, and happy hacking!
~Gary
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.