I must admit I don’t fully understand what challenges you are facing. So I’m going to do a brave/stupid thing and just generally talk into this space based on what I think I understand and one or two things I’ve tried before. I hope it’s useful.
Generally, UI’s and backends are treated as “separate” projects. The UI (often React or Vue) are kept in separate source control repositories, apart from the backend project. The issue with this is that when it comes to run time, the UI and the backend are actually the same software stack. Ideally even, you want your backend to host the static assets of the frontend (ie have ring serve the
.css files from resources). It’s not strictly speaking necessary to host the UI assets from the uberjar, but it makes the job of your devops team slightly easier.
shadow-cljs) or something; there are usually tools like PostCSS involved, you mention webpack etc. These are not integrated with
boot (and I don’t think they should be). Embrace and extend as they say…
postcss --watch -type processes kick off, new assets are generated. This dev-time HTTP server usually has a websocket or something that then notifies the UI and a reload happens. It’s super convenient.
So with all of this in mind, I’ve structured a few projects like below and it worked for me:
- I host my UI and backend code in the same source repo, because I can symlink the output folder of the js build process into my clojure resources. I then have an HTTP route in clj that knows to serve those assets from there.
- I structure my UI code to load a settings file from
/settings.edn. This settings file contains high-level configuration, but usually at least the UI logging level and the protocol, host & port of the backend “API” service, eg
http://localhost:8000. I create a static settings file for dev-time that contains the correct assumptions (port) about dev-time and then I have the clojure backend craft a settings file at runtime that points back to itself. Often one of the configuration values you need to give an HTTP service as the “public URL”. This is the value I put in the settings file served to the UI.
This setup allows me to start the clojure repl and service, start the js tooling, have all the niceties of hot-reloading for dev on the UI (and on the backend…) and still have the benefits of a self-contained deployable for prod/run-time.
There are other benefits too. Usually business stakeholders realise (or communicate) too late about whitelabeling user-interfaces. This setup with the
settings.json file allows to statically deploy customized versions of the UI to separate UI domains, and have them all use the same backend.
Anyway - this is what came to mind when you asked about unifying frontend and backend work.