-
Notifications
You must be signed in to change notification settings - Fork 790
Quick Start
NOTE: This wiki page is under development for ClojureScript >= 0.0-3030. Thanks for your patience.
The only dependencies required for this tutorial is an installation of Java 8 and the standalone ClojureScript JAR. ClojureScript itself only requires Java 7 but the standalone JAR comes bundled with useful Nashorn integration that requires Java 8.
Even if you are interested in Leiningen based workflow this Quick Start is essential reading. It covers the fundamentals regardless of what tooling you decide to end up using.
The standalone ClojureScript JAR comes bundled with Clojure 1.6.0. This supports simple scripting of the ClojureScript compiler and the bundled REPLs without an overly complicated command line interface.
Download the standalone ClojureScript JAR.
Create a directory hello_world
and copy the JAR into that directory,
then from inside the hello_world
directory:
mkdir -p src/hello_world;touch src/hello_world/core.cljs
In your favorite text editor edit the src/hello_world/core.cljs
to look like the following:
(ns hello-world.core)
(enable-console-print!)
(println "Hello world!")
Every ClojureScript file must declare a namespace and this namespace
must match a path on disk. We then direct printing to the commonly
available JavaScript console
object and print the famous message.
In order to compile this we need a simple build script. ClojureScript
is just a Clojure library and can be easily scripted in a few lines of
Clojure. Create a file called build.clj
(the name doesn't matter),
and add the following Clojure code:
(require 'cljs.closure)
(cljs.closure/build "src" {:output-to "out/main.js"})
We require
the cljs.closure
namespace. We then invoke the
standard function for building some ClojureScript source -
cljs.closure/build
. This function only takes two arguments the
directory to compile and a map of options. In our case a simple
:output-to
will suffice for now.
Let's build some ClojureScript:
java -cp cljs.jar:src clojure.main build.clj
We invoke java
and set the classpath to our JAR and the
directory where our ClojureScript code lives. The clojure.main
argument in this case allows us to easily execute a Clojure
file.
Control should return to the shell relatively quickly and you
will have an out
directory with compiled JavaScript including
your simple program. You will see that many files were produced in
addition to the out/main.js
we specified. We'll explain this
momentarily but first let's see how you can easily include the
compiled output on a web page.
Create a file index.html
and include the following:
<html>
<body>
<script type="text/javascript" src="out/main.js"></script>
</body>
</html>
Open this file in your favorite browser and find the JavaScript developer console so you can see the output.
You will not see "Hello world!"
instead you will like see
an error like the following:
Uncaught ReferenceError: goog is not defined
In order to abstract away JavaScript environment differences ClojureScript relies on the Google Closure Library (GCL). GCL supplies an important facility mising from JavaScript, namespaces and a way to declare dependencies between them. In fact ClojureScript namespaces get compiled to Google Closure namespaces.
Loading dependencies correctly across various browser target is a surprisingly tricky affair. GCL accomplishes this by maintaining a dependency graph. When you require a namespace it will write the needed script tags in dependency order for you.
So what went wrong? If you look at out/main.js
you will see some
dependency graph building calls:
goog.addDependency("base.js", ['goog'], []);
goog.addDependency("../cljs/core.js", ['cljs.core'], ...);
goog.addDependency("../hello_world/core.js", ['hello_world.core'], ...);
But wait, where is the goog
object coming from?
Oops. We never loaded it! In order for GCL to bootstrap we must
at least load goog/base.js
. You'll see this is available in
out/goog/base.js
. Let's add this to your page now:
<html>
<body>
<script type="text/javascript" src="out/goog/base.js"></script>
<script type="text/javascript" src="out/main.js"></script>
</body>
</html>
Refresh the page.
The error will be gone but you still won't see the desired "Hello world!"
.
Hrm. out/main.js
didn't appear to have any of the logic that we
wrote, in fact it only includes the needed dependency graph
information for the ClojureScript standard library cljs.core
and our
namespace.
The last step we missed was actually requiring our namespace to
kick things off. Change index.html
to the following.
<html>
<body>
<script type="text/javascript" src="out/goog/base.js"></script>
<script type="text/javascript" src="out/main.js"></script>
<script type="text/javascript">
goog.require("hello_world.core");
</script>
</body>
</html>
To run ClojureScript on Node.js, set the var *main-cli-fn*
to the function you want to use as an entrypoint. For instructions on installing Node.js, see the Node.js wiki. Only the current stable versions of Node.js (0.10.X
) are supported at this time. The example below shows how a functional programmer might print "Hello World".
(ns nodehello
(:require [cljs.nodejs :as nodejs]))
(defn -main [& args]
(println (apply str (map [\ "world" "hello"] [2 0 1]))))
(nodejs/enable-util-print!)
(set! *main-cli-fn* -main)
Save this to a file named nodehello.cljs
and then run the following commands to compile and run.
$ ./bin/cljsc nodehello.cljs '{:optimizations :advanced :target :nodejs}' > nodehello.js
$ node nodehello.js
Note on some platforms (such as ubuntu) the node
command may be named nodejs
. Another example is available in samples/nodels.cljs
, but it currently only works with simple optimizations:
$ ./bin/cljsc samples/nodels.cljs '{:target :nodejs}' > nodels.js
$ node nodels.js src samples
The REPL equivalent of the above two compilation commands are shown below.
(cljsc/build "nodehello.cljs" {:optimizations :advanced :target :nodejs :output-to "nodehello.js"})
(cljsc/build "samples/nodels.cljs" {:target :nodejs :output-to "nodels.js"})
Prior to this commit, Node.js only worked under :advanced
or :simple
optimizations. ClojureScript will now emit the Node.js bootstrap script provided by Google Closure Library which implements Node.js compatible versions of goog.require
and goog.provide
. Under :none
and :whitespace
the following shell interaction will work:
node
> require("./[:output-dir]/goog/bootstrap/nodejs")
> require("./[:output-to]")
> require("./[:output-dir]/path/to/main/namespace")
Note using advanced compilation on Node.js targets is unnecessary. If for some reason it is desirable you must supply externs for the Node.js APIs.
Note: This section assumes that you have set the CLOJURESCRIPT_HOME environment variable and have cljsc
on your path. All examples show how to compile the project in samples/hello
.
The cljsc
tool, and the underlying build
function, supports three levels of optimization and a development mode where no optimization is performed and each input JavaScript file is kept separate. This section will give a quick overview of how to use each mode.
While developing a new application, leave out the :optimizations
option. This will compile all JavaScript into the working directory, which defaults to out
and write a "dependencies" file to hello.js
.
$ cljsc src '{:main hello}' > hello.js
From the REPL use:
(cljsc/build "samples/hello/src" {:main hello :output-dir "samples/hello/out" :output-to "samples/hello/hello.js"})
To host this application in a web page pull in hello.js
.
<script type="text/javascript" src="hello.js"></script>
When ready to deploy, compile the file with advanced optimizations.
$ cljsc src '{:optimizations :advanced}' > hello.js
In this situation, only one script tag is required which will pull in the hello.js
file:
<script type="text/javascript" src="hello.js"></script>
The other types of optimizations: :whitespace
and :simple
each produce less optimized but more readable code. There is also a :pretty-print
option.
$ cljsc src '{:optimizations :simple :pretty-print true}' > hello.js
The command above has the same effect as the one below. :output-dir
, the location where compiled JavaScript files are stored, defaults to out
. When :output-to
is not set, compiled output is printed to standard out.
$ cljsc src '{:optimizations :simple :pretty-print true :output-dir "out" :output-to "hello.js"}'
All of the options shown above may also be used when compiling from
the REPL with the build
function. For a full list of compiler
options, see Compiler Options.
- Rationale
- Quick Start
- Differences from Clojure
- [Usage of Google Closure](Google Closure)