Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Yep this is really good stuff.

The only concern I have is around making things more efficient server side.

For example if you have an expensive DB query that's not really cacheable, you can use streams and frames to only have that query execute once on the first page load but then you can navigate between pages that only load in a different frame.

A good example is something like a video course platform with a video frame, table of contents area and another frame below the video to load specific things like questions, references, show notes, etc.. As you click links in the table of contents, it loads new content in the video frame but the questions wouldn't change and you also don't need to re-render the table of contents either. You get to skip querying and rendering views for all of those expensive things.

With Turbo 8, if you used the new approach you would be rendering non-cacheable very expensive queries and views on every page transition. I want to use Turbo 8's features so much but for the biggest and most complex aspect of my app I don't realistically see how I can. The bookkeeping pain on manually updating 5+ areas of the page and writing a bunch of stream hooks which is multiplied as you add more actions is real though.

I'm hoping as Turbo 8 gets more mature new patterns will emerge to let us get the best of both worlds (performance and complexity compression).



This scenario does seem like something that would be cacheable to me though. Really its a matter of where you're doing the caching -- on the server, or in the client. It's easier to manage cache invalidation (and state in general) on the server so that seems like the preferable option to me for most things.

In the context of Rails specifically, something like Solid Cache helps a lot with this too. There are other similar approaches for other languages/databases as well, although most implementations are based on Postgres instead of MySQL.

If the specificity & complexity of the query is the barrier to caching, it's also possible that breaking the query up a bit could still net better performance if it makes it easier to cache.


> This scenario does seem like something that would be cacheable to me though

The table of contents has a course with sections, lessons and downloads / videos with sums of video lengths that roll up to each section and back to the whole course. It rarely changes but the monkey wrench is there's a checkbox next to each lesson where a user can toggle a lesson as being complete so now it's really personalized for each user with a model storing this state. I didn't want to save this client side in local storage in case they watch things on multiple devices.

Having a separate cache for each user seemed like it would be a big mess, especially since these "lesson completions" move very fast in the sense that a user can toggle a handful of them per session. This table is also pretty big. Imagine having a 200 lesson course but you have 10,000 people who took it. Now we're at 2 million rows. Russian doll caching seemed pretty dangerous here, I'd have to have touch: true on like 5 cascading models where editing 1 thing would bust components of the cache for everyone.

The queries themselves aren't too complicated. It's pretty much 3 queries with "includes" being used at times to avoid N+1 queries. It's getting the course, then looping over its sections and then looping over its lessons and in that lesson loop it gets any downloads. Then there's the lesson completion state for the current user too to see if it should be checked or not.

It doesn't seem very friendly to being cached.

I really wanted to avoid having a single cache for the whole TOC and making a separate ajax request to load in the user's lesson completions after the page has loaded. The UI gets jittery with the checkboxes being populated afterwards. This also opens a few cans of worms. Even if this were to happen in the end with Turbo 8, I'd still have to query the per user lesson completions + all of the resources (questions or show notes, etc.) presented under the video on every page transition.


I don't know all the details of course, but I think I'd approach this by splitting the user specific info into a short lived user specific cache + globally caching the non user specific stuff for a bit longer. Ideally that way you only have to query the user specific part at most once every 5 minutes or something like that.

Or even if you didn't cache the user specific bits, you could cache the rest and just query for that every time.


Other dom morphing setups have the concept of "ignore this sub-tree" which means that on first load you can render the ToC and checkboxes for the user, but then on the AJAX requests from Turbo omit that section of the page entirely. This lets you cache and share them whilst when the user refreshes the page they get the latest ToC.

It adds complexity but then if you need caching, what doesn't?


I'm not familiar with that omission process. What would that look like in practice?

It sounds like I'd still get a poor UX on the first page load (UI checkbox jitter), and on all page transitions I'd need to run the user specific lesson completions query produced from the ajax request and all of the other heavy content under the video (questions + show notes, etc.) would need to get rendered which in the end is much more expensive than using frames to avoid any of that from being processed.

I'm not trying to make the case of sticking with frames + streams either, I think it's been kind of painful to use them with all that's going on within the page. I'd love to be able to use the morph approach. I think I'd be able to delete tons of both server side and client side code.


Turbo morphing will allow to do exactly that, exclude a section from morphing, by wrapping it in:

<div data-turbo-permanent>...</div>

I think it's not yet documented since turbo has not yet landed in a production release of Turbo but it's been merged into main, you can see it mentioned on the PR: https://github.com/hotwired/turbo/pull/1019 (Look for "Exclude sections from morphing" title in the PR description).




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: