Svelte for Sites, React for Apps

swyx - Oct 18 '20 - - Dev Community

Translations: 中文版

In 2020, my personal recommendation to web developers is to use Svelte for Sites, and React for Apps. This is, remarkably, a nuanced enough opinion that it pisses off fans of either of them.

I mentioned this in my Shoptalk Show interview and Chris Coyier encouraged me to blog about it. Let me try to explain.

Sites vs Apps

First, I have to make a distinction between (Web) Sites and (Web) Apps. There are serious, intelligent people who insist that there isn't one. They want to build everything on the web with the same tech. Respectfully, they are wrong.

Web Sites primarily display content, while interaction is limited. First-load times are paramount since users may bounce and/or their limited data/power/CPU may deprive them of important information (see Alex Russell for math on a reasonable baseline but let's say you definitely want <200kb in the critical path). This was the web's original usecase - displaying information - and it is what HTML/CSS/Browsers are great at.

Web Apps primarily exist for interaction. CRUD apps, livestream apps, games, whatever. These apps tend to be heavier, which is unfortunate because that affects their performance. But even a 2MB JS app doesn't sound so bad when it is literally competing with a 200MB mobile app, and (let's say) you're developing a B2B app where everyone is on high power and high bandwidth devices anyway. You're typically also keeping apps open longer, so the first-load issue doesn't matter as much (and can be mitigated with service workers). The challenge is even higher once you account for the fact that the Web App must ship with it all the UI components and behaviors for it to work, whereas a typical native app will usually heavily lean on platform-provided components. The web platform still lacks a lot of standard components/APIs and developer experience needed to make writing great Web Apps easy - hence the gap is filled by frameworks.

I view Sites vs Apps as a spectrum. Of course, if your sites dont need ANY interaction at all, don't use any JS. But most sites have app-like features (login, reactions, comments), and many apps need to perform under site-like constraints.

Aside: Check out Jason Miller's Application Holotypes for more thinking on matching the architecture of a web project to its intended use.

You'll notice that most businesses already recognize this - www.mysaas.com is the marketing site, app.mysaas.com is the app. They may start out the same codebase, but due to the vastly different requirements, they eventually split into different codebases and then different teams handling them. It's usually the idealist enthusiasts that try to make the same tech work for these clearly different purposes.

React for Apps

React has been open sourced for 7 years now. It is used in production at the biggest companies and sites in the world from Apple to Twitter to Amazon to Airbnb to Uber. It has been the most cited technology in Hacker News job postings for at least 36 straight months. There are between 3-9m React developers, growing at least >50% annually. The third party ecosystem is vast and attracting instructors, developers, companies and hundreds of millions in corporate and venture funding.

Based on that alone it is a good tech choice to base your app on already. But these are contingent facts that don't really have anything fundamental to do with React's merits. This is offensive to first principles thinkers. So let me offer some core reasons why React is a great choice for apps:

  • React Native looked troubled in 2018, but the current team seems to be executing well (as far as an outsider like me can tell). Flutter may yet give it a run for its money someday, but has the Dart and Google hurdles to overcome. React Native is the best cross platform (mobile+web+desktop) "Write mostly once, run mostly anywhere" solution in tech today. If you have the resources to hire platform specialists, you won't find this useful. However, if, like the vast majority of companies, you can't afford a dedicated team of specialists per platform, React Native is your best bet.
  • React has by far the most experience in abstraction design. Where React leads, other frameworks follow (Both Vue's Composition API and Svelte 3's $: API directly credit React for inspiration, as do Swift UI and Jetpack Compose). This isn't to say they always get it right (pop quiz: how many Context APIs are there in React?) but when Concurrent Mode and React Flight are released, I expect it to be deeply informed by production usage at the biggest websites in the world. Suspense for Data Fetching, still not yet released, has been in production at Facebook for over a year. I want to stress how unusual this is - typically in open source, you release something and then hope it gets picked up by a BigCo and tested at scale. With React, Facebook dogfoods it at scale before releasing to the general developer community, with many ideas killed before they are publicly blessed, because flaws were found. Judge React as much on what it doesn't ship as you do on what it does ship.
  • That brings me to governance. It's not perfect (many people have issues with Facebook, for one thing), but I think React is one of the best run open source projects in the world. Normally mundane things like versioning policy to error messages to release channels to gradual upgrades matter at the scale of React. The team also does a lot of informal collaboration with key ecosystem partners like Gatsby, Apollo and Next.js, including at the browser level with Chrome and the language level with TC39. The team not only deeply cares about technical governance, but also fostering an inclusive and diverse community.
  • I hesitated to mention this last point because it technically has to do with adoption, but I cannot separate it from React's merits: it seems to have the best thinkers on accessibility and interaction design right now. No other ecosystem has projects like Adobe and Devon Govett's React Aria that has extensively thought through and tested for WAI-ARIA so you don't have to. Ditto Segun Adebayo's Chakra UI. Or listen to Rick Hanlon on the Touchable Web and realize how much web apps need to improve for the open web to reverse its alarming decline vs. mobile walled gardens.

    • Let me be clear - is the React community ACTUALLY good at these things today? Hell to the no. Most of them are still debating whether or not to learn hooks vs class components. BUT React has the best shot because it has the best abstractions that enable the best thinkers to create the web application standard library we all want.
  • Selective and Progressive Hydration are particularly interesting results of the Fiber rewrite. Together with a "full stack" future of React that lets the developer easily move code and execution between client and server, the hope for making apps that feel fast without compromising on developer or user experience is extremely strong.

