A simple full-stack clojure app
Learn more about clojure project structure.
Checkout the live demo.
This is a simple fullstack clojure application developed to explain how to deploy a clojure app.
It consists in a backend in src/atemoia/server.clj. This backend has JSON and HTML endpoints
A frontend in src/atemoia/client.cljs. This is a react app interacts with the JSON endpoints.
There is a build script in dev/atemoia/build.clj. This is invoked via clj -M:dev -m atemoia.build
The build script compiles clojurescript to a minified bundle and compiles clojure to java classes. Then generates a JAR file that include both java class files and javascript static assets.
There is a Dockerfile that uses node:alpine image to install npm dependencies.
Then use clojure:alpine image to compile and create the jar file.
Then create an openjdk:alpine image with just the jar file as "final product".
Heroku operates in container mode, as described in heroku.yml.
There is a github integration that triggers the deploy process.
Before start, install your npm dependencies with npm run ci
You can start your REPL using clj -M:dev
In the repl, require the server namespace: (doto 'atemoia.server require in-ns).
Call (dev-main) and after some seconds the application should be available in localhost:8080.
You will need a postgresql server running
docker run --name my-postgres --env=POSTGRES_PASSWORD=postgres --rm -p 5432:5432 postgres:alpineYou can change src/atemoia/server.clj and run (require 'atemoia.server :reload) to see your changes.
Some changes (in the HTTP server) will need to call (dev-main) again
Changes in src/atemoia/client.cljs are hot reloaded.
You will never need to restart your REPL.
This namespace has a single -main function that when called, generate a jar file in target/atemoia.jar.
The jar contains everything that is listed in target/classes. This directory will only exists after you call this
function.
The function will
- Delete the
targetdir - Start
shadow-cljsserver, generate a production bundle ofatemoia.clientintarget/classes/public, as described inshadow-cljs.edn, stopshadow-cljsserver - Write the
pomfile and othersjarmetadata files intarget/classes/META-INF - Compile every clojure namespaces found in
srcand every required dependency intotarget/classes - Create an uberjar file that has
atemoia.serveras entrypoint.
Uberjar's are not a complex thing. It's simply zip the target/classes folder into a .jar, keeping it tree
structure.
You can open the jar and compare with target/classes to have a better understanding of this process.
They should be equal.
Start a REPL as a developer
## Install npm deps
npm run ci
## Start the repl
clj -M:devSpawn a new JVM and run all tests
clojure -M:dev:test-runnerBuild a production jar
clojure -M:dev -m atemoia.buildStart a dev http server
(doto 'atemoia.server require in-ns)
(dev-main)Run all tests
(require 'clojure.test)
(clojure.test/run-all-tests)- How long will my bullet point remain here?
Up to 10 elements. This code do that.
- Why pedestal?
Is the one that I like to use. The main feature that I like that no other http server does is
the io.pedestal.test/response-for helper.
- Why not datomic?
The idea is to be easy to deploy on heroku. Heroku gives me Postgres, so I'm ok to use it.
In case of questions or errors, report an issue
If you prefer talk directly with me