Wow, just learned of Svelte from this. After reading their explanatory blog post and coming upon this blurb:
That all changed with the advent of hooks [React and Vue],
which handle state in a very different fashion. Many
frameworks started experimenting with their own
implementations of hooks, but we quickly concluded it
wasn't a direction we wanted to go in
...
We can just use the language. Updating some count value — and
all the things that depend on it — should be as simple as
this:
count += 1;
That's super exciting to me, as it puts the emphasis back on solving the task at hand and instead of framework nuances around state management. Will definitely be keeping my eyes on it.
Svelte seems promising. I think it's a natural evolution from what I think is an over focus on FP and purity in React, to a more natural and intuitive DX without significant drawbacks.
Svelte does have an irritating wart IMO, citing their tutorial:
Because Svelte's reactivity is triggered by assignments, using array
methods like push and splice won't automatically cause updates.
So for reference types that are mutated in place you need to do something like:
This looks like a leaky abstraction to me since it forces the developer to work according to the implementation details. Don't know how easy it would be to fix this.
Since Svelte is a compiler I was thinking they could wrap the exported variables in an observable of some sort and make any method call on the reference variable trigger a value update behind the scenes. I have now idea how costly/complex that would be though.
Also, maybe it's a conscious choice and they want to make any data update explicit with reassignment.
I'm a huge fan of persistent data structures such as those implemented by immutable.js. The "normal" way that I would update an immutable.js List is just:
numbers = numbers.push(numbers.length + 1);
Maybe it's just a coincidence, but Svelte seems awfully congruent with the pure FP way of doing things.
FWIW, MobX lets you mutate state in the same way. It does require you to make use of its observer/observable functions to make things reactive, but in general it works amazingly well. I strongly urge everyone to try it!
Agreed. I feel so weird seeing everyone messing around with hooks while all the time I've been using what feels to me like a much simpler better solution.
It seems like you're splitting hairs. React had a new syntax. Svelte has a new syntax too, albeit a familiar one.
You can call Svelte's syntax 'templates' if you want, but if you do, you should call JSX a 'template' syntax too. You seem to be saying templates are bad, which is fine, but a vdom and a compiler are both sufficiently different from, say, mustache templates and you seem to be favoring React for no technical reason.
> Familiarity != simplicity.
Sure. But you literally just said:
> That's what happens when you create your own template syntax...again.
Which seems to indicate you preferred familiarity.
I'm not really sure what your argument is except pointing out that you prefer React. OK.
Preact diffs against the real dom and is faster than Svelte in benchmarks while the library is only around 3.5kb (the minified code fits easily on a single screen). I'd note that authors from most of the frameworks represented have submitted their own optimizations, so performance isn't strictly based on the author's familiarity.
InfernoJS is massively faster than Svelte or Preact (the benchmark author had to do some rather convoluted re-writes of vanillaJS over the years to keep ahead) and it uses a virtual DOM, but has a few optimizations that React doesn't have or can't use due to its external API.
stdweb is the real thing to keep your eye on as it seems to show that WASM can be every fast. They still haven't gotten the vanilla benchmark up to the same speed.
React's Fibers do some cool batching behind the scenes which means that large updates (especially constant ones like animations) don't have large negative impacts on user interaction. I doubt this would be possible without a vdom or something very similar to track all changes before deciding batches and update priority.
Also, remember that vdoms have gotten a lot more efficient too. Newer ones can do things like re-use existing sub-trees or recycle vdom objects (they can also recycle the associated real DOM nodes too). Preventing all that extra garbage goes a huge way toward keeping those vdoms efficient.
As to svelte in particular, you aren't "just using an equals". It actually compiles behind the scenes into a completely different set of reactive code. This gets at my biggest issue with such frameworks. Their abstractions aren't free. I have to learn their proprietary syntax and markup. I then have to learn how their compiler works behind the scenes when its time to debug the code I wrote. When I compile a React-style component into ES7 and run it in the brower, I have to deal with webpack for imports and I have to understand that JSX is really just JS functions. Otherwise, what I wrote is what I'll see.
The version of Svelte used there is roughly 100 releases and a year and a half old. These days Svelte's performance appears to be much closer to Inferno's than Preact's.
Comparing average numbers in that chart, Preact is 22% faster than React, Svelte is 12.6% faster than Preact and Inferno is 14.5% faster than Svelte. (note: Preact 10.1 is out and this uses 10.0)
Vanilla JS 1.04 (5.8% faster than Inferno)
Inferno JS 1.10 (14.5% faster than Svelte)
Svelte JS 1.26 (12.6% faster than Preact)
Preact JS 1.42 (22% faster than React)
Total Size isn't that different either. That's an 11% payload difference between Inferno and Svelte and a less than 5% difference with Preact and Svelte. This isn't surprising since Preact is about 9kb unzipped (less than 4k zipped) and Inferno is about 21kb unzipped (less than 9k zipped).
Maximum memory difference between Svelte and Inferno is negligible too at only 9%. I'd argue that memory usage for any of these will be dwarfed by actual data and the DOM itself. Preact memory usage is interesting as it uses more than Inferno despite not having to diff against a vdom.
Startup time (parse to first load) is also completely unimportant with Svelte at about 1.2ms faster than Inferno, but 1ms slower than Preact (which even beats out the fastest vanillaJS version).
Inferno and Preact both have access to the wide support of the React ecosystem and tooling. Inferno is faster overall while not being particularly worse in any single area and better in others compared to Svelte.
Your total size numbers are almost entirely dominated by Bootstrap and a font, which are the same for all the tests (and not something that would be used on a site where payload size matters). Svelte's JS output, gzipped, is about 40% smaller than Preact and 65% smaller than Inferno.
Assuming those ratios hold up for larger apps, that would be one reason to consider Svelte.
With only 20-ish milliseconds to load, parse, and execute, the size difference disappears into the noise and is irrelevant. In addition, that difference definitely does NOT scale. As you add more components, the ration of component to framework becomes larger and larger as the internal wiring is used over and over again. All those things in the framework have to be re-created quite often in svelte. Even if Svelte could fit all its component changes into the same area as a React-style component (which I doubt), that extra 9 or 21kb would still disappear into irrelevance.
> I have to learn their proprietary syntax and markup.
One of Svelte's raison d'etre is to "use the language" and err on less proprietary syntax / api / markup. Of the big three (not including Svelte), Svelte uses far less proprietary syntax, boilerplate, and API coverage. It errs on using as much native JS, CSS, and HTML as possible.
React has one and only one syntactic conceit which is JSX. Truth be told, that is based on a subset of the now deprecated e4x standard.
Let's look at Svelte's special syntax going over the docs. Everything mentioned here is NOT part of either the HTML or JS spec.
* Uppercase HTML is special (I really don't understand this one as this seems like the perfect opportunity to go all-in on web components)
* Interpolation using curly braces
* magical $$props object
* custom if..else..end syntax
* multiple variants of the custom loop syntax
* custom await, promise, and handler syntax
* custom HTML escape syntax
* custom debugger syntax
* custom element directive syntax
* tons of stuff using the element directive syntax
(especially events and data binding)
* 4 non-standard pseudo-DOM events
* magical <slot> (lowercase) HTML element
* magical <svelte> (lowercase) HTML element
* magical $: syntax for binding updates
That's a ton of magic and doesn't include all the magical code generated to wire everything together. That wouldn't be important except that you can't really avoid it. In React, I can just step over library calls, but since there's no Svelte library, I have to step through the spaghetti it creates from my code (spaghetti because efficient machine-generated code is always spaghetti).
The biennial JS framework migration makes me glad to be in ClojureScript world, where it's a little more static (in a good way). Well, perhaps thats a function of its smaller developer base. ClojureScript + Re-frame + GraphQL subscriptions (Hasura) is the most fun combination I've used in a while. I hope nothing 'better' takes the CLJS market anytime soon.
https://svelte.dev/blog/svelte-3-rethinking-reactivity