How can I create a ClojureScript web app from scratch with Reagent and npm?
Tags: clojurescript, npm, reagent
Published: 2021-11-18 17:27:34

---
title: How can I create a ClojureScript web app from scratch with Reagent and npm?
published: true
date: 2021-11-17 02:00:00 UTC
tags: clojurescript,npm,reagent
canonical_url: https://curiousprogrammer.dev/blog/how-can-i-create-a-clojure-script-web-app-from-scratch-with-reagent-and-npm/
---

The goal of this guide is to create a basic Reagent **ClojureScript** web app from scratch using the **Clojure CLI** tools. We are going to bundle our JavaScript using **Webpack** , have HMR (Hot Module Replacement - reload components while coding) using **Figwheel-Main** and play around with a few npm packages like **axios** and **moment**.

In a nutshell:

- ClojureScript with Clojure CLI
- Reagent
- Figwheel-Main
- Webpack
- npm packages

> You can download the [repository](https://github.com/cbillowes/cljs-app-from-scratch) from GitHub.

> This guide is a combination of tutorials I have read and videos I have watched. The biggest influencer's have been Between Two Parens, PurelyFunctional.tv and the official Figwheel documentation.

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#version-of-things-used-in-this-guide)Version of things used in this guide

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#java)Java

I have the following version of Java on macOS Monterey, Apple M1 Pro.

```
openjdk 11.0.13 2021-10-19
OpenJDK Runtime Environment Temurin-11.0.13+8 (build 11.0.13+8)
OpenJDK 64-Bit Server VM Temurin-11.0.13+8 (build 11.0.13+8, mixed mode)
```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#clojurescript)ClojureScript

| Dependency | Version |
| --- | --- |
| Clojure CLI | 1.10.3.1020 |
| ClojureScript | 1.10.879 |
| Figwheel-Main | 0.2.15 |
| Reagent | 1.1.0 |

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#nodejs)Node.js

| Dependency | Version |
| --- | --- |
| Node | 16.13.0 |
| npm | 8.1.3 |
| Webpack | 5.64.1 |
| Webpack-cli | 4.9.1 |
| React | 17.0.2 |
| React-DOM | 17.0.2 |

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#start-a-new-project)Start a new project

1. Create a new directory. In this guide we will use the very original project name `example-app`:

2. Create the file structure.

> Note how spaces are separated by an underscore in the file name. The namespace will be an exact replicate of the file path but the names will contain hyphens instead of underscores. Eg. `example_app` will become `example-app`.

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#initialize-your-project)Initialize your project

1. Initialize an npm project.

2. Initialize a Git repository and add your `.gitignore` file.

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#install-webpack)Install Webpack

1. Install Webpack.

2. Add the npm packages to play around with

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#install-reagent)Install Reagent

Install React.

```
npm install react@17.0.2 react-dom@17.0.2
```

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#update-your-files)Update your files

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#resourcespublicindexhtml)resources/public/index.html

A host page is the HTML page that includes your ClojureScript script. Figwheel provides a default host page which will be replaced with the one below.

```
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Example Application</title>
    <!--
      The stylesheet will need to be available on the classpath.
      A good place for this file would be at resources/public/path/to/style.css.
    -->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <!-- This will be swapped out by the content of our app -->
    <div id="app"></div>
    <!--
      Hardcoded Development Webpack Bundled JavaScript.
      Place the ClojureScript script tag as the last tag in the body.
      This is the convention for Google Closure compiled projects.
      https://figwheel.org/docs/your_own_page.html
    -->
    <script type="text/javascript" src="cljs-out/dev/main_bundle.js"></script>
  </body>
</html>

```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#resourcespublicstylecss)resources/public/style.css

An optional asset that can be added to your resources and referenced on your host page above.

```
body {
  color: #cc0000; /* because why not */
}
```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#srcexample_appcorecljs)src/example\_app/core.cljs

Entry point to the ClojureScript app.

```
(ns example-app.core
  (:require [reagent.dom :as r.dom]
            [axios]
            [moment]))

;; Use mock REST API to get data to output to the browser
(-> (.. axios (get "https://jsonplaceholder.typicode.com/todos/1"))
    (.then #(js/console.log %)))

;; Display the day of the week
;; https://momentjs.com/docs/
(js/console.log (.format (moment) "dddd"))

(defn app []
  [:div
   [:h1 "Example application"]])

(r.dom/render [app] (js/document.getElementById "app"))

```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#devcljsedn)dev.cljs.edn

Build file for Figwheel.main.

```
^{:auto-bundle :webpack ;; https://figwheel.org/docs/npm.html
  :watch-dirs ["src"]
  :css-dirs ["resources/public"]}

{;; root namespace for the compiled artifact.
 :main example-app.core

 ;; :none does not produce a single self-contained compiled artifact,
 ;; like with :whitespace, :simple or :advanced,
 ;; but rather creates an artifact that loads all of the separately
 ;; compiled namespaces.
 :optimizations :none

 ;; https://figwheel.org/docs/npm.html
 ;; instruct compiler to produce the bundled JavaScript file.
 :target :bundle

 ;; bundles up main.js and pulls in npm dependencies.

 ;; :output-to is replaced with ./target/public/cljs-out/dev/main.js
 ;; it is the path to the JavaScript file that will be output
 ;; needs to point to a path that is basically the classpath + public.

 ;; :final-output-dir is replaced with ./target/public/cljs-out/dev
 ;; :final-output-filename is replaced with main_bundle.js
 :bundle-cmd {:none ["npx" "webpack" "--mode=development"
                     "--entry" :output-to
                     "--output-path" :final-output-dir
                     "--output-filename" :final-output-filename]

              :default ["npx" "webpack" "--mode=production"
                        "--entry" :output-to
                        "--output-path" :final-output-dir
                        "--output-filename" :final-output-filename]}}

```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#depsedn)deps.edn

User level aliases, dependency management and Clojure CLI configuration for deps.edn based projects.

```
{:paths
 [:src-paths :resources-paths :output-paths]

 :deps {org.clojure/clojurescript {:mvn/version "1.10.879"}
        com.bhauman/figwheel-main {:mvn/version "0.2.15"}
        reagent/reagent {:mvn/version "1.1.0"}}

 :aliases
 {:src-paths ["src"]
  :resources-paths ["resources"]
  :output-paths ["target"]
  :dev
  {:main-opts ["--main" "figwheel.main"
               "--build" "dev"
               "--repl"]}}}

```

### [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#ignore-more-files)Ignore more files

Add the following to your `.gitignore` file.

```
# Cached classpath and the runtime basis files
.cpcache

# Output of the ClojureScript compiler
target
```

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#run-the-web-app)Run the web app

Now that everything is set up, you can run the web app. Enter `clj -M:dev` in the terminal to open the app on [http://localhost:9500](http://localhost:9500)

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#final-project-layout)Final project layout

Read more about Figwheel [classpaths](https://figwheel.org/docs/classpaths.html).

```
├── node_modules
├── resources
│ └── public
│ # web assets HTML, CSS, images, etc
├── src
│ ├── example_app
│ │ └── core.cljs
│ │ # other source files
├── target
| └── public
| # compiled ClojureScript files
├── .gitignore
├── deps.edn
├── dev.cljs.edn
├── package.json
├── package-lock.json
```

## [<svg aria-hidden="true" height="20" version="1.1" viewbox="0 0 16 16" width="20"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg>](#resources)Resources

- Official Clojure [Documentation](https://clojure.org/guides/getting_started)
- Official Figwheel [Documentation](https://figwheel.org/)
- Official [Documentation](https://cljdoc.org/) for Clojure/Script libraries
- Official ClojureScript with Webpack [Documentation](https://clojurescript.org/guides/webpack)
- Get started with CLJS + Figwheel-Main [YouTube Video](https://youtu.be/7b5114xE_GA) from Between Two Parens
- Start a ClojureScript App from Scratch [Article](https://betweentwoparens.com/blog/start-a-clojurescript-app-from-scratch/) by Between Two Params
- ClojureScript [Tutorial][purely-functional-clojure-tutorial] by PurelyFunctional.tv
- Learn ClojureScript [eBook](https://www.learn-clojurescript.com/) by Andrew Meredith
- ClojureScript + Reagent [Tutorial](https://purelyfunctional.tv/guide/reagent/) at PurelyFunctional.tv
- Clojure Projects from Scratch [Guide](https://oli.me.uk/clojure-projects-from-scratch/) by Oliver Caldwell
- Clojure `deps.edn` [Guide](https://github.com/practicalli/clojure-deps-edn) on GitHub by Practicalli