Hotwire Turbo is a minimal JavaScript framework developed by Basecamp. It revolutionizes how we approach building modern web applications by reducing the amount of client-side JavaScript and shifting more work onto the server-side. It does this by delivering HTML over the wire to update parts of the page rather than using JSON and client-side rendering.
Turbo Drive is the core component of Turbo. It speeds up navigation within your site by intercepting all clicks on <a href>
links and submitting all <form>
tags asynchronously. Any URL changes are automatically persisted to the history API, giving your site the feel of a single-page application (SPA), but without having to write any JavaScript code.
Turbo Frames allow you to update parts of a page with fresh HTML from the server. This is done by encapsulating sections of a page inside <turbo-frame>
tags. Any link clicks or form submissions within a Turbo Frame are confined to that frame, leading to a seamless page update without a full page refresh.
For example, if you want to replace the content of a specific frame, send an HTML response containing a <turbo-frame>
with the same id
attribute:
<turbo-frame id="frame_id"> New content </turbo-frame>
A key consideration when using Turbo Frames is not to overuse them. They should not be used to structure your application logic, but rather for parts of the page that have a distinct lifecycle. For instance, in an e-commerce context, a Turbo Frame might be used to differentiate between content that is generic and cacheable, and content that is personalized, like the current shopping cart.
Turbo Streams, an additional feature of Turbo, allows you to send updates from the server to the client and update multiple places on the page at once. Each Turbo Stream action is sent using a special MIME type over WebSocket connection or through HTTP responses.
We've created some helper components for Streams under src/components/turbo.tsx
to assist you with this process.
TurboStream
is a component that you can use to generate Turbo Stream responses. Mutation
and Mutations
are helper functions built on top of TurboStream
.
Here is an example usage:
export const UpdatePage = page`/api/mutations/update`(() => (
<Mutation target="date" action="update">
<div>{new Date().toString()}</div>
</Mutation>
));
This example updates the content of the element with id "date" with the current date.
Additionally, JavaScript generators can be used to stream changes:
import page from '~/utilities/page';
import { TurboStream } from '~/components/turbo';
const sleep = (time: number) => {
return new Promise((resolve) => setTimeout(resolve, time));
};
export const GenerateImageLink = page`/frames/generated-images`(async function* (_req, res) {
await sleep(1000);
yield (
<TurboStream target="suggest-image" action="update">
<div>Never gonna give you up</div>
</TurboStream>
);
await sleep(1000);
yield (
<TurboStream target="suggest-image" action="append">
<div>Never gonna let you down</div>
</TurboStream>
);
return res;
});
When working with Hotwire Turbo, here are some best practices to keep in mind:
Minimize Client-Side JavaScript: The philosophy of Turbo is to minimize the use of client-side JavaScript and offload as much as possible to the server. The more you can leverage server-side rendering and HTML over the wire, the better.
Avoid Mixing with Other JavaScript Libraries: Hotwire Turbo is a comprehensive framework designed to work on its own. Mixing it with other client-side libraries and frameworks can lead to unpredictable behavior and conflicts.
Be Careful with Turbo Frames: While Turbo Frames are a powerful tool, they should be used thoughtfully. Do not use them to structure the logical flow of your application. Instead, use them to encapsulate sections of the page that have a distinct lifecycle. In an e-commerce context, for example, use Turbo Frames to differentiate between cacheable, generic content, and personalized content like a shopping cart.
Leverage Turbo Streams for Real-Time Updates: Turbo Streams provide an efficient mechanism to push real-time updates from the server to the client. This is especially useful for dynamic content that needs to be updated in response to server-side events.
Make Use of the Lifecycle Callbacks: Turbo Drive provides a set of lifecycle callbacks that you can hook into. These can be helpful to manage the transition state, to adjust the UI before and after page changes, and to clean up resources.
Test with Different Network Conditions: Turbo offers significant speed benefits but ensure you test your application under various network conditions. What works well under high-speed conditions may not perform as expected in slower networks. Test and optimize for all scenarios.
Avoid nesting Turbo Frames: Turbo does not support nested frames, and trying to nest them can lead to unexpected behavior.
For more details and advanced usage, the official Hotwire Turbo Handbook is a great resource. Just remember, while Turbo can drastically enhance the speed and efficiency of your web application, it should be used thoughtfully and judiciously.
Powered by Doctave