{"id":13760338,"url":"https://github.com/serioga/webapp-clojure-2020","last_synced_at":"2025-08-15T13:33:27.195Z","repository":{"id":48564809,"uuid":"241106746","full_name":"serioga/webapp-clojure-2020","owner":"serioga","description":"Multi-page web application prototype with Clojure(Script)","archived":false,"fork":false,"pushed_at":"2023-10-27T13:36:11.000Z","size":657,"stargazers_count":52,"open_issues_count":2,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-08-12T18:53:09.000Z","etag":null,"topics":["clojure","clojurescript","hiccup","hikaricp","hugsql","immutant","integrant","leiningen","liquibase","multipage-website","next-jdbc","p6spy","prototype","reactjs","reitit","rum","shadow-cljs","ssr","tailwind-css","webapp"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/serioga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-02-17T12:51:02.000Z","updated_at":"2024-09-22T22:58:51.000Z","dependencies_parsed_at":"2024-08-03T13:14:45.798Z","dependency_job_id":null,"html_url":"https://github.com/serioga/webapp-clojure-2020","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/serioga/webapp-clojure-2020","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serioga%2Fwebapp-clojure-2020","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serioga%2Fwebapp-clojure-2020/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serioga%2Fwebapp-clojure-2020/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serioga%2Fwebapp-clojure-2020/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/serioga","download_url":"https://codeload.github.com/serioga/webapp-clojure-2020/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/serioga%2Fwebapp-clojure-2020/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270578402,"owners_count":24610036,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","clojurescript","hiccup","hikaricp","hugsql","immutant","integrant","leiningen","liquibase","multipage-website","next-jdbc","p6spy","prototype","reactjs","reitit","rum","shadow-cljs","ssr","tailwind-css","webapp"],"created_at":"2024-08-03T13:01:08.160Z","updated_at":"2025-08-15T13:33:26.881Z","avatar_url":"https://github.com/serioga.png","language":"Clojure","readme":"# webapp-clojure-2020\n\n## Rationale\n\nI needed project setup to support following workflow:\n\n- The application running in development mode behave like application running in production \n  (as much as possible). So all development code is addictive and excluded from production build.\n- The application state keep running and reloading automatically on changes.\n- Developer can easily extend development environment with any required tools.\n\nSo in about 2 years I've gradually built this prototype for my own needs. \n\n## Features\n\n### Project\n\n- Leiningen based project.\n- Code style settings for IntelliJ IDEA with Cursive.\n\n### System\n\n- Integrant for application and development systems.\n- Parallel start of integrant components.\n- Separate sources for application and development code.\n- Hot reloading on source files changes.\n- `mount` as integrant component for compiled dependencies in code.\n- Configuration in JAVA properties files.\n- Daemon interface to be run as service with `jsvc`.  \n\n### HTTP Server\n\n- `Immutant` web server with multiple webapps, single port, multiple hostnames.\n- Routing: `metosin/reitit`.\n- Page-rendering: `hiccup`.\n\n### Frontend\n\n- ClojureScript with Shadow CLJS (lein integration).\n- React JS + Rum + Server-side rendering (SSR) + Passing component data from server\n- Tailwind CSS\n- Reload pages without Shadow CLJS (adapted `ring-refresh`)\n\n### SQL Database\n\n- `next.jdbc` JDBC wrapper.\n- `HugSQL` “query builder”.\n- `HikariCP` connection pool.\n- Log database queries via `p6spy`.\n- Database migrations with `Liquibase`.\n- Separate read-write and read-only database connections.\n\n## Q\u0026A\n\n### Why mount _and_ integrant?\n\nDuring migration of my setup from mount to integrant I found:\n- that integrant is good for \n  - managing “big” components like web server, database connection pool and so on, \n    which don't require direct reference in the code,\n  - managing multiple systems like application and development once. \n- but passing integrant state around as map to access it from code is\n  - annoying,\n  - not so performant as mount,\n  - harder to trace dependencies in code using IDE's navigation tools.\n  \nSo I decided to take best from both worlds and use mount and integrant simultaneously.   \n\n## Installation\n\n1. OpenJDK 11 https://adoptopenjdk.net/\n2. Leiningen https://leiningen.org/\n3. Node.js https://nodejs.org/\n4. npm modules: `npm install --no-package-lock`\n\n## Usage\n\nRun for development:\n\n    lein run\n\nRun to check build with release options:\n\n    lein clean\n    lein with-profile test-release run\n\nBuild release:\n\n    lein uberjar\n    \nRun built release:\n\n    java -Dconfig.file=dev/app/config/default.props -jar ./target/uberjar/website.jar\n\n## Configuration\n\nCustom configuration properties can be placed in optional file (excluded from version control):\n\n    dev/app/config/user.props\n\nCustom configuration for the development environment can be placed in the optional file\n(excluded from version control):\n\n    dev/dev/config/user.edn\n","funding_links":[],"categories":["Clojure"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserioga%2Fwebapp-clojure-2020","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fserioga%2Fwebapp-clojure-2020","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fserioga%2Fwebapp-clojure-2020/lists"}