Hi friends đź‘‹ Happy Tuesday, and Happy National Dog Day to those who celebrate. Woof!
Last week, a reader mentioned the newsletter had been landing in their spam folder for some time. After some debugging, I learned that my DKIM record wasn't set up correctly (I also learned what DKIM was), so I fixed it and hopefully today's issue will make it safely to your inboxes. If you haven't heard from me for a while, welcome back! You might want to check your spam folder.
In today's issue: a short essay in defense of Single Page Applications, a fresh code showdown to spice up your week, and the usual roundup of interesting links.
Let's dive in.
MAXI'S RAMBLINGS
Stop Trying to Kill the SPA
Ah, the noble Single-Page Application. The pattern that gave us Gmail, Google Maps, and the 56 tools your company’s HR department vibe-coded last week continues to be the most popular way to build websites these days.
And you know what they say about popular things—everyone loves them unconditionally and no one ever criticizes them. (Yes, that was a joke.)
The latest wave of “SPAs are ruining the web” chatter was sparked by Jono Alderson’s piece It’s time for modern CSS to kill the SPA. In his article, Jono brings up the usual “SPAs are evil” arguments: they ship too much JavaScript, they tend to be slow, they can hurt SEO, and they may or may not be connected to the disappearance of several kittens in the Pittsburgh, PA area.
Jono argues that SPAs were a useful stepping stone to help push the web forward during the 2010s, but now that the web platform is catching up with features like view transitions, speculation rules, and the b/f cache, it’s time for us to move forward and declare SPAs dead once and for all.
This isn't a new sentiment, of course. Over the last few years, SPAs have been called a mistake, problematic, the architecture no one needs, and much worse. People have been trying to get rid of the SPA pretty much since it became a thing.
But that feels unfair. SPAs never hurt anyone (unless you count those Pittsburgh kittens, and the evidence there is circumstantial at best), so we should probably stop trying to kill them.
Contrary to what many would like to make you believe, SPAs aren’t evil. Sure, a lot of them are slower than your traditional multi-page application (and for no real benefit), but that isn’t an inherent trait of SPAs; it’s likely just poor architectural choices. When done correctly, SPAs have many advantages over traditional websites:
- They’re cheaper and simpler to deploy: you don’t need to pay for compute on a server to render a client-side SPA. You only need a bucket for static assets and a CDN, which you can get for the loose change in your sofa or even for free. Client-side rendered SPAs are the ultimate “edge computing” pattern: rendering happens as close as possible to the user devices—on the user device itself.
- They enable powerful app-like patterns: if you’re trying to achieve a native-like experience, nothing beats an SPA. As the self-proclaimed biggest fan of view transitions, I would love to agree with the claim that cross-document view transitions can entirely replace the experience of an SPA, but that just isn’t the case. Powerful patterns like real-time sync and offline-first apps, like the ones we talked about in the last issue, are only possible thanks to good ol’ SPAs that run most (all?) of their rendering logic on the browser.
- They give us a smoother developer experience: this isn’t really a trait of SPAs, but of the frameworks people use to build them (i.e., React). I still think it’s fair to mention it here because a lot of the hate against SPAs is really directed towards React and other similar frameworks, and it’s uncalled for. Developers choose component-based frameworks not because they’re faster or superior to native alternatives like web components, but because they offer a much more enjoyable developer experience.
This doesn't mean SPAs are off the hook, of course. Critics like Mr. Alderson raise valid concerns, and I think it's only fair to address them—with a little extra nuance sprinkled in for good measure.
First, it is entirely true that many SPAs are bloated and painfully slow to use (I’m looking at you, WEX Health benefits portal). As I mentioned earlier, this isn’t necessarily a problem of all SPAs, but it is true that SPA frameworks make it easy for us to ship way too much JavaScript without noticing it.
I will say one thing, though: a lot of the anti-SPA comments are some variation of “Look at how much JavaScript Next.js is shipping!”, but they fail to mention that this isn’t always a bad thing.
The first rule of web performance is not “make the bundle as small as humanly possible”, it’s “know your audience.” And your audience may not even notice that extra 500 KB of JavaScript.
Not every site needs to perform well on a 15-year-old Xiaomi smartphone over a 2G connection. For a lot of web apps out there, the out-of-the-box performance of frameworks like Next.js is more than good enough, and optimizing it further would make little to no difference to their experience. If performance is really important for your audience, then it should be an architectural driver and it should be involved in every decision you make. Including, critically, whether you should use an SPA or not.
The other argument I agree with from Jono’s article is that a lot of SPAs shouldn’t be SPAs at all. I’ll echo his advice: don’t build a website like it’s an app.
Most websites aren’t apps.​They don’t need shared state. They don’t need client-side routing. They don’t need interactive components on every screen. But somewhere along the way, we stopped making the distinction.​Now we’re building ecommerce stores, documentation portals, marketing sites, and blogs using stacks designed for real-time collaborative UIs. It’s madness.​A homepage with six content blocks and a contact form doesn’t need hydration, suspense boundaries, and a rendering strategy.​It needs fast markup, clean URLs, and maybe – maybe – a bit of interactivity layered on top.
This is good advice, but I have one more caveat to offer here: the fact that your website shouldn’t be an app doesn’t mean that you wouldn’t benefit from using a framework. Astro is a perfect fit for all of the use cases in the quote above. You can build super-fast apps, with zero client-side JavaScript if you want to, while still taking advantage of great tooling and the ergonomics of modern frameworks.
The bottom line is that both things can be true: the web platform is getting better and more powerful every year, and SPAs continue to be a great fit for a ton of use cases.
The best thing about features like View Transitions, speculation rules, and the Popover API is that any website, SPAs included, can get work done with a lot less client-side JavaScript. SPAs vs. the platform is a false dichotomy. In reality, it’s a win-win: when the web platform wins, SPAs win as well.
🥊 CODE SHOWDOWN
Looping Through an Object
Welcome to the Code Showdown 🥊—the section in which Frontend at Scale readers fight to the death over tiny differences in a piece of code.
For the third-ever showdown, we have a special edition with three contestants, each one representing a different way of looping through a JavaScript object:
- for...of
- for...in
- Object.keys() + forEach()
There can only be one winner. Choose your champion by voting in the poll below. I'll share the results in the next issue.
Voting in polls is only available in the email version of the newsletter. To participate in the next Code Showdown, subscribe to Frontend at Scale below!
WEEKLY SNACKS
Links Worth Checking Out
- Speaking of the web platform and SPAs, Tony Ennis gave an interesting talk at Big Sky Dev Con last month, sharing his vision for a path to platform & SPA parity. Tony is one of the maintainers of MiniJS, a library that lets you add interactivity to your apps directly from your HTML. As you learned from my ramblings above, I don't think SPAs need replacing, but I'm always happy to see folks continuing to innovate in this space.
- Sam Rose is back with a new interactive blog post on Big O notation. It's a super fun read and likely the clearest introduction to Big O you'll find out there.
- And if Sam's latest blog post isn't enough to satisfy your thirst for fun and interactive articles, Josh Comeau's Interactive Guide to SVG Paths is one you definitely don't want to miss out.
- You might have heard about the hottest new role in tech: the Forward Deployed Engineer. If you were wondering, "What does a Forward Deployed Engineer even do?" but you were afraid to ask at this point, the folks at Ramp got you covered in this article.
- JoĂŁo Melo from the Resend team put together a great write-up with his key principles for building AI-first applications. Apparently, there's a bit more to building an LLM wrapper than just wrapping an LLM.
- Antoine Finkelstein built a sync engine using SQLite and the Broadcast Channel API, and wrote a short blog post to tell us how he did it.
- This article by Glyn Normington on dealing with developers' block made me feel seen. If you're feeling that "your wheels are spinning and you need to gain traction", give this one a read.
- Today I Learned about the concept of Minimum Viable Documentation and other great tips for writing docs quickly in this post by Fabrizio Ferri Benedetti.
- A joyful write-up by Stanko Tadic on how to draw Space Invaders using SVG paths.
🛠️ NPM Install This
- ​OverType — The Markdown editor that is a textarea.
- ​assistant-ui — A TypeScript + React library for building AI chat user interfaces.
- ​Fancy Components — A growing library of ready-to-use React components and micro-interactions to make your website pop!
​
🥊 CODE SHOWDOWN — LAST ISSUE'S RESULTS
Reduce vs For Loop
The results are in: in our previous issue, I asked you whether you preferred to iterate an array using a reduce() call or a traditional for loop, and exactly two-thirds of you chose the former option.
I think I'm starting to see a pattern here. Let's see what this week's showdown tells us.
That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)
Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.
I read and reply to all of your comments. Feel free to reach out on Twitter, LinkedIn, or reply to this email directly with any feedback or questions.
Have a great week đź‘‹
– Maxi