You can, of course, use React to make sites. Gatsby and Next.js (and the upcoming Remix) are great static and serverless rendering options (The "greatness" of Gatsby is disputed). Docusaurus is great for docs sites. If you are making sites and are worried about JS weight, you can usually swap Preact for React in a few lines of code because you will usually not be running into any of Preact's compromises if you are just making a site.

So why do I advocate using a different framework for sites?

Svelte for Sites

Specifically, Svelte for Interactive Sites

Svelte is used in production
from the NY Times (of course) to Square Enix to Apple to Spotify to Google Arts to Alaska Airlines and hundreds more, with other big dev platforms like Amazon and Microsoft also increasingly featuring it in their content. It has a lively community with the first podcasts, YouTube channels, schools, conferences and newsletters emerging. Svelte 3 has been wildly successful and yet it is still early days.

I'm going to let you in on a little secret: Svelte and React aren't that different. Take a look under the hood of Svelte compiled output:

function create_fragment(ctx) {
  // redacted
}

export default class App extends SvelteComponent {
  constructor(options) {
    super();
    init(this, options, null, create_fragment, safe_not_equal, {});
  }
}
Enter fullscreen mode Exit fullscreen mode

Wtf? class App extends SvelteComponent?? That looks like React??

Yes. Wait til you realize that = basically compiles to setState, or that yes, it does actually ship a runtime, or that yes, it actually has a scheduler too. Like I said, where React leads, other frameworks follow. React proved Components are the right way to go.

This also means that most React developers can learn Svelte in hours so the switching cost is low.

The differences are large enough, though, in everything else:

  • JS Weight. Your site might get green Lighthouse scores, but hopefully you agree that you ideally only ship JS that you use, for your users' sake. Svelte sites are often single digit kilobytes. React+React DOM is ~120kb uncompressed. You can of course slash this severely if you can switch to Preact. But Svelte offers the smallest measured runtime footprint. We used to worry about the compiler output overhead exceeding the size of React components (smaller runtime = more boilerplate), but recent studies have debunked this concern completely.

    • But my consideration of JS weight extends beyond just the framework. Anecdotally, the kind of people that are drawn to Svelte seem to be more performance-minded than those in React (see everything that lukeed makes). This comes from the top - where React devs often import heavy dependencies as long as they kinda fit the usecase, Rich Harris is the kind of stubborn developer that makes his own version of everything because he just needs it to do a smaller job. But also, Svelte is most people's second framework, so they come to it with more of a performance mindset. Collectively, the dependency choices encouraged by the framework's culture also impact the end result of JS weight.
    • I am even encouraged by the emerging JAMstack culture in Svelte, where Nick Reese has made an excellent implementation of Jason Miller's Islands Architecture with Elder.js. (TL;DR - typical Gen-2 SSG's send JS to rehydrate the entire page, even the content that doesn't change, whereas Islands Architecture sites only send JS to hydrate dynamic parts of the page and leave the rest untouched.)
  • Scoped styles. Need I say more? The way Rich Harris puts it, goes something like this (poor phrasing is my fault): "In my opinion, a frontend framework should give you a styling solution" (fun aside: watch the React Core Team debate styling solutions! They feel the pain). Not just styling, but transitions and animations too. Ask any React developer what styling/animation solution to use, and watch them squirm or give you a PhD length dissertation of 5 subtly different alternatives. I say this with some irony, because I myself use Tailwind with Svelte.

  • Full Sitemaking Toolkit. It's not just styles and animations. State management? Head management? Class toggling? Tween/Spring effects? (soon) Routing? All are one import away. Because of Svelte's design, you can use as much or as little as you like, but at least there is a first party option for everything.

    • React takes pride in its minimal surface area and relies on its ecosystem to fill in the gaps. Choice is good and a big part of React's popularity and longevity.
    • But I've lived with the ambient anxiety of having to stay informed and choose and set up every goddamn part of my frontend stack for years at this point, and it really is not productive. Look, maybe I just suck at this. Or maybe I just need a more productive stack that aligns with my preferences.
  • Svelte is a superset of HTML. Svelte is actually not just a toolkit, it is also a language designed to make the web developer more productive. That means that SVG "just works". That means that you can work with classes. That you can work nicely with Web Components (both exporting and importing). A lot of little things you make apologies for with React and JSX.

  • Svelte's downsides matter less when making sites. Svelte has a much smaller ecosystem and community, but that matters less when you're making sites, since you're going to be mostly making your own designs and interactions anyway. This is certainly how Rich uses it at the New York Times - not relying on the ecosystem. The smaller hiring pool is also less of a concern since you typically wouldn't be hiring the same size team you'd need to maintain an app.

    By the way, we are working on building out the Svelte ecosystem by helping to grow the Svelte community - Svelte Society was started a year ago in a dinky little Microsoft room - check out Svelte Summit if you are reading this on 18 Oct 2020!

  • If you STILL needed to ship features in React, you could mount it atop of a Svelte app if you wished. It would make less sense (because you'd already be paying the library footprint size) to do the opposite, so it just makes sense to have Svelte as the baseline.

Aside on Render Performance and Virtual DOM: The importance of a "Virtual DOM" is a big bone of contention between React and Svelte (Tech Twitter folks will remember the 3d "benchmarks" from last year)) but to be quite honest the kind of pedestrian sites and apps that you and I write don't even run into that kind of perf demands, so I don't count it.

