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).
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.
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.
It adds complexity but then if you need caching, what doesn't?
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.
<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).
Or even if you didn't cache the user specific bits, you could cache the rest and just query for that every time.
It hasn't been released yet but it was merged in main and I was trying it out today. I plan dig more into it and write a breakdown. I'm really interested in how it's exactly working to see what corner cases we need to watch out for. As is usual with "magical" features they're great until you run into a corner case.
Probably the best way to think about morphing is as something that gets you up and running really quickly. Then as your app matures you can replace high traffic pages with turbo frames and streams or something else. In a typical app, even when it's mature you might find that 80% of the pages are low enough on the performance requiremetns that you can just morphing and then use the development time savings to really optimise the other 20%.