Setting Up ClojureScript: A Beginner's Guide
03 Sep 2013I recently started learning Clojure in order to build some ClojureScript applications. However, I found that the learning curve for getting set up is a bit steep. There are some useful tutorials online, but none of them gave me the exact combination of elements I was looking for.
So I thought I’d outline my own setup to add another approach to the mix, and to serve as a source for helpful links. I recommend reading other tutorials as well and piecing together what works best for you.
I. Getting Started
The first thing you need to do is install Leiningen, which you’ll use for a lot of important tasks, such as building projects and running a local server. You can find installation instructions at the GibHub page, but you might try your package manager first.
Once installed, you can jump right into writing some Clojure code at the Leiningen REPL. Start it up at the command line with:
lein repl
This can help you get your feet wet, but you’ll want to create a project with the correct directory structure and initial files if you’re going to build a ClojureScript app. At the command line, you can use
lein new project-name
to generate the bare skeleton of a project in a directory called project-name
. We’re going to use this as our starting point.
II. Configuring project.clj
Navigate to the project-name
directory and open project.clj
for editing (or you might want to just open that directory in LightTable and work from there, which will make your life easier). You can eventually update the description and url, but for now let’s focus on the dependencies.
At first, you will only have the latest version of Clojure listed. I added ClojureScript, Compojure, Hiccup, and Jayq to this list:
:dependencies [[org.clojure/clojure "1.5.1"] [org.clojure/clojurescript "0.0-1806"] [compojure "1.1.5"] [jayq "2.4.0"] [hiccup "1.0.4"]]
ClojureScript needs no introduction I hope. Compojure is a routing library that will help us build our web app out of modular parts. Hiccup allows us to produce HTML using Clojure code, which will come in handy when rendering our app. Finally, Jayq will allow us to use JQuery for DOM manipulation. You might also try Domina or Dommy for working with the DOM instead.
Next, I added a couple of plugins as follows:
:plugins [[lein-cljsbuild "0.3.2"] [lein-ring "0.8.7"]]
lein-cljsbuild
will allow us to autocompile ClojureScript into JavaScript. lein-ring
will allow us to automate Ring tasks from Leiningen. For example, it will allow to start a Ring server from the command line.
We now need to add our source paths and configure lein-cljsbuild
:
:source-paths ["src/clj"] :cljsbuild { :builds { :main { :source-path "src/cljs" :compiler { :output-to "resources/public/js/cljs.js" :optimizations :simple :pretty-print true}}}}
The source paths specify where our Clojure and ClojureScript files will go. :output-to
specifies where ClojureScript files in the cljs
source path will be compiled to a .js
file. I’ve named the target cljs.js
, but you could always name it something else.
Finally, let’s add some lines for the server for our app.
:main project-name.server :ring {:handler project-name.server/app})
Now we’re ready to set up the server itself.
III. Setting up server.clj with Compojure and Hiccup
Create a file called server.clj
in a directory called src/clj/project_name
(note the underscore in the directory name). Let’s begin by bringing in Compojure and Hiccup.
(ns project-name.server (:require [compojure.handler :as handler] [compojure.route :as route] [ring.util.response :as response]) (:use [hiccup.core] [compojure.core]))
We’re setting up the project-name.server
namespace, importing functions from hiccup.core
and compojure.core
, and aliasing compojure.handler
and compojure.route
. We’re also importing ring.util.response
in case we want to serve up static HTML pages. Now let’s create a layout for our app as well as some initial content.
(defn view-layout [& content] (html [:head [:meta {:http-equiv "Content-type" :content "text/html; charset=utf-8"}] [:title "Project-Name"]] [:body content])) (defn view-content [] (view-layout [:h2 "Project-Name"] [:p {:id "clickhere"} "Get yourself a nice alert by clicking here."] [:script {:src "/js/jquery-1.10.2.min.js"}] [:script {:src "/js/cljs.js"}]))
Both of these functions use Hiccup to generate HTML. Looking them over should give you a good initial idea about how this is done. Notice that we are sending the content parameter to the :body
key in view-layout
. This allows us to create the body of our app in a separate view-content
function. view-content
calls view-layout
with some Hiccup code as an argument.
I’ve included a CSS id so that we can make the <p>
element clickable later. At the end of the <body>
element, I’ve included JQuery and our target JavaScript file (originally specified in project.clj
). Be sure to download the minified JQuery file and put it in your resources/public/js/
folder.
Finally, we need to set up a Compojure handler so we can actually see this HTML in the browser.
(defroutes main-routes (GET "/" [] (view-content)) (route/resources "/")) (def app (handler/site main-routes))
When we start our Ring server from the command line, we will be able to access our app at http://localhost:3000/. defroutes
allows us to point directories to either static HTML files or HTML generated in Clojure. In this case, we’re routing “/” to the HTML generated by our view-content
function. We could also have used the following to redirect to a file called resources/public/web-page-name.html
:
(defroutes main-routes (GET "/" [] (response/redirect "web-page-name.html")) (route/resources "/"))
Finally, we bind our app to the main-routes handler. Recall that app
is the name referred to in the last line of our project.clj
file, which looked like this:
:ring {:handler project-name.server/app})
We now have everything we need in place to start up a Ring server from the command line. Open a new terminal, navigate to the project directory and type
lein ring server
A browser should come up displaying our app. However, you’ll notice that clicking will not in fact get you a nice alert. Let’s use some ClojureScript to accomplish this.
IV. Enter ClojureScript: Setting up client.cljs
Setting up our initial ClojureScript file will be simple enough. Create a file called client.cljs
in src/cljs/project_name
(not the underscore again). Here’s what it should look like in full:
(ns project-name.cs (:use [jayq.core :only [$]]) (:require [jayq.core :as jq])) (def $clickhere ($ :#clickhere)) (jq/bind $clickhere :click (fn [evt] (js/alert "Clicked!!")))
We import Jayq in order to use some basic JQuery functions. First, we store the #clickhere
element from our app in $clickhere
. Then we bind a click event listener to that element. Our callback function uses a JavaScript alert
.
In order to see this in action, open a new terminal and navigate to the project directory. Now type the following:
lein cljsbuild auto
This will compile our ClojureScript file to the target .js
file specified in project.clj
. In our case, it’s resources/public/js/cljs.js
. Furthermore, cljsbuild
will be running in the background now, auto-compiling the JavaScript file whenever we make changes to client.cljs
.
Refresh the browser pointed to localhost:3000
to see the change. When you click the appropriate spot, you should get an alert. Like magic!
Well, magic used for a rather boring effect. But now you’ve got the basic setup you need to start making things more interesting.
V. Wrapping up
You’ve now got a basic ClojureScript project started. If you don’t want to go through this tedious process every time, feel free to use my Leiningen template called cljs-exnihilo
. To use it, all you have to do is type the following from the command line:
lein new cljs-exnihilo new-project-name
This will create a new directory called new-project-name
and populate it with the files and directory structure discussed here (or some variation thereof, depending on whether I make modifications in the future to the template).
It’s all well and good that you can use my template to save you time, but it would be much more useful in the long run if you build your own template for your future projects. You can look over cljs-exnihilo
on GitHub to get a sense for how to build your own.
Have fun ClojureScripting!