DEV Community

Fernando Correa de Oliveira
Fernando Correa de Oliveira

Posted on • Edited on

Cromponent new features

Cromponent πŸŽ‰ now lets your components bind cookies, query-string params, headers and HTTP-auth credentials directly in the method signature πŸͺβ“πŸ“‘πŸ” and push live HTML over WebSockets with two tiny hooks πŸ”ŒπŸ›°οΈ.
Paired with HTMX on the client, that means real-time Raku apps with zero JavaScript πŸš€. Below you’ll find the new API plus a complete β€œlive poll” example. Dive in! πŸŠβ€β™‚οΈ

βΈ»

  1. Why Cromponent? πŸ€”βœ¨

Cromponent glues together Cro’s reactive HTTP / WebSocket server and Cro Templates to give Raku developers a component abstraction Γ  la modern SPA frameworks – but rendered on the server and streamed as HTML fragments.
The latest release focuses on state & interaction: declarative request-context binding and built-in WebSocket wiring. ❀️‍πŸ”₯

βΈ»

  1. Prerequisites at a Glance πŸ“šπŸ”Ž
Layer Role 1-Liner
HTMX ⚑ Enriches plain HTML with AJAX, SSE & WebSockets via attributes. hx-put, hx-target, hx-ext="ws", …
Cro 🧩 Reactive HTTP/WebSocket server & router for Raku. route { … }
Cro Templates πŸ–‹οΈ HTML-centric templating DSL compiled on first use. template 'view.crotmp', %data
Red ORM πŸ—„οΈ DB-agnostic ORM with migrations & relationships. model Foo { has Int $.id is serial … }
Dynamic vars 🌐 $*foo passes per-request context through deep calls. $*user in our example
  1. New API: Context Traits πŸͺβ“πŸ“‘πŸ”

Any method tagged is accessible becomes an endpoint and auto-binds request data:

method profile( Str :$uuid is cookie, Str :$q is query, Str :$accept is header, Str :$creds is auth ) is accessible { ... } 
Enter fullscreen mode Exit fullscreen mode
  • Zero plumbing πŸ› οΈ
  • Type-safe input πŸ›‘οΈ
  • Self-documenting signatures πŸ“œ

Route pattern:

/ComponentName/<ids…>/profile 
Enter fullscreen mode Exit fullscreen mode
  1. New API: Automatic WebSockets πŸ”ŒπŸ›°οΈ
    1. Channel key – method IDS { $!id } groups browsers in the same room.
    2. Re-render hook – method REDRAW(:$*user is cookie) { $.Str } returns fresh HTML when you redraw $component.
    3. <|WebSocket> cromponent adds hx-ext="ws" ws-connect="/ws" and the htmx-ws extension swaps fragments for you.

No manual frames, pings or reconnect loops – Cro & HTMX handle all that jazz. 🎷

βΈ»

  1. Building a Live Poll πŸ—³οΈβš‘

5.1. Router & DB Setup πŸ›£οΈ

my $routes = route { red-defaults "SQLite"; PollItem.^add-cromponent-routes; # auto REST πŸ†“ WebSocket.^add-cromponent-routes; # auto WS πŸ†“ get -> 'polls', Str :$*user is cookie = UUID.new.Str { response.set-cookie: :name<user>, :value($*user); template 'polls.crotmp', { :$*user, :@polls = Poll.^all } } } Cro::HTTP::Server.new(:host<0.0.0.0>, :port(2000), :$routes).start; 
Enter fullscreen mode Exit fullscreen mode

First visit ➑️ generates UUID ➑️ saves in πŸͺ ➑️ available as $*user.

5.2. Poll Component πŸ“Š

model Poll does Cromponent { has UInt $.id is serial; has Str $.descr is column; has @.items is relationship(*.poll-id, :model<PollItem>); has @.votes is relationship(*.poll-id, :model<PollVote>); method LOAD($id) { Poll.^load: $id } # rebuild method IDS { $!id } # WS room method REDRAW(:$*user) { $.Str } # push update method did-user-vote($who = $*user) { ?@.votes.first: *.user eq $who } method RENDER { … } # the template } 
Enter fullscreen mode Exit fullscreen mode

5.3. PollItem Component βœ…

method vote(Str :$*user is cookie) is accessible { :http-method<PUT>, :returns-cromponent } { red-do :transaction, { $!votes++; self.^save; $!poll.votes.create: :$*user; redraw $!poll; # broadcast 🌍 $!poll } } 
Enter fullscreen mode Exit fullscreen mode

HTMX button:

<button hx-put="/poll-item/42/vote" hx-target="closest .poll" hx-swap="outerHTML">πŸ—³οΈ Vote</button> 
Enter fullscreen mode Exit fullscreen mode

5.4. WebSocket-Enabled Page πŸ–₯️

<|Boilerplate(:title('Polls πŸ—³οΈ'), :htmx, :style-sheets('/css'))> <|WebSocket> <h6>Logged in as <.user> πŸ™‹β€β™‚οΈ</h6> <@.polls><&HTML($_)></@> <a href="/polls">All polls πŸ“‹</a> </|> </|> 
Enter fullscreen mode Exit fullscreen mode
  1. Generated Endpoints Recap πŸ›€οΈ
Method Path Source
GET /polls manual route ❌
GET /polls/<id> manual route ❌
PUT /poll-item/<id>/vote PollItem.vote βœ…
GET /cromponent-ws WebSocket βœ…

One call to .^add-cromponent-routes ➑️ endpoints galore! 🎊

βΈ»

  1. Key Take-aways πŸ’‘
  2. Context traits (is cookie πŸͺ, is query ❓, is header πŸ“‘, is auth πŸ”) shred boilerplate.
  3. IDS + REDRAW inject WebSocket magic with two methods. ✨
  4. Everything lives in one file: model + template + behaviour – still plain Raku, still testable. πŸ§ͺ

Result: back-end-driven UX with instant updates and zero JavaScript. πŸš€

βΈ»

  1. Further Reading πŸ“š
  2. 🌟 Cromponent β†’ https://github.com/FCO/Cromponent
  3. πŸ“œ Cro docs β†’ https://cro.services
  4. πŸ—„οΈ Red ORM β†’ https://github.com/FCO/Red
  5. ⚑ HTMX β†’ https://htmx.org
  6. πŸ”Œ htmx-ws extension β†’ https://htmx.org/extensions/ws/
  7. 🧠 Dynamic vars in Raku β†’ https://docs.raku.org/language/variables#Dynamic_variables

Happy hacking – and may your components stay Crom-pact! πŸ¦€πŸŽˆ

Top comments (0)