This is the first time I’ve managed to get a Rebol-family application running in the browser in the form I actually wanted.
I did not want to reproduce the conventional web stack inside Rebol, nor build another PHP/Cheyenne-style templating system with bits of language embedded between angle brackets. Nor did I want to reimplement the whole browser GUI.
Instead, Glon implements only enough of the GUI vocabulary to describe the application at a high level.
The browser-facing machinery underneath is deliberately highly leveraged. A Glon view describes enough of a screen for the single-page application, and when something falls outside that vocabulary we can simply drop down to JavaScript rather than continually enlarging the dialect.
That is the same principle I want elsewhere in Glon. Use the high-level dialect for the common case, but retain an escape down to the underlying mechanisms when necessary. We do not have to wrap the entire platform before we can use it.
In the GUI, that means Glon is not trying to implement a complete widget toolkit or reproduce the whole DOM. It describes the useful part of the screen and lets the browser do what browsers already do well.
The result now looks and behaves like a real application: persistent state, routing, events, generated controls, a shopping basket and re-rendering, while the application itself remains Rebol-like.
JavaScript is infrastructure rather than the application language.
The same general principle applies lower down as well. If GQL needs something outside its high-level vocabulary, it can drop down to the underlying prototypes rather than forcing everything through an ever-growing abstraction layer.
So the trick is not to build a full stack at every level. It is to build a small, highly leveraged layer that handles the common case elegantly, while preserving access to the machinery underneath.
And, to me, the nicest bit is View Source.
There are no PHP-style <% ... %> islands, no Cheyenne-style templating, and no giant JSX-style thicket of angle brackets.
You see things like:
home-view: [
heading [ emit-text "Glon Shop" ]
tagline [ emit-text "A tiny GLON storefront" ]
link [ emit-text "View products" ] "products"
]
products-view: [
heading [ emit-text "Products" ]
products catalog
emit-text panel-open
emit-text search-open
input "search"
button [ emit-text "Search" ] "search"
emit-text search-close
meta [ emit-text "Search: " emit-text search-term ]
meta [ emit-text "Products page visits: " emit-int visit-count ]
emit-text panel-close
basket
link [ emit-text "Back home" ] "home"
]
add-product: func [] [
either str-eq current-value "Tea" [
tea-count: + tea-count 1
][
either str-eq current-value "Rice" [
rice-count: + rice-count 1
][
none
]
]
render-current
]
The little view vocabulary is itself written in Glon:
wrap: func [open close] [
func [content] [
emit-text open
do content
emit-text close
]
]
heading: wrap h1-open h1-close
subhead: wrap h2-open h2-close
text: wrap p-open p-close
tagline: wrap tagline-open tagline-close
meta: wrap meta-open meta-close
So we are not embedding Rebol fragments inside HTML.
The application is the Rebol-family program.
HTML is what it emits.
JavaScript sits underneath as the generic browser host, and we only drop down to it when the browser platform gives us something useful that is not worth reimplementing above.
Live demo:
View Source is probably the best explanation of why I’m pleased with it.