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)