Main Blog
veröffentlicht von mathiasp am 19.11.2016 mathiasp

I'm a long time sass and compass user. And now I'm a ClojureScript user, too. So, how do I combine the two?

Is compass still relevant for my workflow?

When readjusting my environment; i first stopped and reconsidered my use of compass. What did I use it for? Do I still need it? It turned out, that I mostly used it for prefixing css and sprite generation. Since I start to use more and more svg icons, the sprite-generation part is becoming less important. And since postcss with autoprefixer gives me a very nice solution for adding prefixes, I think I can safely get rid of compass. Thanks a lot. We had a great time together! And using postcss I can choose from the myriad of available plugins, for example the excellent postcss-font-magigian.

BTW: why do I use sass and postcss? Well, I don't think improperly emulating some future spec is really not useful, at least not for me. For some thoughts on this, see for example Chris Coyier's article on CSS-Tricks, "The Trouble With Preprocessing Based on Future Specs".

So I decided to keep using sass, and use postcss strictly for postprocessing, i.e. autoprefixing, adding font declarations, minifying et al.

Searching for lein plugins

Since I'm using lein for my builds, it seemed a good idea to search for lein plugins. I found two: one basically used the sass command line, the other, sass4clj used libsass through jsass.

Sadly I couldn't use sass4clj since I run mostly on FreeBSD, and sass4clj didn't support this out-of-the-box. And lein-sass used the command line sassc, and really, I don't need no plugin for that.

CLI to the rescue

In the end, for me, it seemed the easiest was out to just run sass and postcss-cli on the command line. Both have inbuild watching capabilites, so I can just say

% sass --watch resources/scss/main.scss:resources/public/css/main.css

and have my scss files turned into css.

Now to the postcss side of things.

postcss-cli can be configured via a json config file. That looks pretty simple for my case:

    "input": "resources/public/css/main.css",
    "output": "resources/public/css/main.min.css",
    "use": ["autoprefixer", "postcss-font-magician"],
    "watch": true,
    "autoprefixer": {
        "browsers": "> 5%"

I still need to decide on a minifying workflow, but that should work quite similar.

Now I can start postcss like this:

% ./node_modules/.bin/postcss -c postcss.json

and have both tools work nicely together.

Reloading works with browser plugins, e.g. Auto-reload for Firefox.

So, no webpack, grunt, or gulp. This setup has plenty enough comfort for me, and having two additional shells open is not really that bad.

veröffentlicht von mathiasp am 12.11.2016 mathiasp

The past: no obvious way

For some time I wanted to use re-frame, the framework/pattern for writing in-browser apps using reagent and react, and combine this with datascript, the in-browser datalog database modelled after datomic.

But re-frame is build around holding all data inside an atom, and I found no good way to combine both. Also, the authors of re-frame said that datascript was to slow in their experience. So maybe it was a bad idea after all...

re-frame 0.8, posh, a new order

Lastly two things happened that made me reconsider:

With the new release 0.8.0 re-frame introduced something new: Effects and Co-Effects, designed to keep re-frame event functions pure. And with these co/effects handler, combining re-frame with datascript seemed like a simple task to me.

And on the performance side posh popped up: a library for writing datascript-based apps which sped up datascript use within UIs considerably.

So I tried again to combine re-frame and datascript using effectfull handlers from re-frame and posh for performance, and it turned out to be easy. Next step will be to find out how this performs.


The basic idea is to put (only) a datascript connection in re-frames db and from then on only use effectfull handlers to update the datascript database, instead of updating the re-frame central app-db atom.
Subscriptons largely work as before, using the reg-sub-raw instead of the new reg-sub, because posh returns reactions allready.


The minimal changes to the re-frame-template I found look like this:

First, add posh to project.clj

(defproject re-posh "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.8.0"]
                 [org.clojure/clojurescript "1.9.229"]
                 [reagent "0.6.0"]
                 [re-frame "0.8.0"]
                 [posh "0.5.4"]]

Now lets add posh and datascript declarations to db.cljs

(ns re-posh.db
  (:require [posh.reagent :refer [pull q posh!]]
            [datascript.core :as d]))

and put a datascript db into the re-frame atom

(def default-db
  {:db (d/create-conn)})

Let's activate posh for this db and put some data in it:

(posh! (:db default-db))

(d/transact! (:db default-db)
             [{:db/id 1
               :posh/name "re-posh"}])

Now that we have our datascript database, let's modify the subscription to use it:

First add posh and datascript (yes, I know, boring):

(ns re-posh.subs
  (:require-macros [reagent.ratom :refer [reaction]])
  (:require [re-frame.core :as re-frame]
            ;; add posh + datascript
            [posh.reagent :refer [pull q posh!]]
            [datascript.core :as d]))

Now use reg-sub-raw, so our posh result (a reaction) doesn't get wrapped into another reaction

 (fn [db nix]
   (pull (:db @db) '[:posh/name] 1)))

Easy, right?

But since posh/datascript pull syntax returns maps we'll need to slightly change our view by using {:posh/name @result} instead of just @result.

(defn main-panel []
  (let [result (re-frame/subscribe [:name])]
    (fn []
      ;; get the name from the pull result
      [:div "Hello from " (:posh/name @result)])))

And now to the interesting stuff: use re-frame's new effectful handler to run
datascript transactions. For this we need an effect handler who actually does the transaction, and then we just use that in an reg-event-fx handler to change the database.

Again, include posh and datascript:

  (:require [re-frame.core :as re-frame]
            [re-posh.db :as db]
            [posh.reagent :refer [pull q posh!]]
            [datascript.core :as d]))

The initialize-db handler stays the same, so I don't show it here, we only add a new effect handler to run datascript transactions for us.

;; the new event handler, just running the transaction
 (fn [transaction]
   (d/transact! (:db @re-frame.db/app-db)

And now the effectful handler. It doesn't even need to return the re-frame db, it just returns the datascript transaction.
Remember, a datascript transactions is only data

 (fn [cofx [_ name]]
   {:transact! [{:db/id 1
                 :posh/name name}]}))

Compile this with lein figwheel dev and use {re-frame.core/dispatch :change-name "Gobblydok") to see the effect in the website.

I've yet to play with debugging this, but I think it show's the power of re-frame's new effectful handlers.

veröffentlicht von mathiasp am 12.01.2016 mathiasp

I sort of liked the idea of nobackend, but hated it's js-orientedness.

I think a generic backend should talk generic APIs, and do not want to be presented with some javascript mubo jumbo. Esp. since I prefer clojurescript ;)

Enter PostgREST: a simple (?) no-nonsense PostgreSQL to REST solution.

And it's breathtakingly simple: download the postgres binary, copy it somewhere on your server, probably somewhere in your path, and then call it with:

postgrest postgres://user:pass@host:port/db [flags]

that's it. Your PostgreSQL server is now available via http, by default on port 3000.

Simple, isn't it?


will give you some JSON with the available tables, and (you guessed it):

GET /myinterestingtable

gets you the table contents as JSON


PostgREST supports JWT token security, full insert, update, delete capabilities, calling database functions, follows foreign key relations: you name it, it has it. The author even describes a very nice and flexible user management system, working only with PostgreSQL tables, functions and triggers.

Very, very nice. Blazing fast. I warmly recommend it!

Sad point: I can't compile it on FreeBSD; I'm currently running the linux version.