One thing I think the author overlooks: the appeal of Svelte's built-in animations and transitions is that they work correctly when the element's lifecycle is being managed by Svelte. E.g. with code like this:
{#if showFoo}
<div transition:fly={{ y: -50 }}> Foo! </div>
{/if}
When `showFoo` changes to false, Svelte will first play a flyout transition and then remove the element from the DOM, and it will correctly handle things if `showFoo` toggles back to true again before the flyout finishes, etc. You could do the same thing with CSS animations, but it would be hairy and you'd need to learn more about svelte internals than you probably want to.The reason this is huge is because 90% of my coding is not Svelte. Usually I'm working on app logic, so I might go weeks or occasionally months without touching any UI code. With Vue I used to dread making UI changes, because I always wound up needing to re-learn which properties I needed to put in which return value to which callback (or somesuch, I don't remember the details). I'm sure it's very intuitive if one uses it every day, but it never was for me after a six week gap.
In contrast with Svelte I feel comfortable doing UI work after a long hiatus, even with nontrivially reactive bits, because apart from the templating it's basically just plain JS (or looks like it). It took a bit of bother initially architecting stuff, but I don't think I've checked its docs since I first switched to it.
That said, the big tradeoff is that Svelte's reactivity is quite magical. Personally this doesn't bother me, because as a JS main I find it easy to intuit what Svelte must be doing behind the scenes in order to work the way it does. But if you're an occasional JS user you might hate Svelte's magicalness for the same reason I disliked Vue - e.g. you might keep needing to re-learn when to use $: statements, etc.
https://vuejs.org/api/sfc-script-setup.html
Re: magic in Svelte, I haven't used it but that sounds like something I'd be wary of. I like how Vue 3 takes a functional and explicit approach to defining reactivity. It's no longer grouped into buckets ala Vue 2 (data vs computed vs methods etc) but rather you write normal non-reactive JS by default and wrap values in reactive() or computed() when you need reactivity.
The only syntactic downside is reactive values always need to use foo.value to access foo's data which causes occasional bugs when you forget it (and it tends to fail quietly) but it makes sense why it is that way. Maybe better LSP/IDE integration can detect that.
It's good to hear Svelte has .svelte files like .vue SFC. That would be the biggest thing I'd miss with React.
This is a very interesting point, because my experience is quite the opposite.
Most of the time changes to the apps that I typically worked on (ERP/CRM platforms) involved both DB migrations, as well as back end and front end work. And with the front end, changes to the logic almost always resulted in changes to the template, even if only within a single component. The only exceptions to this were validation changes (changed logic only) or visual bugs (changed template only).
I wonder what qualities of the system design this points towards, apart from coupling.
However, seeing the way Svelte does it sounds like a dream. I wish that could've been all I reasoned about last week.
{#if showFall}
<div transition:fly={{ u: 8 }}> Fools! </div>
{/if}Added an update to the end of the article linking to this comment - https://tyhopp.com/notes/thoughts-on-svelte#update-2023-03-2...
is it possible to use Svelte more for client-only or client-mainly views, and use other solutions for stuff that communicates more with the back-end? or do they get into each other's way?
I don't get the appeal of frameworks introducing template tags like `{#if showFoo}` vs JSX personally. You have the learn new syntax for things you already know how to do in JavaScript but with less expressibility, and JSX can at least be type checked so you don't have runtime problems like an `<input>` sneaking a string in a number field.
React's "it's just Javascript" mantra is a manipulation that only gullible folks will fall for: you can't just add a bunch of stuff to Javascript and then claim "it's just Javascript". If I throw a piece of steak in your coffee, you won't consider it "just coffee" anymore. And certainly you can't claim you're still a vegetarian after consuming that "cup of coffee".
I personally find it much harder to reason about the weird
condition && <element>
syntax, compared to perfectly reasonable {#if condition}
<element>
{/if}
The latter so readable that it can even be understood by a non-engineer. The "new syntax" is as close to natural language as it gets.Understanding the final layout is much harder in React.
That said, custom template syntax has indentation issue (you typically want indent both HTML elements and custom template tags, so anything inside conditions/loops has double indentation), so I actually think Vue template syntax (<element v-if="condition">) offers the best tradeoffs.
But regardless, at least when I'm looking at all 3 options, I see their tradeoffs and making an informed choice. React folks typically fail to even understand that there are tradeoffs. Even if you buy the "it's just Javascript" mantra, Javascript was never a good option represent a document layout.
As for the other ones React seems to be pretty good with TS and obviously Angular is TS only.
As for using templating logic over JSX, that is of course a matter of taste, but i find code becomes much cleaner when there is a clear separation of templates and logic, and with jsx its a bit too easy to blur that line.
export let name: string;
export let age: number;
FWIW I kinda agree with you about the #if syntax. I like that you can still use a ternary with plain JS values like {Math.random() < 0.5 ‘heads’ : ‘tails’} though, and I would say I very much don’t miss having to use nested ternaries in React.
The React ecosystem has embraced TS it seems. Angular is another obvious candidate, I think it had a strong focus on TS since quite a while. Lit/lit-html is just JS, so there are no surprises if you use TS as far as I know.
I agree with the JSX issue though. It's the one thing that React does better than some of these other frameworks except to for example Lit/lit-html which is literally just JS with template literals and doesn't require a build step.
I'm using Zustand[1] with React as it is as similar as I can find to Pinia, but the whole hook system is just painful to work with... OK rant over.
I haven't built anything substantial with Svelte, but it's definitely on the radar, and I like how similar it is to Vue single file components (SFC). Hoping state management will be as nice to work with as Pinia is with Vue.
0 - https://stackblitz.com/github/piniajs/example-vue-3-vite
React Query is a joy to use and clicks very nicely with how I am structuring my apps, building around interacting with async things like APIs
The thing with Svelte is that for a big project (like an SPA) you're going to end up using SvelteKit, because that's where all the development focus is for things like routing etc... and SvelteKit isn't nearly as settled. As in, there aren't developed "patterns" for doing a lot of things yet so it's a lot of trailblazing. There's also some features that are missing and on the roadmap but SvelteKit just hit 1.0 in December (these are usually more obscure things but you will still likely encounter them if you're building something of moderate complexity.)
I still think overall it would be fine to use for a big project, but a year from now I think it will be a much easier choice. Something that is happening right now is a lot of big players in the wider JS ecosystem are transforming from being React specific to framework agnostic:
- NextJS -> Auth.js: https://twitter.com/balazsorban44/status/1603082914362986496
- React Table / React Query -> TanStack Table, TanStack Query: https://tanstack.com/
This has all happened in the last few months. So it's still new, and they're still improving as they move away from being React specific. People rely on those projects. As more move in that direction I think it will become easier and easier.
And even that is a flawed argument: almost every React codebase uses numerous immature extensions. I haven't seen a conservative React developer.
The counterintuitive truth is that if something is a good fit for small projects, it is most likely a good fit for big ones too.
EDIT: after reading your comment one more time, I assume you've used Svelte only for a small part of the app, not the app as a whole?
Even then, 100% recommend it, documentation, and existing issues are sometimes lacking and information is hard to come by, but the Discord is helpful, even though it takes a lot of searching their "forums". Have great hopes for its' future, and it's really fun to build tools in Svelte, I remember giving all my Network Security assignments (transposition cipher, DES/AES, KDC) a nice, clean reactive front-end showing intermediate states of the data being passed around even though a simple cpp file would've sufficed, just because of how fun it's to use Svelte.
Ive designed svg based editor systems in svelte & the crucial piece was xstate.
I had editors with 7+ states, that is copy line, edit point of line, split line, draw line, etc.. and with xstate, no matter how much i added features each file would be 25-50 lines with some outliers at 80.
Id highly recommend it.
After this time, literally every other framework seems unnecessarily overcomplicated for me lol. It is a BREEZE compared to writing React imo.
The dev tools give you a full visual reactive graph.
I like Svelte, but people like to pretend that it's easier than it is.
then I found out Sveltekit is really a SSR-first design, and Svelte itself has no client side routing etc. While Vercel sells Sveltekit(and Next.js) to be CSR ready, I don't buy it, I don't need the complexity of SSR in the code when I just need a clean CSR, however you paint the SSR-is-for-all picture.
So I switched to React, now React is also favoring SSR-first(next.js etc) approach. I'm back to Vue for future projects.
Vue by default remains to be the sole and true CSR SPA, if you need SSR, add Nuxt will do, but, at least it does not force me into a SSR-first default (and recommended) framework.
If Svelte provides a built-in client side router, and do not try to point everyone who wants to use Svelte to Sveltekit, I may reconsider, for now, Svelte is no longer in my projects.
https://kit.svelte.dev/docs/page-options#ssr
I don't get why so many people seem to think SvelteKit is SSR-only or that it's some kind of Rubik's Cube of configuration to disable.
FYI: There's also export const prerender = true;
Still, I'd give try, it looks like people are still using it, and perhaps someone else will pick up the burden of maintenance, since there's clearly a ton of demand: https://github.com/EmilTholin/svelte-routing/issues/236
I agree that it can quickly cause confusion, but I can’t really think of a situation where it can’t be avoided.
I find it useful for simple things but try to avoid it when the dependency graph gets more complicated.
I haven’t built any large-scale Svelte applications but since reactive labels are by definition local to the component (it’s a compiler feature, and each component is compiled independently), I’m not sure why it would cause more issues at scale.
EDIT: Maybe they’re thinking of the reactive store syntax, which is harder to avoid but much less of a brainteaser. But that’s really a completely different feature that happens to use the same character.
For the part about increasing potential for bugs at scale, my mind was on scaling one or more teams and projects. Might have been better to use some other word than scale since it's so overloaded.
I find it difficult to think of patterns to introduce that would help teams align on when and how to use reactive `$` statements.
It's not a Svelte-specific problem by any means, but I do think Svelte's reactive statements would cause more pain than it would help ease as teams and projects get larger.
But if you mostly have some values that need to be recomputed when other values change, or an effect that needs to re-run, it’s a convenient tool to use.
Focusing on mental model, maybe my mental model can inspire yours? Here it goes.
- For me, `$: dependent variable = expression(independent variables)`, is an equation that Svelte guarantees will hold across the single-file component (SFC). So whenever an independent variable change, the dependent variable is also updated to maintained the equation. - Caveat: In the statement `$: dependent variable = expression(independent variables)`, the expression language is JavaScript but the semantics of the statement are Svelte's (i.e. *Svelte's* scoping rules apply, not JavaScript's). SvelteScript is so close from JavaScript that it feels intuitive to use but confusing when the two differ. In a poor analogy, just like using a word that means something in French, another in Spanish, and wrongly guessing the source language (hence the meaning) that applies.
Then: - `$: {some statements here featuring independent variables}`. *Svelte's* scoping rules apply (only the variables visible in the block are targeted by Svelte's reactivity). This is not an equation anymore, it is the expression of an effect triggered by change in dependent variables.
Why this is natural to me? At the specification level, reactive systems are specified with three core syntactic constructs:
1. event -> reaction 2. dependent variable = function (independent variable) 3. dependent variable <- function (independent variables)
The first item means is where you specify what happens when an event occurs. for instance button click -> (counter <- counter + 1; render new counter)
The second item is the same as lambda abstraction. Say `area = f(length, width)`. That's true all the time and allows using `area` everywhere needed instead of `f(length, width)`. But by referential equality rules, you could absolutely do away with `area` - at the expense of course of less clear and more verbose code (and probably less performant too)
The third item is assignment, and is used to describe changes in the state of the component. As a rule, (reaction, new state) = f(event, current state). So the third item describes how to get new state from current state. The first item describes how to get the reaction from the event and current state. The second item is optional but helps a lot readability, conciseness, and performance (not computing `area` twice if you use it twice).
In Svelte syntax: 1 is $: {reaction code here} (event is some change in value of variables scoped in the code) 1 bis: <some html code here> is the same case as 1 with a different syntax when the reaction is a (re)render. Whenever the dependent variables in scope change, a rerender reaction is executed. 2 is $: x = f(a,b,c,...) (Note that the right hand is a single variable name) 3 is any assignment occurring in the SFC.
Not sure if that helps, but well, that's how I stay away from the pitfalls of mixing SvelteScript and JavaScript. Identify events, state variables, the reaction to the events, and the state changes. Then translate that into SvelteScript.
Syntax wise I don't like it because it makes the whole thing look like a simple variable assignment. Something that might be an expensive call looks like something that's usually a cheap operation.
Maybe I just think in terms of Java too much because it's the first language I learned, but I find all of the frameworks that use conventions like that hard to read. You need a ton of knowledge about how the internals work to understand what's happening in those scenarios. With Java, I always found the cost of writing boilerplate and declaring everything was paid back by how easy it was to read and follow existing code.
I do think that people new to Svelte find it hard. It takes a while to understand how the `$` reactive statements work, and when and when-not to use it. When I first started working with Svelte, I tried to do things the React way and shared similar frustrations. Now that I've been working with Svelte for smaller and bigger projects for nearly 5 years (yes, since 2.0), I find Svelte's reactive pattern simple and intuitive.
There are some aspects I find frustrating with Svelte. One example is being able to pass templates around. With React I'd just pass JSX, but since Svelte is statically compiled, I've had to create components for such scenarios. Slots don't cover all usecases. I can live with this though.
I have built a couple large projects using Svelte and haven't faced issues with scaling. I found Svelte to be quite flexible, which has enabled me to build fast, and maintain a performant codebase.
My recent project is Mathesar, which has a large frontend codebase in Svelte + Typescript [1]. It's also open-source so you can check out the codebase. We use pretty much all of Svelte's features and we even implemented a full component library. Here's an old discussion for deciding which frontend library to use for Mathesar, where we selected Svelte [2].
We have had to establish a number of patterns (including around reactivity) so that new contributors don't break things, which happens more often than you think.
Svelte's primary issue is a lack of established patterns, which makes it easy for new Svelte developers to get things wrong. React has a number of such patterns due to it's massive community. I believe as Svelte's community keeps growing and more projects choosing Svelte, this would be tackled.
[1]: https://github.com/centerofci/mathesar [2]: https://github.com/centerofci/mathesar/discussions/55
Yeah I agree. It's not a big deal but I kinda miss this from JSX.
There was some discussion about adding templates or even components inside other components but it all feels very inelegant and not very Svelty.
Here's more clarity on what I was attempting to say: I had to understand the internal working of the reactive statements inorder to use it the right way and it took me a building a couple smaller projects to completion to get there. I believe this was because at the time I built them, I did not have enough references and projects where similar problems were tackled.
After I understood how it worked, which was about 3 to 6 months into using Svelte v3, I found it rather simple and intuitive. I've been working with Svelte for nearly 5 years overall. It did not take me 5 years to find it intuitive.
Questions about large projects always arise when talking about Svelte. Did you / would you use it and why not?
I would certainly NOT suggest using Svelte on enterprise projects. Why not?
Because other people don’t do it, and that means that it is very likely that there are no (not many anyway ) experienced Svelte devs that are willing to work at/for some large company. React and Angular are safe bets in THAT space.
On the other hand, would I use it for personal projects or in a startup - absolutely. It's simple, it is fast and it is fun to work with.
When talking about other frameworks (sorry, "libraries"), React folks should really avoid throwing stones from their glass house.
I'm not fan of Angular by any means, but I totally respect how opinionated it is and how that translates out to development teams in the wild.
This isn't true, I build enterprise software with Svelte (and have for years), and I know others who do too. We just don't contribute to the technology hype cycle.
But they weren't always. And a lot of people that 'know' React don't feel entirety comfortable using React because of complexity - ever seen someone want to know how to store a variable and watched the life drain out their eyes as they read a Dan Abramov essay on what true reactivity means?
https://legacy.reactjs.org/docs/design-principles.html#sched...
The article is on point. There is 1 caveat to animations that I'd like to add. Everytime we ended up using animation without the `|local` specifier, it broke completely our app, and that's an easy mistake to make. It should be the default imho. That's because svelte is updating the whole DOM instead of that specific component without it, and it waits for the animation to be observably over to re-render the DOM .
For reactivity, it works surprisingly well but for big state updates, and a redux style of having one big state to update, we ended up splitting the state subparts that were independent in reactivity because otherwise you end up very easily into a reactivity hell (reactivity, calling other reactivity). We also have a lot of pattern to keep in check the reactivity on nested objects such as using object comparison checks (using fastEquals) to make sure the input object actually changed and it was not a leaf node unrelated to this component that triggered the change.
Overall, with the small team that we are, we could NOT have build such a complex and blazing fast superapp without svelte. On the other hand, we had to become expert at knowing how svelte would actually compile to otherwise we would have been stuck early at using the reactivity bindings after a certain scale.
[1]: https://github.com/windmill-labs/windmill/tree/main/frontend
On a broader note, does anybody know of any build time comparisons for UI frameworks? Whenever I search for build time speed comparisons, I only find runtime speed comparisons...
The build itself takes around 2 minutes, but that's mostly due to monaco and tailwind taking the majority of the time to be bundled.
Portfolio - https://www.spikeysanju.com
Source code - https://www.github.com/spikeysanju/spikeysanju.com
I confused vercel with nextjs.
Next.js is a React framework. It does not support Svelte.
Because CSS has no hooks into HTML lifecycle. If you want to nimate something that appears in the DOM, or disappears from the DOM elegantly, CSS ain't it.
That's why almost every single framework outside Svelte struggles with animations and employs increasingly bizarre and brittle workarounds to make them work.
That being said I overall prefer the Vue CSS approach to animation, it inspired my brother and I to make https://animxyz.com which has been my most successful side project yet. We wanted to make it work for Svelte as well but they don't have the CSS classes so we can't hook into their events the same.
Added an update to the end of the article linking to this comment - https://tyhopp.com/notes/thoughts-on-svelte#update-2023-03-2...
:)
With the new direction of Sveltekit, the absolutely worst thing is the documentation. The new server-side endpoints have confusingly similar nuances (certain things like fetch can be used on certain server-side files, but another kind of fetch can only be used on another). The documentation style makes these nuances next to impossible to find, and I find myself having to Google or ask Chat GPT to help me figure those problems.
Otherwise, it's been a breeze to build with!
And there are many weird architectural decisions forced on you such as file-based routing which IMO are a deal breaker for anything but trivial projects. Even as a SSG, SvelteKit still lacks fundamental features such as easy to configure permalinks at the page level (which Jekyll had almost 15 years ago).
I've started experimenting with integrating Svelte with Fastify using Vite to get a good backend framework instead of using SvelteKit. It's still a bit ugly but it works:
The syntax changes were straightforward enough, but it left me with a project that didn't compile.
I started a new project and copied the source files there and it worked.
> The logic also didn't belong inline in the rendering code, though. So where does it go?
I think the idea would normally be that you would handle loading the data in +page.ts and do any transformations there, and only deal with rendering and ui elements in the +page.svelte file.
The main one for me is typing props for a component feels extremely wack. In react I have a function, that function takes a type, I export that type and can import that type. In svelte I'm exporting the props individually? It's annoying to get the type declarations in one spot and make that easy to import for other components to use as intermediate typing. This is one of those things that I didn't even think twice about until my project reached a medium size and had multiple developers building out different portions -- it's inconvenient to scale and none of the workarounds feel good.
In Svelte, HTML/CSS is king, with the bare minimum of JS/TS necessary for any given task.
With that in mind, of course React tends toward type definitions. Also explains why Svelte tends toward markup-oriented definitions.
I think the $ shows the tradeoff of reactivity. It makes updates sort of automatic which is great, until it's not. React on the other hand is a bit more explicit and cumbersome, until it's not. Rules of hooks vs rules of reactivity, it's all about managing triggers and dependencies, which easily gets complex. I think there might be a possibility for a mix, reactivity with escape hatches, idk.
The only part that is less explicit than some reactivity libraries is which variables’ changes will trigger re-evaluation.
Some libraries go full-explicit with the likes of foo.observe(foo => …) or computed(([foo]) => …, ["foo"]), requiring that you enumerate the properties to depend on. This is easy to get wrong, leading to bad reactivity.
Some libraries go full-implicit, tracking which properties were accessed during the call. This can be functionally perfect (provided you only use observable objects or primitive values—no Array, for example, leading to the amusing situation of some common patterns being syntactically heavier), but harder to reason about, and makes static analysis impossible in the general case, since property access can be non-local.
Svelte lies between the two extremes, needing no special syntax for it, but just noting which local variables are touched inside the block. This makes bad reactivity quite possible (non-local effects aren’t observed, including object nesting), but the language semantics of $ blocks are easy to learn, which mitigates this (though it’s still the most common sort of beginner error, when people try just using it rather than learning it). Static analysis and reasoning aren’t quite as simple as full-explicit, but are still straightforward in sanely-written code.
I mean if you consider React/Next/Gatsby separate frameworks then there are more, but generally it's Angular, React, Vue, Svelte, Solid, Qwik, Ember, Redwood, HTMX. If you include other programming languages (Elm, elixir ?) then there are definitely many more
I'm sure I missed one or two actual front-end frameworks though
The reactivity system in Svelte is really a joy to use, once you get used to it there's no turning back.
But the author did hit one of the ugliest pain points about it. Svelte can NOT correctly infer transitive dependencies when the variable being updated is inside a function. Meaning that the variable itself will be reactive (it will be invalidated every time it's assigned, even inside a function) but Svelte is not using that information to build the dependency graph, and falls back to the order in which the reactive blocks were defined, which may or may not be right.
I created this issue https://github.com/sveltejs/svelte/issues/5190 a couple years ago documenting it.
It's not so common, but when it bytes you it's pretty nasty.
The workarounds I found are the following
These are the workarounds I found:
- a repl with the issue: https://svelte.dev/repl/640736d3c91d40d3971afcc3eef8b25e?ver...
- workaround 1: manually reorder statements, need to figure out by yourself (and maintain!) the dependency graph: https://svelte.dev/repl/3ecd6aa918e045999db32d379270fc1c?ver...
- workaround 2 (my favorite): provide a redundant update as "hint" to tell the compiler that setY updates y: https://svelte.dev/repl/cbf98bb35f5e4dd4b037d13254853c90?ver...
(thanks to TylerRick for this: https://github.com/sveltejs/svelte/issues/5190#issuecomment-...)
in practice it means to do something like: `$: { setY(x); y = y };`
- workaround 3: put the update operations in order in a single block (it's just the workaround 1 with improved legibility, IMHO): https://svelte.dev/repl/074df362bb934312bbe6fd3aeccab771?ver...
I still think we could do better, at least explaining the issue and how avoid to fall into it (perhaps some linting warning?)
But I really hope svelte developers start considering this an issue to solve, it's inconsistent (meaning the variable is reactive but that reactivity is not taken into account to order the operation in "topological order" (Hey, I learnt about that from one of Rich's presentations, see https://rethinking-reactivity.surge.sh/#slide=19) and as I said before, in the rare occasions you stumble upon it is not so easy to understand what's going on.
So if you want to update y on some changes to x, you do
$: y = x
And if you need something more complicated, a transformation perhaps, you put the logic in a function and assign y to the result of that function parseX(val) { ... }
$: y = parseX(x)https://svelte.dev/repl/44e3aece18294ddb834bcdfb4394af48?ver...
` <script>
let name = 'world';
const flip = () => name = name === name.toUpperCase() ? name.toLowerCase() : name.toUpperCase()
$: console.log({ name })
</script><h1>Hello {name}!</h1>
<button on:click={flip}>flip!</button> `
The confusion the author expresses with $: reactive statements and store auto subscription with the $ are unwarranted IMO. It's really just a lack of familiarity but this kind of stuff becomes intuitive very quickly.
My criticism of Svelte is rather that they haven't gone deep enough into the compiler-based approach.
Would be great if there were something like .svelteStore files where you had all the automatic reactivity tracking without having to use a component. Or some kind of improvements into writing styles. With a compiler you can do anything you want and I think Svelte has been a bit timid, maybe to not scare people away.
For example Imba[1] also bet on a compiler-based approach (years before Svelte existed) and created their own language/framework/compiler. They have come up with amazing solutions to many problems. It's a shame they bet on Ruby aesthetics though and also that they aren't investing into marketing/docs.
Of course, one might argue that using a compiler is a bad idea for a number of reasons. And yeah of course there are objective issues to any approach, but you have to pick your poison. All in all, Svelte has made me tremendously productive compared to using other solutions for years (React, Vue, Mithril, Inferno, etc).
I will say though that I would rather use a solution that doesn't have any reactivity at all. Mithril and Imba have this concept of just "redrawing the whole thing" like a game GUI without having to worry about reactivity. Cognitively speaking, no reactivity is the best mental model IMO. With any reactive solution, it's very easy to fall into complex reactive dependencies which can be hard to track. The author of Imba has a video from 2018 where he talks about this[2].
[1] https://imba.io/
Compilers open up more avenues for productivity than most people in the web dev community realize.
Makes so much sense once it's pointed out.
This is a good pattern that builds on the existing foundational technologies of the web but acknowledges that how we build websites (and apps) has changed quite a bit.
Rip out {#await ...} and put it in the <script> logic, then use local variables when rendering.
intuitively and without realizing. Thanks for writing about it. export type PromiseState<T> =
| { status: 'loading'; value?: undefined; error?: undefined }
| { status: 'resolved'; value: T; error?: undefined }
| { status: 'rejected'; value?: undefined; error: Error };
export function fromPromise<T>(promise: Promise<T>): Readable<PromiseState<T>> {
return readable<PromiseState<T>>({ status: 'loading' }, (set) => {
void promise
.then((value) => set({ status: 'resolved', value }))
.catch((error) => set({ status: 'rejected', error }));
});
}Life is too short for constantly writing boilerplate and performance analysis on a virtual DOM. Don't fall victim to Stockholm Syndrome.
> This subtlety led to more than one case where I didn't understand why a component didn't update. ... In the end I found it was difficult to determine reliably when to reach for the $ label. I'd use it in one scenario and it seemed to work like I expect, then throw it at another scenario and it didn't work like I expect.
OK, that's like you're used to using an old donkey for transport and then someone hands you a brand new car and you start complaining about it not having seat heaters.
The $-based reactiveness of Svelte is great! Just don't expect that every possible side case is covered 100%. Same as with just about any other technology.
Svelte is much, much easier to grasp than React or Vue, especially when it comes to state management. I like that it’s super lean and it never confuses me what’s native Javascript and what’s the framework (pretty important for a non-developer me). And I love not having to write huge amounts of boilerplate code.
Reactivity sometimes gets more complicated than advertised on docs. For example, I have a bunch of functions where I manipulate an object and need to reassign it to itself (feature = feature) to trigger refresh on reactivity block. Sometimes it’s easy to miss and not know why reactive statements are not being updated.
Also, docs are pretty barebones. For comparison, I think Vue docs are explaining details in better and clearer way.
<script>
export let selected;
</script>
<style>
[aria-selected] {
background-color: blue;
}
</style>
<button aria-selected={selected}>Click Me</button>
You can't do that with React. The lack of a VDOM is incredibly refreshing and I don't notice any performance issues.I occasionally come across articles expressing concern that it won't scale up for large applications and I find that confusing. React has considerably more footguns than Svelte. I've ported over several personal projects from React to Svelte and it always shaves quite a bit off the line count and makes the code less confusing (at least in my opinion). Granted, it's not perfect. Forwarding props is kind of a pain in the butt and the docs advise against using `$$restProps`. There's also some trickiness when it comes to overriding styles. The only way to override a certain style in a custom `<Button>` component is via a `style` prop, using CSS Modules, or a CSS-in-JS library like Emotion. I've been using Vite's built-in CSS Modules and it's working pretty well.
The scoped styles are really nice. If you structure your components right, make sure you're adhering to accessibility guidelines, and use semantic HTML, you can usually get away with styling the markup based on the element type or attribute without having to define classes on the elements.
In VS Code I turn on seeing short directories in the tabs, which prevents file confusion. Beyond that it's been a joy to use and pretty easy to get going with. Any confusion or learning comes from not doing next.js first and having to learn about which things happen where in terms of client and server. It's eye opening though and it isn't forced learning.
I give Sveltekit a "you should certainly consider it" vote.
> In the end I found it was difficult to determine reliably when to reach for the $ label. I'd use it in one scenario and it seemed to work like I expect, then throw it at another scenario and it didn't work like I expect.
Yep. There's a bunch of different syntaxes and I can't find a documentation page that lists all of them. I use it, but I don't have confidence to always know when it's appropriate.
> Rip out {#await ...} and put it in the <script> logic, then use local variables when rendering.
Yep. Handling promises isn't something to be done in the HTML. HTML should deal with values.
I think even given these Svelte is still the obvious choice for new apps. Particularly the cleaner syntax, less code, batteries-included handling of CSS, and stores. But the two points above would be great to improve for future versions.
At work, we use Svelte throughout our entire FE platform in many SPA micro-frontends, on both the web and mobile (w/ Cordova). We have 10,000+ daily active users. Our team has used Svelte in production for a few years. All of our developers learned it during the coding interview project, and on the job. It's fun and enjoyable to use.
I disagree strongly with this statement (not using it in production because of the reactive syntax). Reactive-blocks will trigger an update if their direct top-level dependencies change, not if one of their dependencies change from within a new scope/block (e.g. function-call) - that's all. Also, we only use reactive statements when we need to - we typically use data-binding instead.
I still don't fully understand reactivity, or how to handle complex reactivity use cases, but it's not like the story in react is much better.
Overall it was a joy to work with even though I don't think it's a perfect framework and may not have what it takes to unseat react as king.
I adored the $: reactive variables, I liked the await blocks, and I found built in stores difficult.
This was as of a year ago, but still interesting.
Just can't get on board with yet another compiler and string template language. Towards the end of my time with Vue I was favoring JSX more and more. The VSCode Vue extension of choice at the time(this was a couple years ago) was Vetur and they really struggled with performance regressions and great intellisense support.
These libraries with their custom string templates I expect to really struggle to achieve and maintain the level of tooling support I've come to expect. And even if they can; why god, why another custom language requiring a pre-compiler? Felt like we were finally getting out of that a bit with fall of coffeescript, SASS falling out of favor due to the performance issues, babel falling by the wayside in favor of fast SWC or Esbuild with the death of IE and the rise of greenfield browsers.
IMHO MobX has shown us how fine grain reactivity can be accomplished with proxies ages ago; with great DX. SolidJS is showing us what can be done without a compiler(it does some light JSX transformation but AFIAK it doesn't have too and there is no custom language). Vue has made most of the goodness of their string template syntax available in JSX via the newish attribute extensions.
Why do we need another string template language? Why another compiler? React Optimizing Compiler? This is not the way.
Another thing that svelte and similar tools get right IMO is that if you have someone dedicated to design, then the HTML/CSS are maintainable by them throughout the lifetime of the project. A lot of times we'll have a dev do a rough pass on basic functionality and then a web designer come back and make it look good and it rarely requires much back and forth or coordination. Or later in life the project will get a revamped design and it gets implemented without the dev having to do anything. No doubt the JSX-based frameworks have figured out a way to make these scenarios work just fine, but I've been really happy with how naturally the division of labor works out with svelte.
Svelte/Sveltekit has the best DX by far and only some minor gotchas, esp. reactive expressions as described in the article. Once you get how it works, Sveltekit is such an empowering experience, I can't imagine being more productive with anything else.
BTW, I'm using Sveltekit for an SPA, which is well documented, and skeleton.dev, a young but promising UI Tookit. Integration with native libs like echarts or three without any issues.
Oh have you heard of luxpop.js all the cool people are using it, it has bitransitional anti-mutation mega-flip data binding so you regain a microsecond rendering that p tag.
You haven't heard of it? You dinosaur!
bind:this is amazing, just lack of IDE support