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

Live coding ClojureScript with Figwheel


Figwheel ( https://github.com/bhauman/lein-figwheel ) is a Leiningen plugin that builds ClojureScript programs and delivers them to the browser for interactive evaluation. In contrast with nREPL-based work-flows, Figwheel does not rely on third-party REPLs. It is a self-contained library with its own ClojureScript REPL that relies on websockets to push your work to the browser as you edit your ClojureScript code. Figwheel also supports CSS live reloading in the browser, hence providing for a completely interactive web development experience. In this next section, we'll use Figwheel to get set up a ClojureScript live-coding experience on the browser.

Setting up Figwheel for browser live coding

Figwheel comes as a self-contained library that automatically builds and loads the generated JavaScript into the browser. This means we won't have to manually build the JavaScript that'll be pushed to the browser in order to establish the connection to the Figwheel REPL. Everything will be handled for us.

Let's begin by creating a new project that we will use to experiment with Figwheel:

lein new figwheel-project

We'll now need to change our project.clj file so that our project is aware of the lein-figwheel plugin:

(defproject figwheel-project "0.1.0-SNAPSHOT" 
  :dependencies [[org.clojure/clojure "1.8.0"] 
    [org.clojure/clojurescript "1.8.51"]] 
  :plugins [[lein-figwheel "0.5.1"]] 
  :clean-targets [:target-path "out"] 
  :cljsbuild { 
    :builds [{:id "dev" 
      :source-paths ["src"] 
      :figwheel true 
      :compiler {:main "figwheel-project.core"}}]})
        :asset-path "js/out"
        :output-to "resources/public/js/main.js"
        :output-dir "resources/public/js/out"}}]})

Create a file named core.cljs under src/figwheel_project/ so we can have a ClojureScript program that will be built and pushed to the browser. Code changes will be pushed to the browser automatically later on via this loaded file:

(ns figwheel-project.core) 
 
(js/alert "Hello from Figwheel!") 

As before, in order to load the compiled JavaScript that'll connect our browser to the running Figwheel process we need to have an HTML page. Since we're still compiling ClojureScript to the main.js file, we must load this file in order to get it evaluated in the browser. Create a greet.html file that you'll put in the root of your project. This page will contain the following:

<html> 
  <body> 
    <script type="text/javascript" src="main.js"></script> 
  </body> 
</html> 

Let's launch Figwheel. Note how this is done as a Leiningen plugin, and how we don't need to load a specific ClojureScript on top of an nREPL as we did with Piggieback:

lein figwheel

Your terminal should show a message that states that it is awaiting the client connection:

Prompt will show when figwheel connects to your application

For this, we are going to simply use the web server that comes embedded within Figwheel. Provided that we’ve put the previous greet.html in our browser. Open that HTML page as a regular file under the public/resources folder visit the following URL, http://localhost:3449/greet.html. As soon as the page loads, you'll see the greeting we programmed to show in the ClojureScript file, and once you've clicked on the OK button, you'll notice that the Figwheel invite is now showing a prompt accepting user requests for ClojureScript evaluation:

cljs.user=> _

Let's try to evaluate something in the browser. Type the following:

cljs.user=> (js/alert "Hi from Figwheel Again!")

Once again, this new greeting should pop up in your browser!

We've seen how it was easy to set up a browser live-coding session with Figwheel. In the next section, we'll experiment with Node.js evaluations.

Node.js interactive development workflows with Figwheel

Figwheel is mainly intended for the browser, and as such, configuring it to connect to Node.js is a bit trickier than what we just did. Since Figwheel does not rely on the core ClojureScript REPL or nREPL, and hence, there are some actions that need to be taken in order to add Node.js support to its default stack.

Getting Figwheel to provide a Node.js REPLs is a matter of preparing a special JavaScript artifact that, when run with Node.js, will implement a server that connects via websocket to a running Figwheel session. This server will evaluate the compiled JavaScript from the Figwheel REPL via the WebSocket connection. Let's implement this.

First create a new Clojure project and name it figwheel_node. Next, prepare the ClojureScript Node.js script that, once launched, will connect via a WebSocket to the REPL served by Figwheel:

(ns ^:figwheel-always figwheel-node-repl.core 
  (:require [cljs.nodejs :as nodejs])) 
(nodejs/enable-util-print!) 
(def -main (fn [] nil)) 
(set! *main-cli-fn* -main) 

Next, let's modify our project.clj file to target the Node.js runtime using the relevant bootstrapping library. We could configure the bootstrapping library ourselves, but instead we'll use a popular Leiningen plugin, Cljsbuild (https://github.com/emezeske/lein-cljsbuild), to automate this process for us. Let's add and configure it by editing your project.clj as follows:

(defproject figwheel-node "0.1.0-SNAPSHOT" 
  :dependencies [[org.clojure/clojure "1.7.0"] 
    [org.clojure/clojurescript "1.7.122"]] 
  :plugins [[lein-cljsbuild "1.1.0"] 
    [lein-figwheel "0.4.0"]] 
  :clean-targets ^{:protect false} ["out"] 
  :cljsbuild { 
    :builds [{:id "server-dev" 
      :source-paths ["src"] 
      :figwheel true 
      :compiler {:main figwheel-node-repl.core
                 :output-to "out/figwheel_node_repl.js"
                 :output-dir "out"
                 :target :nodejs
                 :optimizations :none
                 :source-map true}}]}
  :figwheel {})

Note that setting the figwheel-node-repl.core namespace as a main entry point will ensure that all the necessary imports are added to our compiled output before we execute any of the program logic via websockets. This way, the script can be painlessly run by Node.js.

Next, let's install the Node.js websockets client library, ws, so that our script can connect to the Figwheel session:

npm install ws

As we've done with the browser setup, launch the Figwheel REPL:

lein figwheel server-dev

As usual, you will see a prompt telling you that the Figwheel environment is awaiting a client connection. This time, the client will be the Node.js script we just developed. Launch it in a different terminal window from the one currently running our Figwheel server:

node out/figwheel_node_repl.js

At this point, you have two running environments: the Figwheel REPL, which now shows the cljs.user=> prompt and the Node.js process, which is actively evaluating the compiled JavaScript that is being pushed to it by Figwheel.

Let's evaluate, on the Figwheel REPL, the HTTP server we used in the previous sections:

cljs.user=> (def http (js/require "http"))
cljs.user=> (.listen (.createServer http
       #_=>                         (fn [req res]
       #_=>                         (do
       #_=>                         (.writeHead res
       #_=>                         200
       #_=>                         (js-obj
       #_=>                         "Content-Type"
                                          "text/plain"))
       #_=>                         (.end res
       #_=>                         "Hello World from
                                          Node.js http server!"))))
       #_=>                         1337
       #_=>                         "127.0.0.1")

If you visit the URL exposed by this HTTP server, http://127.0.0.1:1337, you should see a greeting from Node.js, meaning that the ClojureScript you typed in the Figwheel REPL has been successfully compiled to JavaScript and evaluated by the running Node.js process.

We've studied two alternatives for exposing ClojureScript REPLs-one of them based on nREPL with Piggieback and the other using a standalone REPL environment based on Figwheel. In the next sections, we'll talk about how to set up development environments for ClojureScript on Emacs.