I'm currently working on a giant React frontend codebase and it's baffling how slow certain simple things are for our users. Yes it makes it easier for us to reason about, but performance should be able to scale without hacks.
Svelte seems to show a lot of promise, but I have a few things that I'm not 100% on.
1. How are the higher level abstractions for Svelte? Any framework can be easy for simple applications, but how easy will this be to reason about as we get to larger applications? React deals with this through a semi-functional mindset. What does Svelte offer?
2. Is there any plans for facilitating incremental rollouts? Changing your application to an entire new framework is not always worth it, and is greatly difficult. I could imagine Svelte being incredibly useful for large-scale, performant applications. However, unless it can be incrementally rolled out, then I can't see how the biggest players will be able to utilise the power of Svelte.
I'd love to see the game changed in web frameworks, and I love the idea of using compilers where possible. If anyone could answer these queries, I'd be very much grateful.
Our vision for how to build large apps with Svelte is best represented by Sapper — https://sapper.svelte.technology — which is a Next.js-style framework. Right now it's a bit out of date, we need to spend some time bringing it in line with Svelte 3. That'll happen fairly soon.
Svelte is pretty well suited to incremental rollouts, because it doesn't have a chunky runtime foundation — it's not as though you have to ship two full frameworks simultaneously. There are some community-maintained adaptors for using Svelte components inside apps for other frameworks, I believe. You basically have to start at the leaf components and work your way in. An alternative approach would be to compile Svelte components to custom elements instead, since they can (in theory!) be used anywhere.
> I'm currently working on a giant React frontend codebase and it's baffling how slow certain simple things are for our users. Yes it makes it easier for us to reason about, but performance should be able to scale without hacks.
What's the underlying reason for the slowness?
React applications can definitely be written to be performant without resorting to "hacks", typically using immutable data structures (that support reference equality checking) in combination with judicious use of PureComponent/shouldComponentUpdate/React.memo. Also using something like react-virtualized/react-window for large lists/grids.
I've never worked with React, but I have worked on giant AngularJS (1.x) apps and medium-sized Vue apps. I've only seen performance issues on pages with long repeated lists that create a lot of $watchers. This is fairly straight-forward to solve, and I know that Vue and Angular are both a lot smarter about tracking changes than AngularJS was.
Is React more difficult to keep responsive as an app grows? What sort of UI paradigms lead to poor performance? Just the phrase "using immutable data structures (that support reference equality checking) in combination with judicious use of PureComponent/shouldComponentUpdate/React.memo" makes it seem like you need lots of in-depth React knowledge and additional packages to write a performance React app.
React's default behavior is that when a component re-renders, React will render all of its children recursively, even if they are receiving the exact same props as before.
In many cases, these re-renders return the same render output as the previous render, which means that no changes need to be made to the DOM. These renders are referred to as "wasted", because React went through the work to ask your component "what do you want the UI to look like?" and diffing the output, when nothing actually was going to change.
The two key aspects of optimizing performance in a React app are:
- Decide if the props and state for this component have meaningfully changed
- Tell React to skip the rest of the rendering process for this component (and therefore skip the rest of this subtree as well)
The standard approach for checking for changes is simple reference checks: `prevProps.a === props.a`. For larger amounts of data, this assumes you've updated that data "immutably", by making copies and modifying the copies instead of the originals. This can be done with plain JS objects and arrays, it just can take a bit more diligence. (Libraries like Immer [0] can help with applying those updates immutably.)
For the "skip rendering" part, React has offered several APIs over time, but they all basically boil down to "do shallow comparisons of data, and bail out if they're the same":
- The old / deprecated `createClass()` API allowed use of a `PureRenderMixin`
- Classes have a `shouldComponentUpdate()` lifecycle method where you can implement whatever custom comparison logic you want, and return `false` if the render should be skipped
- Since the typical comparison in `shouldComponentUpdate` is a shallow equality check of both props and state, the `PureComponent` base class was added that does that by default
- More recently, the `React.memo(MyComponent)` API was added to allow wrapping any component (class or function) with that same bailout behavior.
All of those are actual React APIs, not separate packages.
All that said, the React team advises that you should just write the app first, _then_ profile it later (in a production build!) to see where the key bottlenecks are and just optimize those. In most cases, you probably don't even have to do anything - performance will often be sufficient as-is.
React's DevTools have a performance profiling tab [1] [2] that helps show which components rendered for a given update, which makes it a lot easier to track down unnecessary renders. The community has also created various "why did you update?" libs that log unnecessary renders.
Svelte seems to show a lot of promise, but I have a few things that I'm not 100% on.
1. How are the higher level abstractions for Svelte? Any framework can be easy for simple applications, but how easy will this be to reason about as we get to larger applications? React deals with this through a semi-functional mindset. What does Svelte offer?
2. Is there any plans for facilitating incremental rollouts? Changing your application to an entire new framework is not always worth it, and is greatly difficult. I could imagine Svelte being incredibly useful for large-scale, performant applications. However, unless it can be incrementally rolled out, then I can't see how the biggest players will be able to utilise the power of Svelte.
I'd love to see the game changed in web frameworks, and I love the idea of using compilers where possible. If anyone could answer these queries, I'd be very much grateful.