Book Image

Learning ClojureScript

By : W. David Jarvis, Allen Rohner
Book Image

Learning ClojureScript

By: W. David Jarvis, Allen Rohner

Overview of this book

Clojure is an expressive language that makes it possible to easily tackle complex software development challenges. Its bias toward interactive development has made it a powerful tool, enabling high developer productivity. In this book, you will first learn how to construct an interactive development experience for ClojureScript.. You will be guided through ClojureScript language concepts, looking at the basics first, then being introduced to advanced concepts such as functional programming or macro writing. After that, we elaborate on the subject of single page web applications, showcasing how to build a simple one, then covering different possible enhancements. We move on to study more advanced ClojureScript concepts, where you will be shown how to address some complex algorithmic cases. Finally, you'll learn about optional type-checking for your programs, how you can write portable code, test it, and put the advanced compilation mode of the Google Closure Compiler to good use.
Table of Contents (15 chapters)
Learning ClojureScript
Credits
Foreword
About the Authors
About the Reviewer
www.PacktPub.com
Preface

Setting integrated development environments for ClojureScript


Now that we've got the basic lay of the land, we can now focus on configuring a proper Integrated Development Environment. We'll also discuss how we can make it ClojureScript-aware using the REPLs we've covered so far.

In doing so, we strive to profit from the many ways IDEs can assist us. IDEs are powerful tools, exposing functionalities such as code completion, syntax highlighting, program structure introspection, and navigation.

We'll focus on Emacs, its Clojure development environment, CIDER, as well as another simpler package, inf-clojure. The reason why we chose these Emacs-based tools is that they are the most used IDEs for most Clojurists, and are actively maintained by a vibrant community of open source enthusiasts.

Working on Emacs with Piggieback and Weasel on CIDER

