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 clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
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 clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to