stube is a personal research project — somewhere I am working out an old idea about web applications that has been pulling at me for nearly twenty years. This page is the story of how I got here.
The first framework that taught me something genuinely new about web applications was UnCommon Web, Marco Baringer's Common Lisp continuation framework. Two ideas stuck:
I remember showing this to colleagues and the reaction being, almost universally, "this is an abomination." Mixing HTML and code broke a deeply-held habit that templates were templates and code was code. Anyone who has been on the receiving end of "you're doing templating in Lisp?" knows the look. The model felt right to me anyway.
Seaside — Avi
Bryant and Julian Fitzell's Smalltalk framework, later maintained by
Lukas Renggli and the Pharo community — took the same ideas further
than UCW had. Components could call: other components like methods and
answer: results back like return values. A wizard was a sequence.
A confirmation was a function call. The "canvas" API turned HTML
generation into Smalltalk message sends.
I also spent time around Evrim Ulu's core-server, another Common Lisp framework in the same lineage. It had its own takes on continuations and on the host-language-DSL question, and it was a useful second data point: there was nothing fundamentally weird about this style; several smart people in different languages had independently converged on it.
This was, by some distance, the most interesting cluster of web frameworks I had ever met. None of them ever became mainstream.
Then React happened. JSX happened. Suddenly writing HTML inside the host language was the default — not an abomination anymore, just what you did. The thing colleagues had recoiled from in YACLML and the Seaside canvas was now table stakes in a hiring quiz.
It was a strange kind of vindication. The peripheral idea — HTML as host-language data — had won. The central idea — call/answer, invisible page boundaries, the server remembering what the user was doing — got quietly left behind. The web went the other way: thick clients, JSON contracts, URL-based navigation replaced by client-side router libraries, the server treated as a dumb data API. Seaside's center of gravity drifted out of fashion right as its sidekick became universal.
Seaside itself, to be clear, has not stood still — the Smalltalk community has kept working on it, including modern work I won't pretend to be familiar with the details of. But for me the square-peg problem was specific: I wanted this model in Clojure, on a wire shape I happened to enjoy, with the data shapes Clojure makes obvious. None of that was Seaside's problem to solve.
The piece I'd been missing in Clojure was a wire I liked. htmx, Hotwire / Turbo, LiveView, and now Datastar are all in the same conceptual neighbourhood: server-rendered fragments over a long-lived channel, the browser as a renderer rather than a thick client. Any of them would, in principle, support the call/answer kernel I had in mind.
I happened to land on Datastar. It is small enough that a server framework can drive it without taking on a JS framework's worth of complexity; the SSE + morph-by-id protocol clicked with how I wanted handlers to compose; and the signal model played nicely with how the conversation already wanted to carry per-input state. It is a personal preference, not a claim that the others wouldn't work — if you reach for htmx, Hotwire or LiveView instead, you are in good company.
stube is what happened when I sat down with all of these threads in one hand:
It is not a product. It is the artefact of an idea I have been carrying for a long time and finally had the tooling to build faithfully. If it is useful to someone else, that is good news. If it just exists, and someone picks up these ideas from it the way I picked them up from UCW and Seaside, that is also fine.
docs/v2.md — the original design.docs/v2_1.md — the revised plan, including §0 on the
five Datastar facts the implementation had to discover the hard
way.docs/seaside-examples.md — Seaside's
canonical examples ported to stube.docs/halos-spike.md — the dev overlay, shaped
after Smalltalk's halos.Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |