Talks

18 Months of Using Hotwire and ViewComponent in Production

wroc_love.rb 2022

00:00:09.440 Hello, everyone! Thank you for having me. Today, I’m going to talk about Hotwire and ViewComponent.
00:00:14.480 These tools can be used to build a modern monolithic application in Ruby on Rails. Let me share a few words about myself.
00:00:22.160 My name is Yaroslav Shmarov, and I’m from Ukraine. I speak several languages, and you might have come across me on Twitter or seen my YouTube channel, Super Rails.
00:00:28.840 I have quite a few videos about Hotwire there, along with my blog, which attracts around 200 Ruby on Rails developers daily.
00:00:33.920 Additionally, I might have some content on Udemy. I work at a French startup called Bearer.
00:00:40.640 Initially, I was hired for a very specific job, to be a frontend developer. My focus has been on Tailwind, Stimulus, and Hotwire.
00:00:53.039 The company is a few years old, but back in 2020, they decided to pivot. Previously, they were using Rails with GraphQL and React, but during the pivot, they concluded that this stack wasn't necessary.
00:01:07.680 As they were rewriting the application, Hotwire was released, so they thought, 'Why not give it a shot?' They decided to try Hotwire and ViewComponent instead of maintaining a separate frontend and backend.
00:01:15.119 Before I continue, I'd like to share a couple of thoughts on React versus Hotwire. I believe Hotwire is particularly excellent when you're in the early stages, especially if there aren't many developers. When it comes to building a React application, I find it appropriate only when an API is needed to support a mobile application.
00:01:39.360 Hotwire allows you to quickly create desktop experiences. In my opinion, React is better suited for B2C products where most users access services from their phones, while web applications are generally more tailored for B2B environments, where people use laptops at work. It's not fair to compare Hotwire and React as if one is better than the other; they are different tools for different jobs.
00:02:30.080 For instance, Hotwire executes server-side rendering, which means you can't build certain applications like a mirror clone or a tool as complex as Figma, or a good Notion clone. However, you can still build many useful applications like a Jira-like system or any kind of information management system.
00:03:07.440 You could construct components that are updated separately from each other, and you can create platforms like Twitch, Amazon, or Salesforce. Hotwire is indeed capable of supporting many different functionalities.
00:03:19.040 Going back to the company I work for and the technology stack we currently use: on the frontend, we have Hotwire, ViewComponent, Tailwind, and we recently transitioned from Webpacker to CSS and JS bundling.
00:03:43.920 This transition has been one of my favorite pull requests merged in the past year. The builder time has dramatically decreased, from around 40 seconds to something like five seconds, which has significantly improved the developer experience.
00:04:10.560 However, it wasn’t an easy migration; it required some effort to figure things out, but ultimately it was 100% worth it.
00:04:22.960 Now talking about structuring the front end in Rails, you'll encounter helpers, decorators, partials, and templates. I've observed that there can be issues with helpers and decorators; for instance, decorators are object-specific, while helpers are global.
00:04:49.759 You can define anything globally in the application helper or an events helper, allowing you to access it anywhere. If you're not careful, this might result in conflicts, whereas decorators necessitate creating an object, which does not wholly address the need for having components in your frontend.
00:05:08.560 The collaboration between the design team and the frontend team is also crucial. The design team can provide Figma designs, and I'll share a screenshot of our design team at Bearer who created various badge designs.
00:05:30.240 You can see there are many variants of badges, and implementing these designs in real templates can be tricky, but ViewComponent makes it quite manageable.
00:05:43.360 For instance, here is how we implemented the badges, allowing designers to visualize the actual achieved design on our staging environment. The ViewComponent file describes the various sizes and variants of the badge component and incorporates validations.
00:06:07.199 Additionally, we have a CSS file that styles these badges based on their variants, and the HTML file for all variants is succinct, comprising around only 10 lines.
00:06:30.560 A noteworthy finding in using ViewComponent is that while you might have a fixed set of variants (like black, green, or blue), you'll often want to add custom CSS at some point. Instead of creating additional variants, you can append CSS classes to your existing classes to create customized styles.
00:07:08.319 Every component can have default data attributes from a Stimulus controller, which you can extend to include additional attributes. This flexibility allows you to avoid rewriting components or creating duplicates, enhancing the adaptability of ViewComponents.
00:07:38.360 Moreover, while some components might be object-specific, there are also general ViewComponents where you can pass various parameters like color or size. For example, in an inventory component, I may pass a specific object to render different aspects of that object based on the data provided. The Ruby file associated with the component encapsulates the rendering logic, making it more manageable.
00:08:30.080 You can also nest multiple components within a single ViewComponent. For instance, I can have a component where I pass a `color` parameter, and it can take on various labels or records, which results in dynamically generated content in the HTML file.
00:08:55.600 Regarding CSS, whether to create separate CSS files for each ViewComponent depends on the case at hand. You can choose to keep all CSS in a single application stylesheet, but if a component has extensive styles, it could make sense to have its dedicated CSS file for better organization.
00:09:01.279 Creating form inputs, however, often poses more of a challenge when building frontend components. I've encountered situations where I needed to construct a custom dropdown or select component with options, including the ability to search.
00:09:20.480 It was a considerable task to ensure these form inputs worked seamlessly in conjunction with the hidden form they are connected to.
00:09:34.800 It’s essential to note that you don’t have to completely abandon templates or partials in favor of ViewComponent. How to structure your components significantly depends on the specific use case.
00:09:54.800 For example, a regular show action would typically utilize a template, but you can opt for a ViewComponent instead if it suits your needs.
00:10:08.360 Let's shift our focus to Hotwire now. I assume everyone is familiar with the basic components of Hotwire, which include Turbo Frames, Turbo Streams, Stimulus, and standard Turbo functionality.
00:10:45.760 It’s worth mentioning that Hotwire is not exclusive to Rails applications; it can be applied in other frameworks as well. For instance, Turbo Laravel is an adaptation of Hotwire designed for use with the Laravel framework.
00:11:06.000 It’s crucial to recognize that Hotwire materials are branded and structured differently, emphasizing that they can exist outside of Rails.
00:11:30.880 A common source of confusion arises with Turbo Streams, as there are two types: HTTP Turbo Streams and WebSocket broadcasts. The WebSocket broadcasts are specific to Rails and do not function out-of-the-box with other technologies.
00:12:45.760 If we imagine a few years ago, many of you may have worked with AJAX and .js.erb templates. In a way, the HTTP Turbo Streams represent a rebranding of those templates where you could replace direct HTML elements in response to user actions.
00:13:10.960 Now, I would like to show you a live demo. Over the past year, we've developed numerous features using Hotwire, and I’ll demonstrate what you can accomplish with it.
00:13:55.520 Here’s an index page presenting a list of records. When I refresh the page, you'll see new records loading asynchronously.
00:14:00.880 As I scroll, new requests are being made to the server, ensuring that rather than loading a single heavy page, only necessary records appear as they become visible. If one record encounters an issue while loading, it won't block the entire page from rendering.
00:14:20.960 Instead of one large request, you can make multiple smaller ones, which is far more efficient. Now, let me show you how the search functionality works.
00:14:55.760 As I type, you'll see the reset filters button appear once filters are applied, and the URL updates without refreshing the page.
00:15:07.760 When I continue typing, the results update in real-time. You can also add filters interactively without any need for page reloads.
00:15:26.880 In the upcoming slides, I will delve into the background of how all of this operates.
00:15:39.680 This new design represents a significant improvement over the previous index page, where functionality lacked the finesse of the current design built with Turbo Streams and Turbo Frames.
00:15:57.840 Here’s a model that appears when you open the page. It’s like a survey form where you can select various options and proceed through stages seamlessly.
00:16:12.560 This approach provides a smooth user experience, allowing for sequential selections without traditional page refreshes.
00:16:25.920 In addition, when you submit the form or change input values, modifications are efficiently tracked, and only relevant changes are reflected, enhancing the overall fluidity.
00:16:48.960 Let me walk you through multi-step forms as well. For instance, I can navigate through selection conditions, and if any errors occur, they can be rendered on the fly.
00:17:11.560 Here’s an API tokens page. In this scenario, you assign a token a name, generate it once, and you can see the token displayed without the possibility of retrieving it again.
00:17:27.040 Another feature I’m fond of is the folder-like structure, which allows for intuitive navigation as you progress through files.
00:17:43.760 In summary, using Turbo Frames makes it exceptionally easy to create models that can work independently of each other, avoiding full-page refreshes while ensuring that only the pertinent content is updated live.
00:18:02.960 Whether viewing a list of items or interacting with the application, loading records separately is seamless, preserving performance.
00:18:12.320 Now, when a user interacts with the page, it will lead to updates for only relevant components without disrupting the entire user experience.
00:18:25.920 Mixing Turbo Streams and Turbo Frames effectively allows extensive customization in how content is rendered and displayed.
00:18:47.040 The asynchronous loading feature is a standout advantage, allowing for separate and customizable user interactions within the same application.
00:19:02.160 In practice, you can create nested Turbo Frames wherein elements can be updated independently based on user actions without any interruptions.
00:19:22.960 This modular structure lets you develop an intuitive framework for handling user content dynamically.
00:19:30.160 When working with Turbo Streams, you'll often have a combination of notifications for specific users and global notifications.
00:19:52.480 Incorporating empty tags for Turbo Frame models and potential placeholders for flash messages is also a common practice among the developers utilizing Hotwire.
00:20:12.320 Each Hotwire application usually includes Stimulus controllers for various components, including dropdowns, tabs, checkboxes, and more.
00:20:30.000 It's important to remember that Turbo Frames, Streams, and Stimulus can function independently. They don’t necessarily require one other to operate, though their integration offers opportunities to create powerful applications.
00:20:52.080 Let me show you an example from one of my pages. As I type something, the main content gets refreshed. Turbo Frame actions allow URL updates while independent Turbo Streams manage the reset filters function.
00:21:14.560 For seamless infinite pagination, you can render Turbo Frames inside Turbo Streams effectively, allowing content to load dynamically based on user interaction.
00:21:39.680 It's remarkable how scalable your application can be with just a few lines of JavaScript in conjunction with the Hotwire stack.
00:21:57.040 The Stimulus framework is relatively easy to pick up and plays a supportive role alongside Turbo Frames and Streams.
00:22:14.320 Let me share another example with dynamic forms. The classical challenge of having coordinated state like country and city selections can be addressed seamlessly through Hotwire.
00:22:28.320 In this example, a hidden button works with a Turbo Frame. When you select a country, it triggers an event that re-renders the state selections based on the parameters submitted dynamically.
00:22:51.040 Challenges arise, for instance, when conditionally adding new fields to a form. It’s crucial to define the HTML structure appropriately so components can interact as desired.
00:23:12.080 Managing the visibility and relevance of form fields effectively balances user experience and application functionality.
00:23:29.920 In summary, ViewComponent plays a vital role in structuring Ruby on Rails monolithic stacks and facilitates effective communication with design teams.
00:23:45.440 Hotwire exists independently of Rails, and utilizing Turbo Frames and Turbo Streams can greatly enhance application capabilities.
00:24:02.720 I encourage you to experiment with both technologies in isolation, as you'll soon discover which functionality suits your specific needs better.
00:24:22.080 Understanding the different types of Turbo Streams is also essential; the HTTP version responds to requests made by the client, while WebSocket updates are broadcast to any listeners of the same channel.
00:24:36.800 With the addition of simple Stimulus controllers, you can extend the functionality of Turbo Frames and Streams, resulting in a more powerful user experience.
00:25:00.320 If you feel you've exhausted Hotwire's potential, remember there are additional frameworks like Stimulus Reflex and Action Cable, which can further enhance your applications.
00:25:15.520 Even in an environment where Hotwire does not exist, other server-side rendering technologies like Htmx or Phoenix LiveView can achieve comparable functionality.
00:25:42.720 As I conclude, I invite you to connect with me on Twitter, and thank you for your attention throughout my talk.
00:25:58.560 Now, I’m ready to take any questions you might have.
00:26:01.360 Thank you for the opportunity to share my thoughts on using Hotwire and ViewComponent effectively.
00:26:07.200 I hope this inspires you to explore these technologies further.