Ryan Carniato, creator of the Solid.js framework, identified eight ways to reduce JavaScript code in web development at this year’s International JavaScript conference.
Yesterday, The New Stack shared Carniato’s first four “go-to” methods for mitigating heavy code. Today, we share the next go-to step — HTML streaming — plus three strategies that offer more “radical architectural approaches” to cutting down on JavaScript.
5. HTML Streaming
HTML streaming basically allows you to send the page and data in chunks as it completes, Carniato said. This is not strictly a hydration technique and it doesn’t impact JavaScript size or execution, but it’s important to understand its role in frameworks and why, for instance, the React project was excited to add it in React 18, he said.
He showed a Kroger app on the right that drew in boxes of content versus a version of the app on the left that loaded everything at once.
“They both basically load in at the same time, but the one on the right [the streaming app] basically can draw the shell, because it really depends on states, the data, and, then the one on the left that has to wait for everything is quite a different user experience,” he said. “The one on the right almost looks like an interactive single page app with loading state and stuff. But the truth of matter is this can be done without actually even loading the JavaScript framework […] it’s just a small script tag.”
The page works by sending the HTML (including the placeholder) first and then, without closing the connection on the server as the page finishes, it adds the missing parts of the page to the end of the document, via a script tag. The script page basically swaps the content into place to replace the placeholders. React, Solid and eBay’s Marko.js support this approach, he added.
“The benefit of streaming, especially for larger services, is this ability to be able to decouple slow responses, unpredictable responses, so that the overall reliability of your system can be better,” Carniato said. “As I said, only a handful support it today, but luckily React is in that handful, which means that you can use streaming, Next, Remix and a lot of common frameworks.”
These first five techniques are all good mitigation techniques for improving the situation and bringing resiliency or removing server bottlenecks to a page. But they don’t change the amount of JavaScript executed or loaded in a meaningful way, Carniato said, before demonstrating more “radical architecture” approaches.
6. Islands — a.k.a, Partial Hydration
“So welcome to the tropics, more water — islands, also known as partial hydration, are not a new technique, but they didn’t really get popularized till more recently,” Carniato said.
Web design with Islands
The concept of this partial hydration was introduced in Marko.js at eBay back in 2014, but it’s been popularized since Astro and Fresh introduced it as “islands,” he said. Islands are an updated take on multi-page applications, he explained. The concept is simple, according to Carniato: A developer looks at the app as sections and renders the sections almost like separate apps acting independently.
“The big win here over some of the older technologies is that because it’s all written in JavaScript, and in JavaScript backend, those islands get to be written in the same frameworks that you’re familiar with — stuff like React — and they work isomorphically,” he said. “So you can have a full backend, or at least a web server in JavaScript, and you have this ability to basically author things, the way we’ve been doing with single page apps — except [the] benefit is that all those white sections never need to be sent to the browser. “
The trade-off, however, is that it brings back full-page reloads.
For instance, if you’re fetching data on a server, you can have some kind of island wrapper, then the server renders a list into it, and each of those items will be in a client wrapper and have their content still be on a server, he said.
“The reason you would do this is that those client components only need to send the data that gets passed to them via their props coming in,” he explained. “So any data that is used purely for server rendering and static doesn’t need to be sent to the client. If you don’t need to use it to, say, do some piece of interactivity, then it doesn’t end up in that big next JSON blob at the bottom. So in a sense, this actually not only reduces the JavaScript, but solves double data.”
Carniato calls it double data when developers want data used on the server to hydrate in the client, which requires the whole thing to be serialized. The data essentially renders as HTML, then it renders again on the initial page as JSON, he explained.
“Partial hydration is great at reducing the amount of code that reached the browser, but what about that last 15, 20%?” he asked.
ebay results with Islands (left) and without (middle)
7. Resumability
That last mile is where resumability comes in, Carniato said. Resumability is the ability of a framework to resume execution of an application where it left off on the server.
It works by serializing the application state and sending it to the client as part of the server-rendered HTML. When the client receives the HTML, it can deserialize the application state and resume execution of the application.
“Basically, we wouldn’t need to actually run anything except attach those event handlers, when the page loaded up,” he said. “At least in theory — it’s a little bit more complicated than that. But you can take a snapshot, attach a few event handlers, and then basically the first time you click on something on the page, it basically knows where it left off and can just apply it.”
Resumability’s impact on web pages.
There is a cost to serialization, he warned, but the execution cost is almost zero and there’s basically zero scaling cost.
“That is a very interesting way to attack that last bit of what’s left, and as it turns out, breaking up the code where the entries are event handlers, conceptually, lets us identify [and] tree shake out even more code, in some cases [more] than islands,” he added.
But there are things that developers want to persist on the page, and being an application means more than having client-side animations, he said; that’s where hybrid routing comes into play.
8. Hybrid Routing
“What we need to do here is [to] kind of diff the content coming in so we can preserve our stateful client islands,” Carniato said. “Just because we get new content doesn’t mean we should lose the current state. That could be stateful data, it could be the focus of an input on your page, one on one.”
The tricky thing is, if you’re not, if you just try and swap parts of the DOM, and then maybe swap other parts. You could think something persisted, but once you remove an input element from the DOM, focus goes away — like little funny things, like the animation states. Diving is a good way to solve that, but there’s something else that’s needed, he added. For instance, reloading the whole page may be too heavy.
Almost every framework now on the client side has a nested router.
Hybrid routing diagram
“Maybe there’s a listing of items on the page. Each of those navigations means that when you click or change that navigation, you only have to swap out a certain section of the page,” he said. “If you change the side navigation, then everything on the right side swaps; if you change the tab bar, everything below the tabs swap. So that’s the idea behind nested routing.”
Developers can use that idea to do partials as a mechanism to basically do a hybrid routing solution, he suggested.
“If we make our islands the size of say a whole route, all we’re doing then is passing the props into some giant island. So we basically have kind of a JSON API, because you switch the route; and then suddenly, you’re just serializing the props to that island and you’re not really rendering any HTML,” he said.
When developers persist the state in islands and add client-side routing, that’s basically what React server components are, he said. There are variations on this theme; for instance, Astro recently added support for persistence in their view transition API, he said.
Astro offers some client-side routing and Qwik has been working on something similar called containers, which they’re designing from micro frontends, he said. He also said Solid has worked up some demos on the approach.
“There’s a lot of innovation that’s going on, and there’s a lot of complexity that follows this,” Carniato closed. “As we work through best practices, [it] is likely that the next JavaScript framework or project you work on will employ at least some of these techniques, if not all of them. And your application will be better for it.”
TRENDING STORIES
YOUTUBE.COM/THENEWSTACK
Tech moves fast, don't miss an episode. Subscribe to our YouTube channel to stream all our podcasts, interviews, demos, and more.
Loraine Lawson is a veteran technology reporter who has covered technology issues from data integration to security for 25 years. Before joining The New Stack, she served as the editor of the banking technology site Bank Automation News. She has...