Copy
You're reading the Ruby/Rails performance newsletter by Speedshop.

Is Turbo magical speed-sprinkles for legacy applications? Maybe.

I've always been a fan of Turbolinks. "Turbolinks is good, actually" was my original Hot Take that catapulted me to Ruby performance stardom (heh). Unlike many Hot Takes, I think that one survived. HTML on the wire remains a quite relevant technology 7 years later. 

The rub with Turbolinks, however, was always it's all-or-nothing approach. All anchor tags on the page need to trigger Turbolinks navigations, and all of your site's Javascript needs to be compatible with the approach. This made it very difficult to port a legacy application to Turbolinks.

Things have changed a bit with Turbo, the Turbolinks successor, due to the addition of Turbo Frames.

Turbo Frames are basically the same as the old PJAX, which allowed portions of the page to be replaced with HTML via AJAX. This is how Github's file explorer still works today.

Turbo Frames are implemented as custom elements. You insert a turbo-frame tag around what you want to put inside the frame. Then, a couple of things are possible (all are optional):
  • You can lazily load the contents of the frame. Add a src attribute to the frame, and Turbo will fetch that url and then insert the contents of the response into the frame. Adding the loading=lazy attribute will make this behavior happen only when the element is in the viewport.
  • You can cause each link in the frame to, rather than cause a normal page navigation, cause Turbo to fetch the URL and replace the contents of the turbo frame element with the HTML returned from the fetch. This is the default, but you can also make links work normally.
  • Similarly to PJAX, you can also make link clicks inside a frame change the URL of the current page (but not actually trigger a whole navigation).
This is a really interesting addition to the "Turbolinks" family, because it's much easier to implement in a brownfield project. You no longer are stuck with the "all on or all off" paradigm that Turbolinks (now Turbo Drive) required, you can add Turbo Frames to just one tiny part of just one page.

So, what can we do with Turbo Frames that would be useful?
  • Take heavy/expensive parts of an otherwise-fast page and put them in a lazy-loaded frame. This allows the rest of the page to load fast, and everything in the frame will load separately. This can speed up overall page rendering too by allowing the head tag of the document to reach the client faster (a similar effect to using 103 Early Hints or streaming responses).
  • Take an overall slow page and decompose it into many smaller chunks which can be loaded in parallel. There's no limit to how many Turbo Frames you can put on a page. Why have one very slow page when you can load a mostly-blank layout, then load in dozens of individual components as Frames?
  • Implement small interactions (marking an email as read, deleting a row in a table, etc) as Frames, and you only have to render a small part of a page when you respond rather than and entire page. It also creates a "SPA-like" or "Turbo Drive" like interaction experience with absolutely zero Javascript written.
So I'm a pretty big fan of Turbo Frames.

Migrating legacy Javascript remains a challenge. Essentially, legacy JS is usually set up around the assumption that there is a single document ready event (DOMContentLoaded, usually), and that it will only fire once, and that all elements will be on the page at that moment and new elements will never show up. Turbo Frames (and Drive) breaks this assumption because elements are flying on and off the page all the time after DOMContentLoaded has already fired.

I've found an old but still quite functional and nice utility called onmount that helps solve this problem. It makes it a breeze to migrate legacy JQuery-based JS to Turbo-compatibility. Essentially all onmount does is manage a list of selectors and functions, and whenever you call "onmount.poll()", checks its list of selectors and idempotently runs functions on elements which are new to the page. It's really neat.

The combo of Turbo Frames and onmount is pretty amazing for legacy apps. If you're looking at a mass of old JS and wondering if you should rewrite it all, give this approach a try instead.

Until next week,

-Nate
You can share this email with this permalink: https://mailchi.mp/railsspeed/turbo-frames-drive-and-migrating-a-legacy-app?e=[UNIQID]

Copyright © 2022 Nate Berkopec, All rights reserved.


Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list.