Setup shadow-cljs react project
Tags: reagent, react, clojurescript
Published: 2022-04-02 10:30:52

---
title: Setup shadow-cljs react project
published: true
date: 2022-03-13 16:47:16 UTC
tags: reagent,react,clojurescript
canonical_url: 
---

#### 🚀 Create project

The first step is create a project

```
npx create-cljs-project my-project
```

This command will create a project _my-project_ with minimal required structure and install required dev dependencies for proper work of shadow-cljs

```
├── package-lock.json
├── package.json
├── shadow-cljs.edn
└── src
    ├── main
    └── test
```

shadow-cljs.edn is a [configuration file](https://shadow-cljs.github.io/docs/UsersGuide.html#_basic_workflow) for ClojureScript project

```
;; shadow-cljs configuration
{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]

:dependencies
 []

:builds
 {}}
```

#### ♺ Compile ClojureScript to JavaScript

Now, let’s create an entry point ClojureScript file

```
touch ./src/main/core.cljs
```

and add minimal boilerplate code to it

```
;; ./src/main/core.cljs
(ns core)

(defn main []
  (js/console.log "Hello World!"))

(main)
```

Now we should specify how to build the project. To do this, we should modify the :builds section in _shadow-cljs.edn_ file

```
...

:builds
 {: **app** {:target : **browser**
        :modules {: **main** {:entries [**core**]}}}}}
```

- :app is a build id
- :browser is target’s type for generated JavaScript files
- :main is a name of generated JavaScript file
- core is a ClojureScript entry namespace

You can add :output-dir "public/js" to explicitly specify output directory for generated files by default shadow-cljs will use public/js

Now we can compile our ClojureScript to JavaScript files

```
npx shadow-cljs compile **app**

shadow-cljs - config: /private/tmp/my-project/shadow-cljs.edn
shadow-cljs - connected to server
[:app] Compiling ...
[:app] Build completed. (43 files, 0 compiled, 0 warnings, 0.33s)
```

#### 👾 Start server

Now we are ready to setup the development server which will serve our static files. For this, we should return back to _shadow-cljs.edn_ and add information about the dev server

```
:dev-http {8000 "public"}
```

- 8000 is a port which will be used by http server
- public is a folder name for static files

Now we can start it by using watch command

```
npx shadow-cljs **watch** app
```

Beside the start http server watchcommand also automatically recompile JavaScript files when we change ClojureScript one

You can open [http://localhost:8000](http://localhost:8000) and see that the server is running

```
Not found. Missing index.html.
```

but complains on missing index.html. Let’s add index.html to the public folder

```
touch ./public/index.html
```

and add some minimal markup with reference to our generated JavaScript file

```
<!DOCTYPE html>
<html lang="">
  <head>
    <title>my-project</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <div id="app"></div>
    <script src=" **js/main.js**" type="text/javascript"></script>
  </body>
</html>
```

If we open developer tools in the browser we should see “Hello World!” message in the browser’s console. You can open _core.cljs_ file and change the message. Browser automatically pickup the change via embedded to shadow-cljs live update functionality and display the new message

#### 📦 Add React as dependency

shadow-cljs support npm dependencies, so here we can install react via npm

```
npm install react
```

Now we can use React in our ClojureScript application. Let’s print React’s version in the browser’s console. To do this, let’s modify core.cljs file

```
;; ./src/main/core.cljs
(ns core **(:require ["react" :as react])**)

(defn main []
  (js/console.log **(.-version react)**))

(main)
```

We can look at the console without restarting the server and see that now it displays React version

```
[Log] shadow-cljs: load JS – "node_modules/react/index.js"
[Log] shadow-cljs: load JS – "core.cljs"
[Log] 17.0.2
```

By the same way, we can install react-dom and render “Hello World!”

```
(ns core (:require 
           ["react" :as react]
           **["react-dom" :as react-dom]**))

(defn main []
  **(let [app-node (.getElementById js/document "app")]  
 (.render react-dom "Hello World!" app-node))** )

(main)
```

#### 🎸 Reagent

We can use raw react and react-dom in our ClojureScript but it’s much better and less verbose to use Reagent is a minimalistic ClojureScript interface for React.

Because Reagent is a ClojureScript module, we can’t install it via npm. To install it, we should define required version in _shadow-cljs.edn_

```
:dependencies
 [**[reagent "1.1.1"]**]
```

Reagent is dependent from React & React DOM packages, so you still should install them via NPM.

Let’s update core.cljs code and replace React on Reagent

```
;; ./src/main/core.cljs
(ns core (:require 
          **[reagent.core :as r]  
 [reagent.dom :as rdom]** ))

**(defn app []  
 [:b "Hello World!"])**  

(defn main []
  (let [app-node (.getElementById js/document "app")]
    **(rdom/render [app] app-node)**))

(main)
```