I've written more thoughts on Why I Enjoy Svelte, but these are the two salient points that lead me to pick Svelte over React for my own interactive sites.

Why use frameworks at all?

Of course, webdev being webdev, we aren't done discussing the full complexity of this sort of tech stack choice. The other concern people have comes from the opposite direction - if you're just making a site (interactive or otherwise), why use a framework at all?

It's a valid question - after all, perfectly good, fast, battle tested solutions exist from Hugo, Jekyll, Eleventy, and so on. They generate zero JS by default, and then let you "sprinkle on JS" as needed.

My current answer here is more about mental model. I want to code using components, and I want an easy upgrade path to add interactivity to something that wasn't previously interactive. None of those more traditional site generators let me do that. I'm not sure that this line of argument is convincing to the "no frameworks" crowd, but it is true for me.

The Philosophical Big Picture

I want to share with you a deep realization I had, that is going to sound extremely underwhelming at first:

Tools-designed-to-make-small-things should work very differently from tools-designed-to-make-big-things.

Well, duh, right? At the surface, this is just a restatement of the tired "Use the right tool for the job" cop-out, which I have my problems with.

But no, this is subtly different. I am insisting that what looks like the same job, at two different scales, are actually different jobs. Different enough to justify using different tools.

Further, when we ignore this and try to make the tool do everything, we make the tool worse for everyone - more confusing to learn, more API to remember, and often a degraded end user experience from making too many tradeoffs.

In the rush to satisfy everyone, we delight no one.

Aside: The reasons we do this are complex. Sometimes devtool companies do it because they feel they need it to grow. Other times hackers just do it just to show that they can. I pass no judgment here, it is always worth trying to push limits.

This is the high level takeaway I have in the React vs Svelte debate. It's exposed most clearly in the public statements that the React team have been making (PLEASE DO NOT CROSS EXAMINE THEM ON THIS, THESE ARE MERELY OFF THE CUFF STATEMENTS ON PERSONAL SOCIAL MEDIA):

  • Dan Abramov: "A “disappearing framework” is certainly cool and worth striving for. But it doesn’t help much when the framework is 5% of your code. Say “disappearing app” and I’m listening."
  • Seb Markbage: "This is from an internal perf investigation I did. We also see similar numbers in all real significant apps. This is the percentage of all JS time and about 5% is the time spent creating the actual DOM nodes so it’s inherent. The framework code is about 8%. We could optimize those 8% and use various other tradeoffs. To save maybe 7% of JS execution... However that hides 87% of the JS executed in actual apps. That’s what we need to focus on."
  • Dan again: "I think overall it's true that we're a lot more focused on optimizing the application size over the library size. Because the library size is relatively constant, whereas the application size keeps growing. lazy() is an example of that, but there is a lot more we need to do."

The thing is... React's library size is 120kb (uncompressed). What size of app are you targeting for React to be 5-13% of total JS? 1mb-2.5mb. Is your site/app anywhere close to that?

The ground facts are these:

  • React is without question the best framework for making apps and getting better
  • the React team is more focused on apps than sites
  • While they really care about community, React is made for Facebook needs first and foremost
  • You Are Not Facebook
  • Your site is most definitely Not Facebook
  • You probably don't use all the features React ships
  • Even if you use Preact instead, the P/React ecosystem doesn't give you enough out of the box to be productive
  • There should exist a better and different toolkit for making interactive sites.
  • The best langauge for that today is Svelte.

Svelte for Sites, React for Apps. Q.E.D.

P.S. for the apoplectic Svelte fans: yes of course you can use Svelte to write Apps too. Let people realize that on their own. Make the case where you can indisputably win, where adoption is easy and lower cost, rather than fight every battle on every front even where circumstantial facts weaken your case.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .