Someone interested in a "Basecamp Hotwire" library for Phoenix?

I wonder if will be interesting build a library like hotwire-rails or turbo-rails for Phoenix. What the thoughts of the community about it?

The multiplatform (iOS and Android) and offline features comming with Strada, together with Phoenix, can be a very smart choice for small teams that wants productivity and performance side by side. IMO Hotwire + Phoenix can be a way better than Hotwire + Rails (Given Phoenix performance, OTP and etc…).

And… can LiveView and Hotwire works together in some scenario? (in the same project?)

2 Likes

I’d be really interested to hear from someone who’s trying out Hotwire to find out how it stands out and compares with Liveview and other options in the Phoenix ecosystem. I know it’s quite a different approach from Liveview, but with similar-ish goals to do much more work on the server side of things.

Personally I’m wondering if Liveview already covers most/all of what Hotwire can do (though with a different style of approach), or if there are some things that could compliment or even be inspiration for Liveview. Either way, it’s great seeing other devs finding value in paths similar to Liveview. I use Liveview heavily and it’s been a huge boon to solo development and small team work for me!

As for using both together, my guess would be that they would conflict a lot, especially without some extra effort configuring both. Things like phx-ignore might allow them to coexist peacefully though? Interested to see!

2 Likes

Based on the posts, it sounds interesting - but instead of starting with a library, consider starting with demo applications that just use the Hotwire idioms. It wouldn’t surprise me if there’s a lot of out-of-the-box usability modulo details like naming attributes just so.

2 Likes

I’ve been using Turbolinks for years and that’s comparable to Hotwire Turbo Drive. Hotwire Turbo Frames are interesting too. The biggest difference I’ve seen so far is that they both work over HTTP and your existing applications work as they do now with minimal to no code changes. There’s also progressive enhancement in that if JS isn’t enabled, links just do full page loads instead of getting the enhanced experience.

I added it to a Phoenix (and Flask app) and it worked pretty much out of the box. One drawback I’m seeing tho is there’s no push state with frames but the more I work with it, the more I’m understanding that frames aren’t meant to have push state because if you wanted a push state experience you would just use turbo drive (which is meant to be a drop in replacement zero code change solution for super fast page transitions).

Turbo Streams is the other component of Hotwire and that’s a bit more effort to get working with non-Rails backends since it deals with sending bits of server rendered HTML over a websocket connection.

I think the main takeaway I’ve gotten so far is drive + frames can get you pretty far to make awesome feeling apps over HTTP with zero websocket dependence and then you can opt into something like LV for just the push / broadcast / reactive bits of your site as a replacement to Turbo Streams.

That would be opposed to using LV to replace drive, frames and streams. That has its own pros and cons but it’s technically doable.

4 Likes

I am using Turbolinks with LiveView for achieving something like Turbo Drive in my side/learning/testing project where I keep the LiveView connection open only on subpages that need it. Otherwise everything is operating as just plain old HTML.

3 Likes

I’m very interested in this! I’ve been using it with Elixir, although haven’t gotten streams to work.

I’ve been using Turbolinks for years and that’s comparable to Hotwire Turbo Drive. Hotwire Turbo Frames are interesting too.

It looks like they fix the one annoying issue in turbolink: you no longer need to set the Turbolinks-Location header. So turbo drive should just work without any involvement from the server side.

It also looks like turbo frame should work so long as I have the server side routes to spit out the required html snippets, which should be fairly simple to do in phoenix. I don’t think we need a library here.

Turbo Streams is the biggest hurdle but If I need to have a web socket, why don’t I do one step further and make it stateful, like Live View?

From the scant of documentation they have, it is not clear to me if turbo frames can be nested?

For the most part yes. In the apps I tested it in, I didn’t do anything on the server. I dropped in the JS library and everything worked without changing 1 line of code on the server. They say even form submissions with drive will work too, although I didn’t test that yet.

Although, Rails does make 1 optimization for frames. If the request is a turbo frame then it doesn’t send the layout over the wire to help reduce the payload. Everything works without doing this but it’s an optimization worth making. The implementation for Rails is at https://github.com/hotwired/turbo-rails/blob/ec31fa125165fb0a207c5f88dce9e8719b1c711f/app/controllers/turbo/frames/frame_request.rb#L1-L24. That should be doable with a Phoenix plug.

The other stuff is minor convenience helpers like providing a template tag to render the frame instead of using the html tags taken from the Turbo docs.

Like: put_layout(conn, false) ?

Yes, but potentially the etag bit too. I’m not sure if Phoenix or cowboy sets it in the response but given the comment in the Rails implementation it seems important if it is set because you would want both a layout and layout-less version of your content to have different etags because the URL endpoint would be the same depending on how the URL was accessed (frame or not).

From what I can see phoenix/cowboy set neither etag nor last-modified header. The cache-control is:
max-age=0, private, must-revalidate So I don’t think phoenix can leverage cache anyway.

It can, you just need to handle it on your own. The default is no caching.

1 Like

LiveView + Turbo Stream, the easiest way!



Just realized this is not a liveview thread, so note that my liveview code is completely stateless (zero assigns, state kept in socket.private[:state] for now) because I’m experimenting if I could go back to plain Phoenix Channel. Seems like <turbo-stream> works perfectly with Channel.

7 Likes

Cool. Please write a blog post afterwards.

1 Like

I created a Phoenix port of the demo Rails application.


As a novice alchemist, I would be glad to hear any feedback.
7 Likes

Could it be that the just-merged function components in Liveview might be quite helpful for integrating Hotwire (particularly Turbo Streams) with Phoenix?

2 Likes