I needed project setup to support following workflow:
- The application running in development mode behave like application running in production (as much as possible). So all development code is addictive and excluded from production build.
- The application state keep running and reloading automatically on changes.
- Developer can easily extend development environment with any required tools.
So in about 2 years I've gradually built this prototype for my own needs.
- Leiningen based project.
- Code style settings for IntelliJ IDEA with Cursive.
- Integrant for application and development systems.
- Parallel start of integrant components.
- Separate sources for application and development code.
- Hot reloading on source files changes.
mount
as integrant component for compiled dependencies in code.- Configuration in JAVA properties files.
- Daemon interface to be run as service with
jsvc
.
Immutant
web server with multiple webapps, single port, multiple hostnames.- Routing:
metosin/reitit
. - Page-rendering:
hiccup
.
- ClojureScript with Shadow CLJS (lein integration).
- React JS + Rum + Server-side rendering (SSR) + Passing component data from server
- Tailwind CSS
- Reload pages without Shadow CLJS (adapted
ring-refresh
)
next.jdbc
JDBC wrapper.HugSQL
“query builder”.HikariCP
connection pool.- Log database queries via
p6spy
. - Database migrations with
Liquibase
. - Separate read-write and read-only database connections.
During migration of my setup from mount to integrant I found:
- that integrant is good for
- managing “big” components like web server, database connection pool and so on, which don't require direct reference in the code,
- managing multiple systems like application and development once.
- but passing integrant state around as map to access it from code is
- annoying,
- not so performant as mount,
- harder to trace dependencies in code using IDE's navigation tools.
So I decided to take best from both worlds and use mount and integrant simultaneously.
- OpenJDK 11 https://adoptopenjdk.net/
- Leiningen https://leiningen.org/
- Node.js https://nodejs.org/
- npm modules:
npm install --no-package-lock
Run for development:
lein run
Run to check build with release options:
lein clean
lein with-profile test-release run
Build release:
lein uberjar
Run built release:
java -Dconfig.file=dev/app/config/default.props -jar ./target/uberjar/website.jar
Custom configuration properties can be placed in optional file (excluded from version control):
dev/app/config/user.props
Custom configuration for the development environment can be placed in the optional file (excluded from version control):
dev/dev/config/user.edn