CIDER, or the Clojure Interactive Development Environment that Rocks for Emacs ( https://github.com/clojure-emacs/cider ), is an open source Emacs Library for working with Clojure on Emacs. Originally called nrepl.el, it is stable, feature-rich, and an active project that is highly beneficial to Clojure and ClojureScript developers.

If you're going to use CIDER, its authors have stated that they expect ClojureScript developers to use Piggieback and Weasel as their default toolkit.

Let's assume that you can launch a Piggieback/Weasel-enabled nREPL session for your ClojureScript project (refer to the Live-coding ClojureScript on top of nREPL with PiggieBack and Weasel section). We'll now focus on how CIDER empowers you to develop ClojureScript with Emacs.

Installing CIDER

Installing Cider is a matter of getting the relevant library from package.el (using MELPAMELPA Stable, or Marmalade repositories) and issuing the following command (in Emacs):

M-x package-install [RET] cider [RET]

Alternatively, add the following lines to your Emacs configuration file:

(unless (package-installed-p 'cider) 
  (package-install 'cider)) 

You'll also need to hook up the CIDER middleware into our nREPL. To do this, add the following to the :user section in your ~/.lein/profiles.clj file:

:plugins [[cider/cider-nrepl "x.y.z"]] 

We haven't spoken about Leiningen profiles too much prior to now. To learn more about how the profiles.clj file works, check out the Leiningen documentation at https://github.com/technomancy/leiningen/blob/master/doc/PROFILES.md#declaring-profiles. Take care, the "x.y.z" version number in cider-nrepl must match the CIDER version, otherwise you'll get a warning when trying to connect to a project's REPL.

Working with Clojure and ClojureScript REPLs on CIDER

At this point, you're free to tweak CIDER's configuration to add features like different autocompletion providers or syntax-highlighting behavior. Whether you choose to or not, you should have everything you need to get CIDER up and running at this point.

Once you have installed CIDER and its nREPL middleware, you can open a Clojure file (even an empty buffer to experiment in), launch an REPL on it and begin to work interactively. Most Clojure developers go back and forth between editing and sending code to the REPL for evaluation. To launch a Clojure nREPL session from Emacs use the following command:

M-x cider-jack-in

Now, how can we get this set up to work with ClojureScript? Let's go back to our piggieback_project from earlier in this chapter and get CIDER working for it.

First, we'll need to tell CIDER which ClojureScript evaluation environment we are going to use. CIDER defaults to Rhino, so for our case we'll need to tell CIDER to use Weasel. Customize the cider-cljs-repl file to set it to Weasel:

M-x customize-variable RET cider-cljs-repl RET Weasel RET 

Make certain that your ClojureScript file contains the following connection code:

(ns piggieback-project.core 
  (:require [weasel.repl :as repl])) 
 (when-not (repl/alive?) 
  (repl/connect "ws://localhost:9001")) 

Tip

Make sure that this ClojureScript code has been successfully compiled at least once. Otherwise, we won't be able to load the websocket client.

Next, we'll use the lein-cljsbuild package. To activate this plugin make sure that your project.clj file looks as follows:

(defproject piggieback_project "0.1.0-SNAPSHOT" 
  :description "FIXME: write description" 
  :url "http://example.com/FIXME" 
  :license {:name "Eclipse Public License" 
    :url "http://www.eclipse.org/legal/epl-v10.html"} 
  :plugins [[lein-cljsbuild "1.1.0"]] 
  :cljsbuild { 
    :builds [{:source-paths ["src"] 
    :compiler {:main piggieback-project.core 
    :output-to "out/main.js" 
    :output-dir "out" 
    :optimizations :none}}]} 
  :dependencies [[org.clojure/clojure "1.7.0"] 
    [org.clojure/clojurescript "1.7.122"] 
    [weasel "0.7.0" :exclusions [org.clojure/clojurescript]]] 
  :profiles {:dev {:dependencies [[com.cemerick/piggieback
    "0.2.1"] 
    [org.clojure/tools.nrepl "0.2.10"]] 
    :repl-options {:nrepl-middleware
      [cemerick.piggieback/wrap-cljs-repl]}}})

Now we'll  build the code responsible for creating the connection. While in the project directory, type the following:

lein cljsbuild once

Now open any ClojureScript file in Emacs, and launch the nREPL session with:

M-x cider-jack-in-clojurescript

You'll see two REPLs, one for Clojure and the other for ClojureScript. The ClojureScript REPL should notify you that it is waiting for the client to connect.

Connect your browser to the Weasel session by opening greet.html. You should get the following screen in Emacs:

Now, switch to the window containing the Clojure REPL and set it to show the buffer containing your test.cljs ClojureScript file.

Load the content of the file in your REPL using the following Emacs command:

C-c C-k

Then, set the namespace of the REPL to be the one declared by the current source file:

C-c M-n

Switch now to your ClojureScript REPL:

C-c C-z

Start typing the name of the function. You'll notice that code completion should be working. In the minibuffer, Emacs should also help you with the signature of your function.

Now let's evaluate some ClojureScript in our REPL:

piggieback-project.test> (defn test-fn [your-name] (js/alert (+
      "hello " your-name)))
piggieback-project.test> (test-fn "Rafik")

And a popup should happily greet you from your connected browser.

Working on Emacs with Figwheel and inf-clojure

In order to use Figwheel with Emacs, we'll need to use inf-clojure, an Emacs package offering basic interaction with a running Clojure subprocess. In conjunction with clojure-mode, this setup will make sure that we benefit from static code analysis features. inf-clojure is not as feature rich as CIDER, which is worth keeping in mind. It is nevertheless, able to load files, switch namespaces, evaluate expressions, show documentation and source of symbols, and do macro-expansion.

Installing inf-clojure

Type the following in your Emacs:

M-x package-install [RET] inf-clojure [RET]

You may also want to add the following snippet to your Emacs configuration file:

(unless (package-installed-p 'inf-clojure) 
  (package-install 'inf-clojure)) 

To enable inf-clojure whenever you visit a Clojure or ClojureScript file, add the following to your Emacs configuration file:

(add-hook 'clojure-mode-hook #'inf-clojure-minor-mode) 

Configuring inf-clojure to run Figwheel as a Clojure subprocess

In order for Emacs to know that we want to use Figwheel as our REPL environment, we'll need to configure it explicitly. To do this, add the following to your Emacs configuration file (usually ~/.emacs):

(defun figwheel-repl () 
  (interactive) 
  (run-clojure "lein figwheel")) 

Restart Emacs or re-evaluate the the configuration file buffer for the modifications to take effect. Next, let's open a file in the source directory of the figwheel_project we've set up for the browser, say core.cljs, and launch the ClojureScript powered inf-clojure session by typing the following:

M-x figwheel-repl

You'll end up to a configuration like the one shown in the following screenshot, where Figwheel, run from inf-clojure, is awaiting connection from the browser:

As soon as you open the greet.html file within your browser, the user prompt should change to notify you that the evaluation environment is successfully connected to the Figwheel REPL:

Let's evaluate some ClojureScript. Split your window in two using the following:

C-x 2

And load the buffer containing core.cljs:

C-x b  core.cljs [RET]

You should end up with something like the following:

Move the cursor to the (js-alert...) form and evaluate it by hitting the following:

C-c C-c

You should see the greeting showing up in the browser.

We've now seen two different possible setups on Emacs: one based on Piggieback/Weasel, which is harder to set up but offers a fully-fledged Clojure development environment—CIDER, and another using Figwheel but offering less integrated development functionality. Which one you choose to use relies pretty much on personal taste, and how much effort you feel like putting in.