A React-style frontend framework for Corros — components, props, hooks
(use_state), nested stateful components, event handling, diffing, and
server-side rendering with hydration and live updates, written entirely in
Corros. Components are plain Corros
crafts; the browser runtime (web/glaze.js) is a single dependency-free
JavaScript file.
| React | glazecraft |
|---|---|
React.createElement("div", props, ...children) |
el("div", props, children) |
function Greet({name}) { return <p>Hi {name}</p> } |
component(craft(props) { return el("p", {}, ["Hi " + props["name"]]) }) |
useState(0) |
use_state(0) → [value, setter] |
<button onClick={fn}> |
el("button", { "on_click": fn }, ["go"]) |
renderToString(<App/>) |
glaze_render(App, props) |
ReactDOM.hydrate |
glaze_hydrate(app) + glazecraft.mountAll() |
key prop / reconciliation |
key prop; nested state persists; glaze_diff(old, new) |
| live re-renders in the browser | /_glaze/event round-trip (server re-renders, client patches) |
curl -fsSL https://raw.githubusercontent.com/CocoCopi/glazecraft/main/install.sh | sh
glazecraft renderadopt "/path/to/glazecraft/src/glaze.cro"
forge Counter = component(craft(props) {
forge pair = use_state(0)
forge count = pair[0]
forge set = pair[1]
return el("div", { "class": "counter" }, [
el("p", {}, [str(count)]),
el("button", { "on_click": set, "data-glaze-value": "1" }, ["+1"])
])
})
forge app = glaze_mount(Counter, {})
speak(app["html"]) // <div class="counter"><p>0</p>...
app["set_state"](0, 5) // update state slot 0 -> re-render
speak(app["html"]) // <div class="counter"><p>5</p>...
- Server-side render —
glaze_mount(comp, props)renders the component; every element with anon_*prop is markeddata-glaze-h/data-glaze-evt. - Hydrate —
glaze_hydrate(app)registers the app and returns{id, html}to embed in the page;web/glaze.js(glazecraft.mountAll()) attaches the events. - Live updates — an event posts
{id, h, value}to/_glaze/event; the server runs the handler, re-renders, diffs, and repliesok\n<new html>; the client replaces the root and re-wires.examples/serve.croandglazecraft serveare complete working examples (served by kilncraft, the sibling backend framework).
el(tag, props, children)— virtual nodes; sorted attributes, HTML escaping, void elementscomponent(craft)— any render function becomes a componentuse_state(init)— per-instance hooks; setters re-render- Nested components with their own state (persisted via
key/position) - Conditional rendering (
when), lists (each), fragments (return a list) glaze_handlers(vnode, [])— collecton_*handlersglaze_diff(old, new)— token-level diff (common prefix/suffix + changed middle)glaze_page(title, vnode)— full HTML documentglaze_hydrate(app)+glaze_handle_event(app, h, value)— the live-update API
bash tests/run.sh- Corros suite (
tests/t_glaze.cro) — elements, attributes, escaping, components, hooks, nested state, events, diff, hydration, live events. - Browser runtime (
tests/glaze_dom_test.js, Node) — loadsweb/glaze.jsin a sandboxed fake DOM, simulates a click, and asserts the XHR round-trip. - Live round-trip — boots
glazecraft serveand POSTs a real event.
- Backend: kilncraft — the
Express-style server framework this demo's
servemode routes through. - Math: oremath / cryotorch for any server-side computation the components need.
The component/state/composition model is React's; the re-render happens on
the server (a LiveView-style architecture) because Corros runs server-side —
the browser gets the diffed HTML via /_glaze/event, and glaze.js patches
the DOM. That's a real frontend framework in the React mold, minus a
client-side VDOM: there's no way to run Corros render functions in the browser
(yet — a Corros→JS compiler is the natural next step).
MIT — see LICENSE. Built with Corros; see the Corros repo for the language.