Tutorial: Clojurescript App With Reagent For Beginners, Part 2

10/18/20182 Min Read — In ClojureScript

This is part 2 of my Clojurescript Reagent Tutorial. In part 1 we created a simple random quote app that displays quotes from the TV-series "Breaking Bad".

Here is the live demo: Breaking Bad Quotes.
And here is the Github Repo, so you can see the whole code (minus the sensitive login details for Firebase): Github.

Now it's time to deploy it. We will use Google Firebase for that, just to learn on how to do it.
A free plan will be enough.

Firebase offers services like a real-time database and authentication, but for our purpose we just use their hosting. But if you would like to develop apps that are more advanced, you could look into that.

Firebase Setup

EDIT: You need this if you use authentication or the database. Skip this step if you only host your app on Firebase.

Install firebase with npm or yarn.

$ npm install --save firebase

Head over to the Firebase web console and add a project. Call it "breaking-bad-quote-machine" or something like that.

Now, you need to add the web app to get started. Please check the documentation. In the Firebase web console go to Develop > Authentication , then click Web Setup.

The pop-up window will give you a snippet to connect the project to Firebase.

Back at your editor create a new folder in your src/breaking-bad-quotes directory. I called it fb for Firebase. Then create the init.cljs file.

Your file (...src/breaking-bad-quotes/fb/init.cljs) should look like this:

(ns breaking-bad-quotes.fb.init
  (:require ["firebase/app" :as firebase]))

(defn firebase-init
  []
  (firebase/initializeApp
   #js {:apiKey      "####"                    ; your apiKey from the web
        :authDomain  "###"                     ; authDomain, depends on what you called the project in the Firebase console
        :databaseURL "###"                     ; ...
        :projectId   "###"}))                  ; ...

We require the npm package in our namespace with quotes because it's an npm package (not a Clojurescript repo), then use the function "InitializeApp" with our API details.

If you use git to store your files, make sure to add init.cljs to your .gitignore`-file!

We need the firebase function in our main file.
Require it in your namespace and add it into the init function in src/core.cljs.
Your complete file now looks like this:

(ns breaking-bad-quotes.core
  (:require [reagent.core :as r :refer [atom]]
            [ajax.core :refer [GET]]
            [breaking-bad-quotes.fb.init :refer [firebase-init]]))

(defn fetch-link! [data]
  (GET "https://breaking-bad-quotes.herokuapp.com/v1/quotes"
    {:handler #(reset! data %)
     :error-handler (fn [{:keys [status status-text]}]
                      (js/console.log status status-text))}))

(defn quote []
  (let [data (atom nil)]
    (fetch-link! data)
    (fn []
      (let [{:strs [quote author]} (first @data)
            tweet-intent (str "https://twitter.com/intent/tweet?hashtags=breakingbad&text=" quote " ~ " author)]
        [:div.cards>div.card
         [:h2.card-header.text-center "Breaking Bad Quotes"]
         [:div.card-body.text-center
          [:p#quote (or quote "Loading... please wait")]
          [:p#author author]]
         [:div.card-footer.center.text-center
          [:button#twitter.outline>a#tweet
           {:href tweet-intent
            :target "_blank"}
           [:i.fi-social-twitter " Tweet"]]
          [:button#new-quote.outline
           {:on-click #(fetch-link! data)}
           [:i.fi-shuffle " New Quote"]]]]))))

(defn start []
  (reagent/render-component [quote]
                            (. js/document (getElementById "app"))))

(defn ^:export init []
  ;; init is called ONCE when the page loads
  ;; this is called in the index.html and must be exported
  ;; so it is available even in :advanced release builds
  (start)
  (firebase-init))

(defn stop []
  ;; stop is called before any code is reloaded
  ;; this is controlled by :before-load in the config
  (js/console.log "stop"))

Ok, now we need to prepare our app for the web. In your terminal:

$ shadow-cljs release app

Install firebase-tools

Use npm or yarn to install firebase-tools.

$ npm install -g firebase-tools

Then init and deploy.

$ firebase init

This opens up a command-line style interface. Select "Hosting" (use the space key) and go from there.
Select the project you've set up with the Firebase console.

shadow-cljs compiles your Clojurescript code into Javascript code in the public directory.
Just hit enter when Firebase asks for your public directory, the default choice is the correct option.

You don't need to reconfigure your app as an SPA, because there's a only a HTML-file. Choose N.
Don't let Firebase overwrite your HTML-file.

Afterward,

$ firebase deploy

Sit back and enjoy.

Kudos

Many thanks to Jacek Schae and his course Learn Reagent as well as Dmitri Sotnikov for his book Web Development with Clojure, 2nd Edition.