Lesson 5: Bootstrapping a Clojurescript Project
In this lesson:
- Walk through setting up a project from scratch
- Learn how to use Leiningen, the leading ClojureScript build tool
- Explore the structure of a fresh project
Using Leiningen to bootstrap a new project
$ lein new my-cljs-project
Leiningen comes with a large command-line interface that provides access to
common tasks such as creating a new project or running tests. Simply running the
lein, with no arguments will list all of the commands available. For
more help on a specific task (such as
new in the command we just ran), we can
lein help TASK where
TASK is the name of any Leiningen task available.
While Leiningen provides a number of tasks by default, we will often run tasks
provided by plugins.
NOTE: The terminal examples in this book are for a Unix-like environment such as OSX or Linux. Windows users may have to make minor adaptations the commands.
In the examples in this book, we will only be scratching the surface of Leiningen’s capabilities. It is quite a capable tool for managing both Clojure and ClojureScript projects, and it has very good documentation and examples on its website. Below is a summary of the only tasks that we will use in this book. As we can see, it will not be too difficult to remember how to use these tasks.
|new||Creates a new project|
|figwheel||Automatically recompiles code and pushes live updates to a web browser|
|doo||Runs ClojureScript tests in any number of browsers|
Summary of key Leiningen Tasks
- Create a new Leiningen project called
Creating a Project
Now that we have had a whirlwind tour of Leiningen, let’s dive in and create our
first simple project, a weather forecasting app. Since we will be using Figwheel
to automatically compile and code in the browser as we make changes, we can make
use of a Leiningen template, which is a blueprint for the files and directory
structure to create. By default there are several built-in templates for
generating Clojure applications and Leiningen projects, but we can specify other
templates as well. When invoking
lein new with a template name, Leiningen will
check to see if the template is a built-in one or one that is available locally.
If it cannot find a built-in or local template, it will try to find the
appropriate template from a central repository, download it, and generate our
Leiningen Template Resolution
The Figwheel project provides a template that generates a ClojureScript project with all the plumbing required for live reloading. We will be using the Reagent library for building the UI, and thankfully the Figwheel template allows us to pass an additional option to include Reagent boilerplate code in the generated project. We can now create the project for our app.
$ lein new figwheel cljs-weather -- --reagent
Since this command includes some unfamiliar syntax, let’s take a moment to
dissect it. As we just learned, the first part of the command,
figwheel, creates a new project using the
figwheel template. Since
is not a built-in template, and we probably have not created a template by that
name locally, Leiningen will fetch the template from Clojure’s central
repository, Clojars. The remaining portion of
the command is passed to the template. By convention, the next argument
(“cljs-weather” in our case) is the name of the project and is used to
determine the name of the project’s directory and top-level namespace. Templates
also commonly use the project name in a
README or other generated files. There
is no convention for the remaining arguments, but templates commonly allow users
to supply a number of additional flags. In the documentation for the Figwheel template, the author
indicates that for clarity’s sake, we should separate template-specific options
from the rest of the command by a
--. The final argument that we pass in is
--reagent, indicating that we want the template to generate code for
the Reagent framework. We’ll be using both Figwheel and Reagent extensively
through the course of this book.
lein new Command
Exploring the Project
We now have a running (albeit skeletal) ClojureScript project. To see the application that Leiningen generated, we can navigate into the project directory and see what files were generated.
$ cd cljs-weather $ tree -a <1> . ├── .gitignore ├── README.md ├── project.clj ├── resources <2> │ └── public │ ├── css │ │ └── style.css │ └── index.html └── src <3> └── cljs_weather └── core.cljs
Exploring the Generated Project
- View the contents of the project directory recursively
resourcesdirectory contains the HTML page that will load our application as well as any styles and assets we need.
srcdirectory contains ClojureScript sourc code
Leiningen generated several top-level files, a
src directory, and a
directory. Leiningen uses the
project.clj file for all configuration that it
needs, including project metadata (name, version, etc.), dependencies, and
ClojureScript compiler options. This file is the equivalent of
build more applications in Section 3. For now, we only need to know how it is
used. Finally, the .gitignore file will exclude all of the local files the
Leiningen, the ClojureScript compiler, or figwheel might generate. All things
considered, this is quite a bit of boilerplace that was handled by a single
src directory contains all of the ClojureScript source files for our
project. Usually, there will be a single folder under
src that shares the same
name as our project, and under this folder, there can be any number of
files and other folders. If we open
core.cljs in a text editor or IDE that
supports ClojureScript 1, we will see something like this:
core.cljs with Emacs
We will dig in to the rest of this file over the next couple of lessons, as we
start to build out the weather forecasting app. For now, we will look at the
namespace declaration at the top of the file, since it is closely tied to the
structure of the project. Each ClojureScript file contains a single namespace,
which is simply a collection of data and functions. The namespace is the unit of
modularity in ClojureScript. If we open up the
core.cljs file that was
created, we can see the namespace declared on the first line:
cljs-weather.core ...). The ClojureScript compiler uses a simple naming
convention for namespaces based on the name of the file that houses them:
- Take the file path relative to the source directory
- Replace the path separator (“/” on Unix-like systems and “\” on Windows) with a dot, “.”
- Replace hyphens, “-”, with underscores “_”
Filename to Namespace Convention
Hyphen or Underscore?
One detail that sometimes trips up newcomers to ClojureScript is the fact that we name directories in the project with underscores but we name namespaces with hyphens. This is a convention borrowed from Clojure, which compiles namespaces into Java classes, naming the classes according to their file path. Since hyphens are not allowed in Java class names, they are not allowed in the file paths either. ClojureScript follows Clojure’s lead and requires that hyphens in a namespace be converted to underscores in the filesystem path. It is a quirk, but it is one that is easy to live with once we are aware of it.
resources/ directory contains all of the assets that we need to serve a
website, including an
index.html, a stylesheet (which is empty by default),
and once we build our project, it will additionally contain all of the compiled
index.html with a
file that will load our application as well as all of its dependencies. This is
fine for development, but when it comes time to deploy, we probably want to
compile all of the modules from our code and everything that it depends on into
a single file so that we can compress it more effectively and transfer it in a
- What file would you change to tweak the markup of the page that will load your app?
- What file would you change to add project dependencies?
- What file would you create to add a
We already get a taste on ClojureScript’s focus on simplicity: bootstrapping a
new project did not create dozens of files full of boilerplate code; it only
created 4 project-related files, plus a
.gitignore and a README. The amazing
thing is that we really do not need more than this to start a new project.
ClojureScript development focuses on building incrementally from a
Visit Leiningen’s website and explore what you can do with it. Remember that Leiningen is a build tool for both ClojureScript and Clojure (JVM), so some of the instrution is geared towards Clojure. Here are a few exercises to help understand what Leiningen does for you:
- Create a new leingen project from the mies template and see what (if anything) is different from the project that we generated.
- Replicate the files that Leiningen generated by hand. Was it difficult?
- Write out the name of each of the files that was generated and explain the purpose of each.
In this lesson, we have walked through the process of creating a new ClojureScript project from scratch. We were introduced to Leiningen, the most widely-used ClojureScript build tool, and we explored the project structure that it generated for us. Next, we will learn about Figwheel, the other core tool that will enable us to receive immediate feedback while we are developing. After that, we will be able to jump in with both feet and start writing code. We now know:
- How to set up a brand new ClojureScript project using Leiningen
- What sort of tasks are handled by the Leiningen build tool
- How a typical ClojureScript project is laid out
- Most programmers’ text editors have a Clojure language package that can be used for ClojureScript, but if you prefer working with IDEs, Cursive is by far the most fully featured Clojure(Script) IDE available. [return]