Project Setup
In this chapter, we will bootstrap a project using create-cljs-app and understand the code generated. We'll also study Hiccup, a CLJS alternative for JSX, and various ways to require namespaces.
We have already learned how to set up Shadow projects manually. We have also used the first-project
for code examples in the last module. Unlike first-project
Tinycanva will run in the browser instead of a Node terminal. So, to get the REPL working, we'll need to open the app in a browser, in place of running the node script in the shell.
Create a new project#
The app we are going to build is called Tinycanva. We'll use create-cljs-app
to bootstrap the project:
yarn create cljs-app tinycanva
# or npx create-cljs-app tinycanva
In time, we'll make changes to the template project. create-cljs-app
automatically installs some modules that we'll cover in this chapter.
Once done, you should see a directory named tinycanva
with the following contents:
$ tree -I node_modules
.
└── tinycanva
├── README.md
├── package.json
├── public
│ ├── css
│ │ └── style.css
│ ├── favicon.ico
│ └── index.html
├── shadow-cljs.edn
├── src
│ ├── app
│ │ ├── cards.cljs
│ │ ├── core.cljs
│ │ ├── hello.cljs
│ │ └── hello_cards.cljs
│ └── e2e
│ └── core.cljs
└── yarn.lock
6 directories, 12 files
The files and directories created by create-cljs-app
might feel overwhelming at first. Let's break it down so we understand what's happening.
Understanding Shadow configuration#
The automatically-generated Shadow config should look similar to this:
{:builds
{:app {:asset-path "/js"
:modules {:main {:init-fn app.core/main}}
:output-dir "public/js"
:target :browser}
:cards {:asset-path "/js"
:modules {:main {:init-fn app.cards/main}}
:compiler-options {:devcards true}
:output-dir "public/js"
:target :browser}
:test {:ns-regexp "app.cards"
:output-to "out/test.js"
:target :node-test}
:e2e {:ns-regexp "e2e.*"
:output-to "out/e2e.js"
:target :node-test}}
:dependencies [[reagent "0.8.1"]
[devcards "0.2.6"]]
:dev-http {3000 "public"}
:nrepl {:port 3333}
:source-paths ["src"]}
By default, we have four builds:
a development server configured to run on port 3000 serving contents from the
public
directorya nREPL server configured on port 3333 and one source path
src
two dependencies that we'll learn about in detail soon: - Reagent: a minimalist Clojure wrapper for React - Devcards: a StoryBook-like tool for developing components in isolation
As of now, we should only be concerned with the :app
build target. The other build targets i.e. :test
, :e2e
, and :cards
are meant for testing the app.
The :app
build target is configured to call app.core/main
function on startup, target the browser runtime and spit JavaScript code to public/js
. Let's check the main
function definition.
The main
function#
As we learned before, the function defined as :init-fn
is called as soon as the app is ready. The generated app.core
namespace is:
(ns app.core
"This namespace contains your application and is the entrypoint for 'yarn start'."
(:require [reagent.core :as r]
[app.hello :refer [hello]]))
(defn ^:dev/after-load render
"Render the toplevel component for this app."
[]
(r/render [hello] (.getElementById js/document "app")))
(defn ^:export main
"Run application startup logic."
[]
(render))
This page is a preview of Tinycanva: Clojure for React Developers