Borkweb is an effort to create a full-stack Clojure framework that is simple, minimal and traditional. I believe that the complexity and overhead of modern web development frameworks have made it difficult for developers to focus on building great applications. Our goal is to provide a tool that allows developers to work efficiently and effectively, without getting bogged down in unnecessary configurations and integrations.
I didn't create Borkweb as a proof-of-concept or a side project. I created it because I needed it. I was building real applications and was frustrated with the complexity and overhead of existing frameworks. I wanted a tool that would allow me to focus on building great applications, without getting bogged down in unnecessary configurations and integrations. Borkweb is the result of my efforts, and I've been using it in production for my own applications.
Borkweb is a full-stack framework that uses Clojure on all ends. This means you can write your frontend code in ClojureScript using Squint, your CSS in Gaka, and your backend code in Babashka. Everything backed by a traditional SQL database.
One of the key benefits of Borkweb is that it requires minimal overhead. You don't need to worry about setting up a complex build pipeline or managing a multitude of dependencies. With Babashka, you can simply write your code and run it. No need for Node.js, no need for a separate frontend build process. Just write, run, and deploy.
Borkweb is an open-source project, and I welcome contributions from anyone who is interested in helping to make it better. If you have an idea for a feature or a bug fix, please open an issue or submit a pull request.
borkweb only needs babashka to get started. To run the template just do a bb -m core
and you are good to go.
Make sure you have a postgres database at hand find documentation for that down below. If you need a postgres db there is a docker-compose.yaml there. Start it up as always docker-compose up -d
.
The initialization of the database is currently done with an init.sql which you can trigger either with bb -m database.core/initialize-db
.
Or by a tool of your choice. The database connection parameters are available in database/core.cljs
just replace as you like.
Currently postgres is used for the database backend but you can basically use any sql database that you like and which is supported by your runtime. If you want to use a diffrent db like datalevin you'll lose the registration and login functionality and have to adjust some stuff.
Routing can be done in the routes.clj
file found in the base folder. There are already premade helper functions to generate routes in a compojuresque style.
(route path method (fn [req] body))
(get path (fn [req] body))
(post path (fn [req] body))
borkweb provides already everything you need to get started with cljs no need for any bundler or anything else.
Get to resources/cljs
drop your cljs code that is squint compliant and you are good to go. borkweb allready includes some examples for preact and preact web components. There are helper functions to compile cljs code in your hiccup templates. You can find them in view/components.clj
cljs-module
to generate js module code and cljs-resource
to create plain javascript code. there is even ->js
which can be used to trigger squint/cljs code inline.
;; resources/cljs/counter.cljs
(require '["https://esm.sh/preact@10.19.2" :as react])
(require '["https://esm.sh/preact@10.19.2/hooks" :as hooks])
(defn Counter []
(let [[counter setCounter] (hooks/useState 0)]
#jsx [:<>
[:div "Counter " counter]
[:div {:role "group" :class "btn-group"}
[:button {:class "btn btn-primary" :onClick #(setCounter (inc counter))} "+"]
[:button {:class "btn btn-primary" :onClick #(setCounter (dec counter))} "-"]]]))
(defonce el (js/document.getElementById "cljs"))
(react/render #jsx [Counter] el)
;; view/some_page.clj
(require '[view.components :as c])
(defn some-page [req]
[:h1 "My fancy component page"]
[:div#cljs]
;; just use the filename without cljs. the function will search in the resource/cljs folder.
(c/cljs-module "counter"))