-
Notifications
You must be signed in to change notification settings - Fork 791
The REPL and Evaluation Environments
This page describes work which is being done on the clojure.browser
branch. Everything is subject to change.
One of the reasons for creating ClojureScript is that JavaScript reaches. There are many interesting environments in which JavaScript can run. Each of these environments has something unique about it. One of the reasons that Clojure rocks is that it has a REPL which gives developers the most dynamic development experience possible. We would like to support this dynamic development experience in every environment where JavaScript runs. To accomplish this, we have created an abstraction around the JavaScript environment and disconnected the REPL from any particular implementation. This gives the REPL the same reach as JavaScript as well as allowing evaluation environment implementations to be used independently for things like automated testing and cross-environment testing.
Most projects will target a specific environment. These changes will allow you to have the full benefit of a REPL in your target environment. Currently there are implementations for two environments: Rhino and the browser. By implementing one protocol, you can easily support additional environments.
The basic usage of the REPL is always the same:
- require
cljs.repl
- require the namespace which implements the desired evaluation environment
- create a new evaluation environment
- start the REPL with the created environment
Using the REPL will also feel the same in each environment; forms are entered, results are printed and side-effects happen where they make the most sense.
(require '[cljs.repl :as repl])
(require '[cljs.repl.rhino :as rhino]) ;; require the rhino implementation of IJavaScriptEnv
(def env (rhino/repl-env)) ;; create a new environment
(repl/repl env) ;; start the REPL
This is very much the same as it was before and will behave the same as the old ClojureScript REPL.
A browser-connected REPL works in much the same way as a normal REPL: forms are read from the console, evaluated and return values are printed. A major and useful difference form normal REPL usage is that all side-effects occur in the browser. You can show alerts, manipulate the dom and interact with a running application.
There is a sample project under samples/repl
which shows how to set up a minimal browser-connected REPL. This example will walk through doing the same thing, step-by-step.
The first step is to create the browser side of the connection. This is done by adding one require and one line of code, as shown below in a file named foo.cljs
.
(ns foo
(:require [clojure.browser.repl :as repl]))
(repl/connect "http://localhost:9000/repl")
The most interesting use case for a browser-connected REPL is to connect it to a project and use the REPL to drive and develop an application while it is running. To set this up you only need to add this same code to any file in the project.
Next, compile the file in either development mode or with simple optimizations. No advanced optimizations please.
./bin/cljsc foo.cljs > foo.js
Create a host html page like the one shown below.
<html>
<head>
<meta charset="UTF-8">
<title>Browser-connected REPL</title>
</head>
<body>
<div id="content">
<script type="text/javascript" src="out/goog/base.js"></script>
<script type="text/javascript" src="foo.js"></script>
<script type="text/javascript">
goog.require('foo');
</script>
</body>
</html>
There is nothing different about this and what one would do for any other browser-based ClojureScript project.
Start the REPL using the pattern described above, but with the browser as the evaluation environment.
(require '[cljs.repl :as repl])
(require '[cljs.repl.browser :as browser]) ;; require the browser implementation of IJavaScriptEnv
(def env (browser/repl-env)) ;; create a new environment
(repl/repl env) ;; start the REPL
Once the REPL has stared you will see the message "Starting server on port 9000". At this point, open the html page to complete the connection. Once the paged is open and the connection is made, the REPL prompt will be dispalyed.
Just in case you can't think of anything interesting to do, here are some ideas.
;; the basics
(+ 1 1)
(:a {:a :b})
(reduce + [1 2 3 4 5])
(defn sum [coll] (reduce + coll))
(sum [2 2 2 2])
;; load a ClojureScript file and use it
(load-file "clojure/string.cljs")
(clojure.string/reverse "ClojureScript")
;; browser specific
(js/alert "I am an evil side-effect")
(load-namespace 'clojure.browser.dom)
(ns dom.test (:require [clojure.browser.dom :as dom]))
(dom/append (dom/get-element "content")
(dom/element "ClojureScript is all up in your DOM."))
;; load and use goog code we haven't used yet
(load-namespace 'goog.crypt)
(ns test.crypt (:require [goog.crypt :as c]))
(c/stringToByteArray "ClojureScript")
(load-namespace 'goog.date.Date)
(goog.date.Date.)
There are currently two options which may be used to configure the browser evaluation environment.
-
:port
set the port to listen on - defaults to 9000 -
:working-dir
set the working directory for compiling REPL related code - defaults to ".repl"
In the example above, two ways are shown to load new code into the environment: load-file
and load-namespace
. load-file
simply loads a single ClojureScript file. load-namespace
loads any file, ClojureScript or JavaScript, with all of its dependencies, which have not already been loaded, in dependency order.
- Rationale
- Quick Start
- Differences from Clojure
- [Usage of Google Closure](Google Closure)