ClojureScript + Firebase
I'll talk about ClojureScript and Firebase. I use next libraries:
- shadow-cljs ... a build tool
- reagent ... React wrapper
- firebase npm library
Setup a project
First of all, I generate a shadow-cljs project:
npx create-cljs-project cljs-firebase
Its results:
cd cljs-firebase
tree -a -I node_modules .
.
├── .gitignore
├── package-lock.json
├── package.json
├── shadow-cljs.edn
└── src
├── main
└── test
Next, I edit a shadow-cljs.edn
:
;; shadow-cljs configuration
{:source-paths
["src/dev"
"src/main"
"src/test"]
:dependencies
[[binaryage/devtools "1.0.2"]
[reagent "1.0.0"]]
:builds
{:app {:target :browser
:output-dir "public/js"
:asset-path "/js"
:modules
{:main
{:entries [cljs-firebase.core]}}
:devtools
{:http-root "public"
:http-port 8080
:preloads [devtools.preload]}
:release
{:output-dir "dist/js"}}}}
And, I edit a package.json
:
{
"name": "cljs-firebase",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "shadow-cljs watch app"
},
"devDependencies": {
"shadow-cljs": "2.11.11"
},
"dependencies": {}
}
OK. I finished to set up a shadow-cljs, so I run the next command:
$ npm run dev
> cljs-firebase@0.0.1 dev /home/kbaba/repos/cljs-firebase
> shadow-cljs watch app
shadow-cljs - config: /home/kbaba/repos/cljs-firebase/shadow-cljs.edn
shadow-cljs - updating dependencies
Retrieving thheller/shadow-cljs/2.11.11/shadow-cljs-2.11.11.pom from https://repo.clojars.org/
Retrieving reagent/reagent/1.0.0/reagent-1.0.0.pom from https://repo.clojars.org/
Retrieving cljsjs/react/17.0.1-0/react-17.0.1-0.pom from https://repo.clojars.org/
Retrieving cljsjs/react-dom/17.0.1-0/react-dom-17.0.1-0.pom from https://repo.clojars.org/
Retrieving cljsjs/react-dom-server/17.0.1-0/react-dom-server-17.0.1-0.pom from https://repo.clojars.org/
Retrieving cljsjs/react-dom-server/17.0.1-0/react-dom-server-17.0.1-0.jar from https://repo.clojars.org/
Retrieving thheller/shadow-cljs/2.11.11/shadow-cljs-2.11.11-aot.jar from https://repo.clojars.org/
Retrieving reagent/reagent/1.0.0/reagent-1.0.0.jar from https://repo.clojars.org/Retrieving
cljsjs/react-dom/17.0.1-0/react-dom-17.0.1-0.jar from https://repo.clojars.org/
Retrieving cljsjs/react/17.0.1-0/react-17.0.1-0.jar from https://repo.clojars.org/
shadow-cljs - dependencies updated
running: npm install --save --save-exact react@17.0.1 react-dom@17.0.1
+ react@17.0.1
+ react-dom@17.0.1
added 5 packages from 2 contributors and audited 104 packages in 2.176s
3 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
shadow-cljs - HTTP server available at http://localhost:8080
shadow-cljs - server version: 2.11.11 running at http://localhost:9630
shadow-cljs - nREPL server started on port 27730
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build failure:
The required namespace "cljs-firebase.core" is not available.
The command setups dependencies, builds the system and runs a server at http://localhost:8080
. But, I didn't write any code, so the build was failure now. I will fix those errors.
I type ctrl+c
to finish npm run dev
and run the next commands:
$ mkdir src/main/cljs-firebase
$ touch src/main/cljs-firebase/core.cljs
I edit src/main/cljs-firebase/core.cljs
:
(ns cljs-firebase.core
(:require [reagent.dom :as rdom]))
(defn view []
[:div "hello world"])
(defn mount-root []
(let [root-el (.getElementById js/document "app")]
(rdom/unmount-component-at-node root-el)
(rdom/render view root-el)))
(defn ^:export init []
(mount-root))
I rerun npm run dev
$ npm run dev
> cljs-firebase@0.0.1 dev /home/kbaba/repos/cljs-firebase
> shadow-cljs watch app
shadow-cljs - config: /home/kbaba/repos/cljs-firebase/shadow-cljs.edn
shadow-cljs - HTTP server available at http://localhost:8080
shadow-cljs - server version: 2.11.11 running at http://localhost:9630
shadow-cljs - nREPL server started on port 38281
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build completed. (173 files, 0 compiled, 0 warnings, 7.39s)
And, I open a browser and access http://localhost:8080
Initialize Firebase
I install firebase
npm install --save firebase
And, I create a next file:
; src/main/cljs_firebase/firebase/init.cljs
(ns cljs-firebase.firebase.init
(:require ["@firebase/app" :refer (firebase)]))
(defn initialize-firebase []
(if (zero? (count (.-apps firebase)))
(-> firebase
(.initializeApp
#js {:apiKey "..."
:authDomain "..."
:databaseURL "..."
:projectId "..."
:storageBucket "..."
:messagingSenderId "..."
:appId "..."}))
(.-app firebase)))
We can use npm packages by using ""
at :require
, so I wrote ["@firebase/app" :refer (firebase)]
. And, I initialize Firebase by config in Firebase SDK snippet.
I edit src/main/cljs_firebase/core.cljs
:
(ns cljs-firebase.core
- (:require [reagent.dom :as rdom]))
+ (:require [reagent.dom :as rdom]
+ [cljs-firebase.firebase.init :refer [initialize-firebase]]))
(defn view []
[:div "hello world"])
@@ -10,4 +11,5 @@
(rdom/render view root-el)))
(defn ^:export init []
+ (initialize-firebase)
(mount-root))
Next, I will connect to Firestore.
Connect to Firestore
I make a next file:
; src/main/word_penne/firebase/firestore.cljs
(ns cljs-firebase.firebase.firestore
(:require ["@firebase/app" :refer (firebase)]
["@firebase/firestore"]))
(defn firestore []
(.firestore firebase))
And I edit src/main/cljs_firebase/core.cljs
(ns cljs-firebase.core
(:require [reagent.dom :as rdom]
[reagent.core :as r]
[cljs-firebase.firebase.init :refer [initialize-firebase]]
[cljs-firebase.firebase.firestore :refer [firestore]]))
(def todos (r/atom [{:task "aaa"}]))
(defn set-todos [val]
(reset! todos val))
(defn load-todos-from-firestore []
(-> (firestore)
(.collection "todo")
(.get)
(.then
(fn [snapshot]
(let [result (r/atom [])]
(.forEach snapshot
(fn [doc]
(swap! result conj
(conj {:uid (.-id doc)}
(js->clj (.data doc) :keywordize-keys true)))))
(set-todos @result))))))
(defn view []
[:div "hello world"
[:ul
(js/console.log @todos)
(for [todo @todos]
[:li (:task todo)])]])
(defn mount-root []
(let [root-el (.getElementById js/document "app")]
(rdom/unmount-component-at-node root-el)
(rdom/render view root-el)))
(defn ^:export init []
(initialize-firebase)
(load-todos-from-firestore)
(mount-root))
conclusions
I connected to Firebase and got data. Because I used npm packages directly, the system is easy to maintain. And, we can use Firebase Authentication, Functions, etc.
I made a system by using those and Reagent, re-frame, stylefy, etc.
Top comments (1)
nice article! I think you forgot to put index.html code and where it will be