Developing Ionic applications with Clojurescript
1. Note
This blog post is a part of a series of blog posts about developing Clojurescript application using Ionic framework.
2. What is Ionic?
Ionic is a supposedly cross-platform development framework which allow developing web, mobile and desktop applications. It uses web based tech stack, and is a good candidate to try to use it with Clojurescript.
3. Before you begin
This post describes a way of developing Ionic Clojurescript application using standard Ionic tooling. While certainly doable, it provides no clear benefits of using Clojure REPL.
If you are iterested in developing Ionic application using Clojurescript tooling and shadow-cljs
with all the benefits it brings with it, check the next post about better approach.
4. Install required software
Make sure you have nodejs
, npm
and git
installed.
Follow the official installation guide to instal Ionic.
npm install -g @ionic/cli
5. Create a new Ionic project
After installing preerquisites you may create a new Ionic project from commandline.
ionic start
For the purpose of this blog post I used react
as a framework of choice and blank
template. I named the project cs-starter
.
You can verify if the project is created by starting it and playign around.
cd cs-starter
ionic serve
This will start a newly created application on http://localost:8100 You may start and play with it a bit.
Once we verified the app works we can proceed further.
6. Replace JavaScript with Clojurescript
First get rid of the existing Javascript (Typesrcipt) source. Delete everything from the src
folder.
mv src src_ # or outhright delete # rm -rf src mkdir src
Now, we'll need to set up our clojurescript build using shadow-cljs.
Create shadow-cljs.end
configuration file with the following content.
{:deps true :nrepl {:port 7002} :builds {:app {:target :react-native :init-fn cs-starter.core/init :output-dir "src/app" :devtools {:autoload true ;; :after-load steroid.rn.core/reload }}}}
Since we are using deps
to manage Clojure dependencies, we'll need to set it up too using deps.edn
{:deps {org.clojure/clojure {:mvn/version "1.10.3"} org.clojure/clojurescript {:mvn/version "1.11.4"} thheller/shadow-cljs {:mvn/version "2.17.2"} reagent/reagent {:mvn/version "1.1.0" :exclusions [cljsjs/react cljsjs/react-dom]} re-frame/re-frame {:mvn/version "1.2.0"} } :paths ["clj"]}
Our source code will be located in clj
folder. Create a folder, and inside it create a file with our source. File name should be core.cljs
and located in the folder clj/cs_starter/
which corresponds to our cs-starter.core
package.
(ns cs-starter.core (:require react [reagent.core :as reagent] [reagent.dom :as rdom] ["react-dom" :as rd] ["@ionic/react" :as ir] ["@ionic/react-router" :as irr] ["react-router-dom" :as rrd])) (defn home [] [:> ir/IonPage [:> ir/IonHeader [:> ir/IonToolbar [:> ir/IonTitle "Blank"]]] [:> ir/IonConten {:fullscreen true} [:> ir/IonHeader {:collapse "condense"} [:> ir/IonToolbar [:> ir/IonTitle {:size "large"} "Blank"]]]]]) (defn app-root [] [:> ir/IonApp [:> irr/IonReactRouter [:> ir/IonRouterOutlet [:> rrd/Route {:exact true :path "/home"} "Home"] [:> rrd/Route {:exact true :path "/"} "Root"]]]]) (defn init [] (println "init started") (ir/setupIonicReact) (rdom/render app-root (.getElementById js/document"root")) (println "init done"))
Now, create an index.js
file in `src` folder that will set up CSS imports and hook up our code.
/* Core CSS required for Ionic components to work properly */ import '@ionic/react/css/core.css'; /* Basic CSS for apps built with Ionic */ import '@ionic/react/css/normalize.css'; import '@ionic/react/css/structure.css'; import '@ionic/react/css/typography.css'; /* Optional CSS utils that can be commented out */ import '@ionic/react/css/padding.css'; import '@ionic/react/css/float-elements.css'; import '@ionic/react/css/text-alignment.css'; import '@ionic/react/css/text-transformation.css'; import '@ionic/react/css/flex-utils.css'; import '@ionic/react/css/display.css'; /* Our Compiled Clojurescript application code" */ import "./app/index.js"
7. Testing
Now you need to compile project using shadow-cljs.
npx shadow-cljs watch app
It takes a while for code to be initially compiled to javascript. From now on, shadow-cljs will watch for modification of the source code and automaticaly compile and reload all the changes.
Now you should be able to start project using ionic serve
, go to http://localhost:8100 and see an application home screen.
Whenever you save files, shadow-cljs will detect chahnges, compile it, and browser will relead it.
8. Troubleshooting
If you see a bunch of errors when you start your aplication, it may be due to the way Ionic Typescript compiler is configured. Since we don't care about Typescript here, we can remove it from the project.
Open tsconfig.json
file and change the value of strict
from true
to false
.
Open package.json
and find eslintConfig
section that looks something like this:
"eslintConfig": { "extends": [ "react-app", "react-app/jest" ] },
Remove the complete section. We don't need it.
9. Source code
10. What's next?
Now you are ready to start developing your Ionc application using familiar Clojurescript tools like reagent and re-frame.
So far I have only played with web part. For me nexp step would be to play a bit more with the Ionic support for mobile and progressive applications using their Capacitor framework.
You can also check the second part of the tutorial that shows how to build a todo application in the next post and eliminate some of the pain points of the aproach take in this blog post.