Svelte – A UI framework that compiles into tiny standalone JavaScript modules
svelte.technology
svelte.technology
> It's currently fashionable to avoid two-way binding on the grounds that it creates all sorts of hard-to-debug problems and slows your application down, and that a one-way top-down data flow is 'easier to reason about'. This is in fact high grade nonsense. It's true that two-way binding done badly has all sorts of issues, and that very large apps benefit from the discipline of a not permitting deeply nested components to muck about with state that might affect distant parts of the app. But when used correctly, two-way binding simplifies things greatly.
I wonder what the author considers "used correctly" and "done badly" and how Svelte approaches this.
I have the feeling most programmers are just lazy, that's why they use 2WB.
And I can't blame them. Redux is much more boilerplate than MobX, for example.
For me at least, the reason boilerplate bothers me so much is that it impacts the readability of my code. Ideally, I'd like my codebase to express the business requirements of my solution as succinctly as possible - every line of boilerplate code I need to include to express yet again how to make an AJAX call, or update a piece of state, is a distraction from what I'm actually trying to accomplish with the application.
But if you hide boilerplate you not really improve readability. Not seeing what is really happening just creates the illusion of readability.
React's virtual DOM diffing makes components more readable than the previous style of writing code to explicitly manipulate the DOM and totally hides what's really happening. However, we trust that it's going to do the right thing, just as we trust that the JavaScript engine will do the right thing when it JITs and interprets our code.
It's not that people said "Everything is bad, do assembly". It's just that people identified 2WB as problematic and you just shouldn't do that one thing.
And if the framework has abstracted away something that you end up needing to understand - well bad framework or bad usage I guess, but still difficult to figure out what's going on.
The argument I'd make is that the illusion is the point when you're writing well abstracted code. The abstraction makes it possible to write code with the assumption that some specific detail is taken care of automatically. While it's true that the detail is hidden, that lets the author and reader of the code focus on other details that might be more important.
Of course, this doesn't absolve anybody from needing to be at least somewhat aware of the abstractions, but hopefully most of the abstractions can fade into the background most of the time. (Anybody who's ever worked with a buggy compiler can attest to how frustrating it can be when this is not the case.)
Don't write things like that, it always reads like "Noone cares about your opinion, so stop using X and also stop writing about how bad X is"
You could have written your comment without that sentence and it would still convey your opinion :)
First is that if you look at the system as a graph of updates, automatically closing all cycles between variable update and widget means that any additional two-way binding links you add become a cycle, which makes it difficult to implement, model, and debug. If the framework only initially links the variable to the widget or the widget to the variable, the graph is a lot less populated to start with and creating a cycle is much harder.
Second is that the developer ends up wanting more and more complicated transforms over time, and having to implement both directions of them at once is much more difficult than having to implement only one direction, because not only are you writing two transforms instead of one, you also really ought to make sure the transforms are able to be roundtripped without data loss, and also that any invalid states on either side of the transform are handled sanely in some manner. Very few developers think this way; it's one of those places in programming where you really need to approach it with a mathematical state of mind, but it's generally being written by the "I don't see how programming is connected to math" types. (Which is something a two-way binding advocate needs to keep in mind when writing their library; you're not going to get your users to deeply understand the way the library works before they can benefit from it, they're going to want to just dive in and get something useful going.)
These are not necessarily insurmountable problems, but they are fundamental problems to having two-way binding. I think these two things are why it has never really taken off despite the fact I've seen at least half-a-dozen attempts over the years. I can imagine programming language tools that could help with both problems, but as what I'm seeing getting sketched up in my head requires a type system at least as strong as Haskell's to be practically usable without so many holes as to be insignificantly different from what we already have, it's not going to take off anytime soon.
You may have bodged together the relevant concepts by experience. That works perfectly fine. But there is a faster way to learn and teach it... if you can get people past the idea that there's some sort of virtue in bragging (for lack of a better word) about how math has nothing to do with programming and how little they know about the mathematics involved in programming. It's all way easier if you start with the concept of an isomorphism and learn how to compose them from the beginning, rather than having to rewrite the same concepts in your code over and over again without realizing it.
I also implemented my own two-way/omnidirectional data binding system ages ago (before I knew what it would even be called) in Java Swing for another audio UI, and all the challenges you mention are real, but as you say, not insurmountable. Multiple copies of my UI can be controlling the same hardware, and they will all remain in sync without infinite feedback loops, but getting there took lots of work.
Dataflow constraints with solvers like DeltaBlue solve these problems and allow you to incrementally add additional constraints.
I show how this works for a simple example in my paper "Constraint as Polymorphic Connectors"[1]. I also show that constraints are useful for expressing the high-level architecture of many interactive systems and suggest how to two might be connected.
[1] https://www.hpi.uni-potsdam.de/hirschfeld/publications/media...
If not "used correctly" means a buggy app, and it's easy for an inexperienced developer to make those mistakes, you're still in for a world of pain. If you need to be an expert to avoid accidentally screwing everything up, there's still work to be done.
This is the whole "pit of success" thing Facebook talks about, the path of least resistance should be towards a functional nearly bug-free app. Certainly an app where bugs are relatively well-quarantined.
I also think it's ignorant to say it's fashionable to avoid two way binding, I've seen teams greatly benefit from avoiding it, teams with less experienced devs and devs who I've previously seen write terrible code. Maybe now two way binding would be easier for them, though I don't know; I'm unlikely to suggest they 180 on tech that has made them much more successful.
In my own experience, I worked on an app that migrated from a 2WB (forgot the name, sorry) to React, and it was night-and-day difference.
Similar things have been said about memory allocation in 'do whatever you want' languages like C++.
That said, I'm not criticizing the framework here, and I welcome new ideas, but a better choice of benchmark is sorely needed to be persuasive here.
I rather like https://github.com/staltz/flux-challenge myself, but I wonder if there are any other projects that are focused on more complex examples.
Something like a GmailMVC would be better.
About 100-200LOC to implement, does recursive views, xhr, routing, dynamic state tree, and the server periodically responds w/ errors (on purpose) to force you to implement loading and error states.
My conclusion was that it seemed like the file size would grow fairly quickly
[1](https://www.reddit.com/r/javascript/comments/5fcwhz/svelte_t...)
When adding the "Edit User" feature:
Svelte's unminified size grew 1.39x. Its min+gzip grew 1.2x. Preact's unminified size grew 1.06x. Its min+gzip grew 1.05x.
The final tally for an almost line-for-line equivalent app in both:
Preact:
- Minified: 15.8KB
- Min+GZ: 6.2KB
Svelte:
- Minified: 23KB
- Min+GZ: 4.8KB
So for a trivially small app, when minified and gzipped, Svelte does produce very compact results. But its growth rate (1.2x) vs preacts (1.05x) indicates to me that it would probably outgrow preact on a normal-sized app.
It would take a long time for it to outgrow the typical React or Angular stack, though.
[Edit: grammar]
I'm the author of a commercial framework for BIG applications [1]. Once you put everything on the table you can see which features should go into the framework and you end up with things like localization, date/number formatting, form validation, keyboard navigation, layouts, tooltips, routing, modals, etc. Once you have all that, you can build a coherent widget/charting library on top of it.
This somewhat annoys me. You can definitely do it.
Sure, it's easier, more comfortable, safer and quicker to use something like React. But you can still do some modularization that scales reasonably well without it.
I've been working on an app and spent a lot of time looking into frameworks to handle its complexity but ended up sticking to vanilla JS to keep more control, especially for detail optimizations.
For example, I'm currently working on a project with mostly plain js, and I've already had to spend quite a bit of time adding code to make relatively basic things work across browsers (including mobile).
Even though it's much less work than it used to be, it's still extra time and code that others will now also have to understand. And who knows what other browser issues linger or will pop up as more features are added!
The worst part is that if I'd be allowed to lazy load some of the images and make a few small other optimizations, I would've shaved off enough Kb's to load multiple version of jQuery...
We really need to stop comparing the size of JS and images. Images do not block the app while JS often block it in many ways: download, parsing, slow executing at first (JIT), GC pauses.
It's truly apples and oranges.
On a recent hackathon, I wanted to implement instant search and ended up using mostly plain javascript for this reason. Not pretty, but worked: http://i.imgur.com/lLi3noX.gifv
> The Svelte implementation of TodoMVC weighs 3.6kb zipped. For comparison, React plus ReactDOM without any app code weighs about 45kb zipped. It takes about 10x as long for the browser just to evaluate React as it does for Svelte to be up and running with an interactive TodoMVC.
A complete library by itself can be pretty big, but it stays the same size no matter how many components you add.
I tried peeking at the EachBlock example and it came out at 7.5kb uncompressed. Copying and pasting the loop a few times makes that grow fairly quickly. Four copies of that example code is enough to make it grow over 22kb. For comparison, the render method in Mithril.js is about 21kb uncompressed. I imagine you would only need another 20 or 30 times more code to reach the size of React (~140kb).
https://www.reddit.com/r/javascript/comments/5fcwhz/svelte_t...
The equivalent JSX output for that clock demo is about 1KB. So yes, I would guess that apps with many components would end up bigger (in total JS bundle size) than equivalent React apps.
Possible counterarguments:
- Bundling and gzipping several Svelte components together might compress well – a lot of their size comes from repetitive substrings like `.parentNode.removeChild` and `.setAttribute` etc.
- Once downloaded, the Svelte approach would probably be faster than React (at both rendering and updating) and would use less memory (no virtual DOM, no diffing, just fast granular updates).
- The self-contained nature of Svelte components makes it easier to treat them as atomic downloads and use them as needed. For example, you could get to a working UI extremely fast, and then download more components for below-the-fold or other pages in the background. This could work well with HTTP/2.
But yes, an app built entirely out of standalone components would eventually overtake the total size of an app built using a more conventional framework. (By the time you get there, your app is probably already too big anyway, and you should be code-splitting.) We're going to add a compiler mode that addresses that very soon by deduping some code within an app.
I suppose that's why it's so critical that the app zips down while it's going across the wire.
I can't help but wonder if shipping a rudimentary bootstrap framework that wraps those methods would be helpful.
The Preact TodoMVC version is ~2x bigger than this example, but it states nowhere how this stuff scales with more components.
I think now the community has settled on the Component based development, especially with JSX templates.
What we need are multiple react-kernels implementations. I see React community providing component API specs. Similar to Linux distros, we should have API compatible implementations, where application code can run on multiple kernels without any changes. We are now seeing multiple react-shim layer implementation - Preact [0], Inferno [1].
Unlike React etc this lib used W3 Components which are far superior because of Shadow DOM, which is already implemented in Chrome.
The Svelte doc says: every call to `component.set()` produces a synchronous DOM update. I can already see how this leads to very poor rendering performance in applications with a large number of nested components.
React and the Virtual DOM solved this problem, and that's why web apps today use a lot of components. So until Svelte can demonstrate fitness and speed comparable to React on large apps, it just looks like Yet Another JS Framework.
For how it actually looks.
Interestingly, it shares most similarities to vue. I guess vue is winning mindshare.
> Normally, this is the part where the instructions would tell you to add a <script> tag to your page or install something from npm. But because Svelte runs at build time, it works a little bit differently.
> First, install the CLI:
> npm install -g svelte-cli
They might want to change their opening
> installs something from npm
> In other frameworks, you'd have to install something with npm...
>Run npm install -g svelte-cli
This is a huge part of Javascript fatigue for me. I love the fact that we're recycling old concepts and mashing them up to get constant improvements and better tooling. It's the relentless hype and pretending that everything is new that really gets to me.
Also, a precompiled Handlebars template is just a function for outputting an HTML string (with a runtime dependency). By comparison, the compiled Svelte output is a dependency-free JavaScript module for a dynamic view, which knows how (and when) to granularly update the browser DOM in response to state changes. It's unprecedented.
Check out the output from this SVG Clock demo: https://svelte.technology/repl/?gist=44e20b4e0224617d228e3c3...
Why not transpile the Svelte compiler to ES5 so it will run on all browsers? Otherwise devs may get the impression Svelte generated applications will not work on all browsers.
The guy did some incredible work - he wrote all of this code in a week. I'll look at the REPL code to see if there's a simple fix. All the levels of indirection, code generation and bundling may take a while for my non-Rich-Harris brain to sort out.
update () {
text1.data = root.name
}
This is the entire DOM manipulation code for this component.There is no runtime library. The trick here is that the generated code is aware of exactly what DOM updates are needed. Instead of a large, general-purpose reconciliator like React's, you have specialized code for changing the DOM, generated from your templates.
What kind of logic are they using here? Isn't any javascript just vanilla JS?
It's a very slight but interesting distinction.
i wonder, though, if compilation is really better than creating a library? if we look at the REPL output [0], we can see what comprises the bones of a Svelte component, and how much generated code will be replicated.
it also shows that the more interesting part here is it's method for rendering. it's use of data binding and compilation means we don't really need something like VDOM to stay efficient (at least, not a VDOM running in the browser).
[0] https://svelte.technology/repl/?gist=0ed5146aa22c28410dfcff2...
Because we did! For instance, this is exactly the approach that we have released back in 2009 with http://opalang.org
Naturally, there are things we would implement differently today, but the OCaml codebase of the compiler is still, in my humble and biased opinion, pretty valid.
With some css preprocessing + vulcanizing you can even use separate js/css files from your component templates if that is your thing - they can get inlined in the build process.
What's the advantage of this over something like Google's Polymer library, which is a toolkit for rapidly creating reactive web components?
Can't reply to your comment so editing here:
Works natively on IE11+, Edge, Safari 9+, Chrome, Opera, Firefox, and mobile browsers. The polyfill for everyone else (webcomponents-lite.js) is 41kb.
Shadow DOM lets you build reliable, reusable components.
I sure am missing something here because the author of Svelte is actually also the author of rollup.js [1] which does exactly that, it eliminates dead code via its tree-shaking mechanism.
[1]: http://rollupjs.org
https://twitter.com/balloob/status/803882259719696384
And the actual code:
I don't see the point of yet another framework here.
The "no dependencies" argument seems to fall down for me, since it would seem to me that they would need to duplicate a lot of code for state management and rendering, bloating the code for anything more complex.
And if there's some clever tree shaking or whatever going on, than I don't see the point as opposed to just including another JS file...
I couldn't find any explanation of what's so different here, worthy of creating another framework for it. Would love to be enlightened!
if it wasn't for projects like that we'd be coding in some feature rich ims/cobol framework.
How does this compare to Google's Closure compiler and library? Does Svelte's compiler do anything that the Closure compiler cannot? Or how about running the source through a hygienic macro system like sweet.js and feeding the output of that to the Closure compiler?
I ask because I'm skeptical of a new, unproven compiler. Google has been using the Closure compiler on production code for years, and its optimizations are pretty awesome.
It IS old (well, 2009 counts as old I guess), but it's still maintained, and still doing what it says on the tin. That's quite an achievement in and of itself.
I'm wondering if Svelte will take away development efforts from ractivejs?
OT >The web's obesity crisis, solved. Svelte turns your templates into tiny, framework-less vanilla JavaScript.
Made me think of [idlewords][1] website obesity presentation...
Self-fulfilling prophecy unfortunately.
Actually, I would like to see the author's thoughts on ractive vs svelte. From the outside svelte is very reminiscent of ractive.
[EDIT] +\n
...is the general reasoning. However, personally, I find that unless you're very well organised, you're not saving yourself much, if anything, in the long run.
It's hard to build in an interactive user interface when you have to wait for full page loads to complete between actions. It can be done with thoughtful planning, but sooner or letter that JS you sprinkle in to do view manipulation is going to be unwieldy.
In general, this is not good. Of course there are specific applications where it's useful but in the general space of applications it would be very limiting.
For example, go to http://square.github.io/crossfilter/ and do the filtering on the 5MB data such that you wait for the histograms to be updated from the server. Instead of the tens of milliseconds, it might be seconds or tens of seconds if the server is loaded, i.e. orders of magnitude slower, not to mention unpredictable.
You can think of the network as a data flow constraint. It constrains latency, throughput, privacy and security; the constraints can be unpredictable (network outage; DoS, MiM attack etc.). There can be many good reasons for wanting part of your domain specific logic to fall on the client side.
In particular, dynamic media e.g. interactive data visualization, games and most interactive things that use data or modeling are best partly in the browser.
We're past the point where the rule of thumb was to do business logic on the server and the client only did the presenting of the view and acted as a controller.
And MVC in the browser doesn't need to be complex. It can be tiny as seen in this MVC lib for React: https://github.com/rajeev-k/mvc-router
He's an inventing and implementing machine.
Both compile templates to DOM manipulation code.
Drawbacks would be maturity, community size, template closed expresiveness and not typescript friendly. Nothing too major.
Why are people porting apps to a framework that is a few days old?
I find it very difficult to believe that your app, with it's 50% size decrease, has any more complexity than a todo app.
Just, why?
You only write your template once, you don't have to think about two separate paths: creation and update. With backbone, you either did that and had performance issues or did updates separately, which is a pain to maintain.
Also, in backbone, parent<->child communication is a complete after thought.
Asking for a friend.
[1] http://www.aiga.org/typography-and-the-aging-eye
[2] http://blog.typekit.com/2013/05/01/hi-dpi-typography/
or submit a pull request
What a nightmare being a programmer who has poor eyesight. My eyes kill me after a whole day of looking at code and I have 10/10.
The only other thing I like is CSS scoping, though. I think that CSS scoping is a problem in React, and current ideas on how to implement that in React are absolutely horrible IMHO.
Two-way binding is a step back I think, I don't love the name (lots of people will judge a new technology by its name), and the thought of introducing yet another framework is a nightmare.
I'd personally go with Polymer if you like scoped CSS, since it's already established and it's a good project.
I wonder if these ideas can be somehow applied to React, doing precompiling on React components, so that one can continue taking advantage of all freely available React components out there, and keep using Redux.
I've tried a few solutions to add styles to React components but they all had something that didn't make them see as the perfect solution.
This looks very good, I've never tried it before.
Thanks.
The only tiny issue left with that approach is that you still can't share code (for instance, colors) between JS & CSS.
but overall, I think it's the best compromise today.
From looking at the docs, the two-way binding seems entirely optional and I can't find anything that would prevent a developer from using a redux model of state management.
I've got framework fatigue, too, but on the surface this project seems to embody the best of what I love: a tiny API, little magic, and getting out of the way.
As for the name sure, but now there's a lot of competition between frameworks, and you want to get all help you can marketing-wise. I might be shallow, but I've not looked at projects a lot of times just because I didn't like the name. I just have no time to make informed decisions, there's too much stuff to look at. I'll see if besides the concept/purpose I like the logo and name a lot of times.
You don't have to use it – its effects are restricted to the subtree where you've explicitly opted in to it. I've personally found it to be a huge timesaver, and would never go back to a world where I didn't have the option of using it. But you're in no way forced into it.
> I wonder if these ideas can be somehow applied to React
A lot of people have wondered that, including me. Unfortunately, a compiler wouldn't be able to generate a good picture of the structure of a JSX component – because it's 'just JS' it resists the kind of meaningful static analysis that Svelte can take advantage of. I'd love to be proven wrong, but sadly I just don't think any JSX-based framework will ever be able to fully embrace these techniques.
You did an awesome job.
I'm really scared about trying out yet another framework since I've tried pretty much all of them before settling on React, (and I guess a lot of people will be, too, since there's a new one every couple of months) but I'll try this weekend.
Thanks!
Can you elaborate more on this? It seems like passing the compiled JS through Esprima and checking the call graph would give you a fairly detailed structural representation of a JSX UI. You may need to do some graph stitching across module boundaries, haven't tried this myself.
What static analysis does Svelte provide?
It makes me uneasy because React wraps up existing HTML with Javascript. Because it violates using existing, established standards that have truly stood the test of time and wasn't broken at all.
Svelte really hits that sweet spot.
1. Easy to write typechecking for the templates.
The compiled template is just function calls (or well, factory function calls) and the typechecker can work with that.
How many template language authors will write a typechecker for the template language?
2. Sane scope sharing - you can take advantage of all existing encapsulation and modularization tools of JavaScript. How do I expose functions to JSX? I simply bring them in scope e.g. by importing them or defining them. How do I expose functions to the template? Well... it depends. There is this $scope object (Angular)... Or there is this components property which informs the template whats in scope (Vue: https://vuejs.org/v2/guide/components.html#Local-Registratio...). I guess there are worse options, like having to register your helper functions or components into some sort of global registry and pray that there wont be a conflict.
3. First class components - want to write a list component that takes an item component as a parameter in props? Tough luck, its likely that the template language of your average framework doesn't support this. JSX gets this for free because its just JavaScript, and JavaScript is a proper language with first-class support for passing around functions and classes.
Its not that its impossible to do this... its just that most template languages aren't advanced enough, and somehow we think thats a good thing.
4. The sandboxing fallacy
From https://angularjs.blogspot.co.uk/2016/09/angular-16-expressi...
Angular template, and expressions, should be treated
similarly to code and user-provided input should not be
used to generate templates, or expressions
If you are distributing the compiler with your framework, there is this urge to expose it to the developers. If you expose it to the developers, there is the chance that it will end up compiling user input. And then you spend ungodly amount of time building a sandbox, unsuccessfully.-
svelte seems to be built by people with deep interest and expertise in compilers, so I'm somewhat hopeful that its template language will not suffer from the usual template language problems. On the other hand, the task is much harder (compiling to code without runtime), so that seems like a driving force in the opposite direction (less powerful template language). I guess we'll see how it goes.
IMHO the next step in frameworks isn't this (compilers are hammers, and everything else is nails). The next step is, after current frameworks fight things out, we take the common subset of the "infrastructure code" that the most popular ones use (DOM diffing? events that are the same across browsers to remove the need for synthetic events? PropTypes? Maybe someone at whatwg should start thinking about this list) and include it in the browser API, then let frameworks build on top of that and be 10 times smaller on average.
1) what is meant by type checking in this context? do you mean that now that HTML is converted to JSX in JS context, you can test HTML as if they were Javascript Objects?
2) so the ease of importing functions to JSX + use of existing "encapsulation and modularization" (I'm not sure what this menas) libraries.
3) what makes it difficult to support it from templates point of view? JSX is easier because?
4) why is sandboxing harmful? how does giving developers compilers create sandbox fallacy?
With the last paragraph, you are saying that the lowest common denominators such as DOM diffing will become a common cross platform feature in all browsers?
Re encapsulation, the way that JS provides it is scope. JavaScript's lexical scope ensures that things you define in a function are only visible in that function, or that things you define in an ES6 module are only visible in that module. Even with the tiny quirks of function based lexical scope, its natural and intuitive: if you can see the definition (or import) in the (function/module) parent(s) of the code you're looking at, its available. Its a tried and true solution.
Template languages don't always bother to add something like "import" or the concept of lexical scope, so when you want to share something from JS (or other templates) with them (like data, or processing functions, or components) you need to somehow put it in their own custom scope. Many template based frameworks make the mistake of working around this not by adding import mechanisms to the template language, but by registering things globally - e.g. when you register a component in Angular or Vue it becomes globally available. This has the same problem any other global variables have. (I suspect this in Angular 1 is what led to the totally parallel "module system" with dependency injection, although maybe they just didn't like the existing ones)
Regarding supporting first class components in template languages, its not really that difficult. Its just that we believe the fallacy that we need the template language to be underpowered. Also, once you add support for first class components and JS scope sharing (or at least import/export) mechanisms to a template language, you've basically reinvented JSX (perhaps with a different syntax)
Sandboxing isn't harmful, its just extremely hard. Angular spent years trying to write a proper expression sandbox and every new version of it was broken successfully - thats why 1.6 removed the sandbox.
What I'm hoping for is that someone works out what contributes the most to popular framework's size, takes the common parts and provides them as built in API in the browser in such a way that the frameworks can take advantage of that instead of writing their own implementations.
does it try and do as much as it can without javascript?
closes tab