In this chapter:
- 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
$ 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 command,
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 run
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.
||Creates a new project|
||Automatically recompiles code and pushes live updates to a web browser|
||Runs ClojureScript tests in any number of browsers|
- Create a new Leiningen project called
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 project.
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,
lein new figwheel, creates a new project using the
figwheel template. Since
figwheel 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 a flag,
--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
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
- 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
resources 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
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
*.cljs 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 chapters, 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:
(ns 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
- 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 chapter, 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. ↩