Compared to desktop GUI frameworks, most web frameworks pretty much suck. Of course, web frameworks are like editors and X window managers - nearly everybody hacks one together, so there are more available than can reasonably be known by one person. If I've missed one that doesn't suffer from the problems I mention, please let me know about it!
So consider the simple act of adding a button that arranges to run a single bit of code. In a desktop app and OO language, that looks something like:
ActionPane.AddButton(text="Do It!", callback=DoIt, pack=LEFT)
I.e. - you tell the system you need a button, how to label it, what code to run when it's pushed, and a little bit of information about how to position it.
In a web application frameworks, getting that effect typically involves adding text to a template somewhere, then tweaking the global "routing" configuration so whatever event the user generates by clicking the button in their browser actually invokes the DoIt code. Instead of editing one file - that's the same language as the code to DoIt - you're editing as many as three files, in three languages. If you're really lucky, two of them are XML with different namespaces, so it only feels like two languages.
Having to specify the routing by hand is particularly egregious. It's sort of like having to use the windowing systems ID for the button to find the callback code for the button. No competent desktop programmer would put up with that for long. If nothing else, they'd write a wrapper function to hide that from them.
Templates are a relic of a bygone era. In the best case, you're editing XML with multiple namespaces - which is ugly enough. But there's a good chance you're editing XML intermingled with something else. In the worst case, that looks just enough like XML to confuse an XML editor, but I hope everyone is beyond that.
Apache's Tapestry manages to avoid all that by using Java's introspection facilities to find methods in the code and automatically tie them back to invocations in the templates. The downside is that this exposes all your code in the templates, which is maybe not such a good idea. The problem is that half the application uses templates that need to refer to code objects, but aren't written in code themselves.
Templates were intended to separate the presentation of the data from the code that generated it, but I've never seen a templating system that did that properly. In particular, to present a list of data items of unknown length, either the templating language has to have a method of coding a display that's repeated for the sequence, or the code has to emit bits of display control to separate items in the sequence.
The reason I call this a relic of a bygone era is that CSS was supposed to have allowed the presentation control to be moved into the style files. While everyone uses style files to control presentation, people still seem stuck with doing the actual page coding in templates. If your team is driven by non-programmers who create the template files, this may be a desirable situation. But if your team is all programmers, it pretty much sucks for them - even if they don't realize it.
If, on the other hand, the template's could be replaced by code, with the presentation controlled by CSS, a lot of problems vanish. Programmers could work in one language - the code. CSS doesn't need to reference code objects, it just needs to reference known tags, class or id values - which are part of the output data, not part of the code. This is essentially what the desktop applications are doing.
One major difference is that desktop applications have to call code to create the structures that describe the UI. The UI for web apps can be described by a simple text string. Because of this, even in tools that embed the template in the code, the template is often text or data, and not actually code. This then requires code to walk that structure, generating the text and plugging in values where it's needed. Unless the structure in question allows sharing bits between it, this makes sharing objects between different parts of the UI difficult. If the UI is described by objects with their own intelligence, it becomes easy to share those objects between different parts of the UI, even if it looks like a template structure.
Like I said, there's no fundamental reason that this can't be done - it's just that people don't. The one exception I know of is the Seaside framework. Unfortunately, it's written in Smalltalk, which is even worse about playing well with others than LISP. It's also not suitable for use with Clojure, as it's unabashedly OO.
I've spent the last few days contemplating what a Seaside like framework for Clojure should look like. I've got a rough design, and hope to have some sample code working in the near future. At that point, I'll post a design for review.