At The Gnar, we’re always reading, watching, and listening in order to keep our skills sharp and our perspectives fresh. Every month, we round up our learnings and publish them in a Gnarly Learnings blog post.
This month, we learned about Turbo from the perspective of React devs, the value proposition of web components, and current trends in serverless computing.
RailsConf 2023 - Hotwiring My React Brain
Over the last several years, I’ve grown more and more familiar with React…for better and worse. Although I initially loathed it, I’ve come to appreciate Facebook’s popular JavaScript library as an effective technology for building snappy web apps.
New tools like Phoenix LiveView and Turbo, however, offer a tantalizing peek into a world less dependent on JavaScript for interactivity.
These libraries render HTML on the server and send them down to the client using WebSockets to offer similar functionality to React and other JavaScript frameworks.
But while the functionality is similar, implementation is a bit different.
In RailsConf 2023 - Hotwiring My React Brain, Aji Slater gave a stellar Hotwire vs React presentation, in which he related Hotwire/Turbo concepts to their analogs in React.
The discussion centered around building an app with pages and chapters, similar to the structure of guides.rubyonrails.org.
For example, they went into detail on how one might re-render a chapter while leaving the rest of the page intact:
[17:50] When Turbo intercepts the click it sends the request via JavaScript, includes a special header – Turbo-Frame and the frame ID. That way the server knows that the page it’s talking to is Turbo enabled.
...we make our first request and receive chapter one. Remember this section of the page is encased in a Turbo frame with the ID ‘chapters’. When we click the next chapter link,Turbo sends a request for chapter two and down it comes. It’s essentially the whole page minus the head tag. Turbo is going to inspect this response and look for a Turbo frame element that matches the one it asked for of ‘chapters’. And if it finds it, Turbo will punch out the old chapters frame and throw it away. It will remove the new 'chapters' Turbo frame, throw away the rest of the response, and switch the new frame in, having only updated the part that needed to change. Sounds kind of React-y, right?
Aji’s comparison here is pretty intuitive for React devs!
They point out that we can wrap elements with turbo_frame_tag
in our erb
files to selectively render those elements. When we navigate to a new chapter, the resultant request includes a Turbo-Frame
header and ID that tells the server what it does and does not need to return.
We could, of course, accomplish similar functionality in React with some sort of Chapter
component and a useState
hook.
Implementing this logic in React would obviously be quite different, but the end result is similar: when we navigate to different chapters, we execute a partial re-render instead of a full page reload.
This leads to a fairly obvious issue though – what about the state of the page navigation (see the left side of the above image)? How does that section of the page know what’s going on with the chapters section of the page?
Basically, this involves providing some more context to the pages section by adding a data
attribute to the partial that renders the chapter links:
[20:45] We can tell this link which frame we want it to swap out by adding a data attribute to the anchor tag.
turbo_frame
tells Turbo to target thechapters
frame from the response, instead of the frame which originated this request.
You may have noticed turbo_action: :advance
in the data
attribute, which tells Turbo how to handle the application visit. Specifying advance
in our Turbo link means the navigation entry will be pushed on to our browser’s history stack; if we instead specified replace
, the topmost entry on the browser’s history stack would be replaced
Aji also points out that we need to add a src
attribute to the chapters/show
view. This tells Turbo to eager load the frame as soon as the frame src
is available:
[22:27] So when the page loads, Turbo will notice the URL [and] fire off that request. But the React version was able to handle a loading state as well, right? Well, the block inside the Turbo frame will be rendered in the same manner as before. It’ll be replaced though as soon as the response comes back.
If this pattern seems familiar, it’s probably because you’ve done something similar in React with useEffect
.
We might envision, for instance, that every time a page
property in the useEffect
dependency array is updated, we change the selected page in the list of chapters. And whenever data is being retrieved, we would swap in a loading state by adding an isLoading
value to the dependency array.
Aji’s talk is chock-full of these insights. So if you’re a React dev looking to dive into Hotwire and/or Turbo, I’d encourage you to watch the full RailsConf 2023 recording.
What Web Components Are Good At with Nolan Lawson
Web Components have been on my radar for a while now. And I think this is true for many devs that spend a lot of time on front-end code.
The idea of creating lightweight, custom components with zero dependencies that can be dropped into any front-end framework sounds amazing in theory…but then, why haven’t I ever really gotten my hands dirty with the concept?
In a PodRocket episode titled “What web components are good at”, Salesforce engineer Nolan Lawson takes some time to explain his views on web components: when to use them, when not to use them, and why some front-end developers (myself included) may have unintentionally avoided them.
[2:20] …so the first case I bring up is to me like the most clear cut case where web components can just be extremely useful, really almost no downsides whatsoever, which is client rendered leaf components.
Nolan’s opinion is that fully client-rendered leaf components are a fantastic niche in which to apply web components. His examples include calendar widgets, rich text editors, emoji pickers, and similar interactive elements that don’t need to communicate with the backend to function.
Crucially, he highlights the fact that web components are framework agnostic (though not all frameworks support web components).
So if you wanted a datepicker in your Svelte web app, you could use date-picker-svelte, but you could also use something like the @vaadin/date-picker web component. Check out this web components list if you’re curious about what sorts of things can be built with web components.
Though most of us React devs gravitate toward React libraries, Nolan points out several advantages to using web components vs React components.
Firstly, using web components can help circumvent the need for bundlers, transpilers, and the vast majority of dependencies.
Secondly, web components can be used across your entire web app, regardless of framework.
[10:00] …more and more big companies, especially when they're building design systems, they're choosing to build them with web components. And when you think about it, it makes sense why they would do that…your company might have teams that are building front ends written in Angular and React and Vue, or in some server rendered framework, they're not even using much JavaScript. And in those kinds of environments… [how] do you write something that everyone can just pick up and use, the consistent experience across all those different stacks.
In other words, web components provide you with a relatively simple way to create a consistent user experience across the various parts of large web applications.
While Nolan makes a great case for using web components for interactive client-side components, he was far less bullish on the use of server side rendered web components.
[18:50] That said, I feel that the server side story for Web Components has not really been written yet
So for the moment, it seems you’ll need a framework specifically set up for rendering web components on the server (e.g., Astro and Lit) if you want to dabble in this area.
Listen to the full podcast to hear more about Nolan’s views on web components, and read the accompanying blog post for more insights.
The State of Serverless (2023)
In August 2023, Datadog released The State of Serverless report for 2023, which examines data from their users to draw conclusions about the general landscape of serverless.
Several things stuck out to me in the report. First and foremost is that, despite the ever-present grumblings about serverless architecture, serverless adoption has continued to gain ground throughout 2023.
Importantly, Google Cloud Platform (GCP) and Microsoft Azure usage is increasing at a faster rate than Amazon Web Services (AWS) usage.
In the case of GCP, this is probably at least partially due to its dominance of container-based serverless offerings. Google led the charge in this arena with Cloud Run, which provides a smoother on-ramp for companies unfamiliar with serverless architectures.
Or as the Datadog report puts it:
…organizations can upload their existing container images to cloud provider-hosted registries and seamlessly deploy those containers as microservices. Serverless container products also support a wider breadth of languages and larger total application sizes compared to serverless functions.
One other finding from the report that stuck out to me was AWS Lambda function cold start times.
More specifically, I was surprised by the fact that Java cold starts took three times as long as Python cold starts.
It seems perfectly reasonable that the overhead of the Java Virtual Machine (JVM) would make serverless Java functions slower…I just didn’t expect them to be that much slower.
But the finding that I found most interesting was the emerging prevalence of serverless platforms focused on frontend development.
This is definitely a trend that I’ve become acutely aware of lately.
The Datadog report mentions big players in this field, such as Vercel and Cloudflare, but there are also smaller players like Deno with Deno Deploy and Bun, which aims to offer specialized edge hosting in the near future.
Each of these platforms has also been striving to offer more and more services to entice customers. For instance, Vercel now offers various forms of storage and Deno isn’t far behind with Deno KV.
These niceties make it simpler and easier to spin up a fullstack app on any of these niche front-end serverless platforms…at the price of potential vendor lock-in. But the tradeoffs for that lock-in may be well worth it for small companies looking for an all-in-one solution.
Gnarly Bytes
- Design: shadn/ui is a neat new component library we’re keeping our eyes on
- JavaScript: Looping over iterable objects with
for await…of
can make your life easier - Ruby on Rails: Adding
-S
torubocop
adds a URL to the cop…you’re welcome - Ruby on Rails: Enums are now validatable without raising
- Ruby on Rails: Calling
to_h
with a block is the same as callingmap
and thento_h
, as long as the result of the map is hashable
irb(main):011> arr.map { |i| ["#{i}foo", i] }.to_h
=> {"afoo"=>"a", "bfoo"=>"b", "cfoo"=>"c"}
irb(main):012> arr.to_h { |i| ["#{i}foo", i] }
=> {"afoo"=>"a", "bfoo"=>"b", "cfoo"=>"c"}
Contributors:
Learn more about how The Gnar builds software.