I haven't dug into it yet, but from the description it reminds me a bit of Facebook/Instagram's React js framework [1].
React creates a lightweight model of the DOM in memory, and when any part is changed, it sends a diff to update the browser DOM. No bindings necessary:
"When your component is first initialized, the render method is called, generating a lightweight representation of your view. From that representation, a string of markup is produced, and injected into the document. When your data changes, the render method is called again. In order to perform updates as efficiently as possible, we diff the return value from the previous call to render with the new one, and generate a minimal set of changes to be applied to the DOM."
Your description is similar, but it's not clear how exactly the update is made:
"In this example, Ractive.js constructs a parallel DOM representation which is aware of its dependencies on the values of user and messages.unread. When those values change, it knows exactly which parts of the real DOM need to be updated.
This kind of surgical DOM manipulation is more efficient than constantly trashing views only to re-render them, and it scales far more elegantly than manually updating elements."
Basically, items in the parallel DOM register themselves as dependants of 'keypaths', so a {{user.name}} mustache depends on the value of user.name. If you do ractive.set( 'user', { name: 'Bob' }), Ractive scans the dependency graph to find items that may need updating. The mustache will compare its new value to its old value, and if it has changed it will update the text node that it is mirroring.
I'm not intimately familiar with how React updates happen so I can't comment on how similarly we're doing things, but it looks like we have the same kind of approach.
I've been using knockout heavily for a project recently and have come to really like it. This is a small to mid size website, about 6 engineer months of effort and somewhere in the mid 10klocs of custom javascript. Some strengths of knockout:
- it builds on the "Good Parts" of javascript, in that KO observables are just closures. You can pass them around or attach them to different objects however you feel like. For instance, we built a standard UI widget for entering currency values. Anywhere we need to accept currency, we instantiate one of these widgets and pass it the observable that holds the value. Clean, easy, encapsulated.
- Some people have a distaste for the "()" syntax: obj.prop() rather than obj.prop. There's some truth there, but the "()" syntax has one big benefit that overrides the slight ugliness in my experience: it catches naming errors immediately right at their source. If you've ever had to refactor a fairly big piece of JS, you know that one difficulty is correcting all the changed references. And if you miss one, the bug may be subtle, as the old reference doesn't except but quietly returns undefined. With knockout, the old reference blows up immediately, as undefined isn't a function. This is a big win.
We had some growing pains with knockout. Lessons learned:
- don't build anything but a small web app the way the knockout examples demonstrate. The reason is that while knockout claims to be MVVM, their examples are really just VVM -- there're no distinct model classes. They store data directly in the viewmodel classes. Bad things follow as your app grows: since the data is in the VM, any view that needs the data (i.e., all of them) needs to be bound to that same VM, meaning that your one VM ends up needing to feed several views. You find yourself annotating your viewmodel into sections -- "// these properties are used by view X ... // these properties are used by view Y" etc. Yech. Much better to have true model classes, then build a VM class on top of the model for each of your views.
- we now make heavy use of named templates to decompose large views into more manageable pieces. We wrote a simple custom binding to make this easy: since each VM is designed to work with a single view (see prior note), we put the #id of the view's named template into a .Template property of the VM class. The custom binding inspects this property and binds the VM class to its named template.
> - don't build anything but a small web app the way the knockout examples demonstrate.
Have you any code samples written like this you can share? I'm just about to start a large (for Knockout) project and it'd be great to start without making the same mistakes.
I've got a library called Falcon.js (https://github.com/stoodder/falconjs) that essentially provides a Model, Collection, View framework on top of Knockout that I've been using for over a year now on internal and client projects. It works really well for single page and mobile web hybrid apps, it's completely unit tested, and I'm currently in the works of getting the documentation finished up. It's only dependency is jQuery and it comes bundled with Knockout 2.2.1 built in. Feel free to take a look at what I have so far, I'd love your feedback. Again, I apologize for the incomplete state of documentation at the moment but I promise everything'll be wrapped up sooner than later!
Thanks for the quick feedback! As a quick update, I threw together a todo app that also describes some of the basic functionality of Falcon. Check it out: http://jsfiddle.net/stoodder/2ZX52/20/
Sorry, this was too terse. I'm inclined not to use Knockout because I find the branding unappealing and a bit too visually intense. I think backbone.js[1] has been so successful in no small part because the website is excellent. Very simple, easy on the eyes, explains itself, and gets right to the point: documentation. Angular's too[2].
Choosing a product because you liked the commercial, choosing a book because you like the cover, choosing a bottle of wine because you like the label, choosing a computer because you like the design, choosing clothes because you think they look good is a bit... Superficial, no?
When you choose a technology with a bad website, you have to actually look at that website for hours and hours reading the documentation. This can be incredibly frustrating for people who are sensitive to such things.
But more importantly, there's a subtle biasing. People usually do not make rational decisions about technology. The design of the website is a more significant factor than you might think, at least in my experience of watching people make such decisions. If it wasn't, then why would anybody bother to make a good website?
I'm currently using this style in a RequireJS/Angular project. Everything works great, but it's pretty ugly. We should strive to not write ugly shit, but good clean expressive code. This is so non-standard it hurts. There are plenty of other ways the Angular team could have gone; CommonJS or AMD would have been better choices IMO.
ngmin doesn't work with r.js. My response was about using it with AMD modules. I know there were a few efforts to get ngmin/r.js working together, but last time I searched around I didn't see anything promising.
personally, I already have a massive library of AMD modules, using a second module system, even if it adds a feature is confusing for people who join the project and makes for ugly code.
Also I don't like having to organize unrelated code into factories and services just because that's how Angular wants to view the world.
Or if you're already in the process of minification you can also fix these injections automatically, with a simple regex or https://github.com/btford/ngmin.
I actually find that website almost entirely useless. A to-do list means nothing and demonstrates nothing useful. It has no associations between models and nothing particularly complex. I have tried so many of these frameworks and found crippling flaws in all of them, but on the surface they all look peachy when compared via a to-do app.
It's pretty much only useful if you want to write a to-do app.
I completely disagree. I find it very useful to see small, easy to digest, and easy to compare example apps when new frameworks come out for a first impression to help decide if I want to have a play with it myself.
Declarative data binding is intrinsically limited. If you want something that supports more complex updates, you need to start looking into things like incremental algorithms, self-adjusting computations, damage and repair, logged reversible effects, iterative processing methods, and so on.
Say you want to write a compiler whose input is "bound" to a source file; when the input changes, you don't want to recompile the entire file all over again. Instead, you memoize at AST node boundaries, trace dependencies between AST nodes, and then "clean" nodes when they become dirty, detecting changes that affect other nodes to clean them also.
To be honest, I find these data binding frameworks to be very boring, since we've been doing this forever (I did my dissertation on one myself). We really should be looking at the next level that supports incremental processing of more complicated updates.
Knockout does incremental updates as well as memoization. It instruments the evaluation of computed observables to determine the dependency relationships. I haven't delved into Ractive.js closely, but it sounds like it does something similar. How is what they do different from what you're describing?
Re-evaluation is easy enough when your computation is pure. But once you throw in some imperative effects, like adding a name binding to a symbol table, all of the declarative data binding frameworks fall down very quickly.
There is a lot of research in this area, concurrent revisions at MSR or self-adjusting computations at CMU to name a couple. Also, if you've seen Bret Victor's videos and wonder how any of those could be implemented for real, then this is where we need to go. It will be a fun trip though.
You're awesome. I've been playing around with a dependency network in JS recently, and I'd just been puzzling over exactly that question: how best to handle the case where a computation has side-effects. So I'm now busy googling concurrent revisions and self-adjusting computations. Got any further references to throw my way? Is there a standard literature on this stuff?
Actually it's a problem I'm working on right now, but I have nothing to share yet. Some sort of restricted programming model is needed, in my current system effects must be reversible and commutative, the last one being a major restriction but workable for most programs (e.g. set add is typically commutative, list add is not but can be hacked, dictionary set to the same key is not but can restricted by set once semantics).
Hard to explain concisely but it allows fairly complex updates to be expressed very efficiently - see this animated chart for example. The path is created using an expression, which is reevaluated during animation and whenever the dimensions of the chart change: http://www.ractivejs.org/examples/animated-chart/
This is fascinating: I've been writing a very (and I mean very) similar library that also uses the concept of a Parallel DOM (dependents, views updating on a 'data' property, nodes named by standard ids, all child nodes with IDs scanned for and bound to a property), I had just decided to create the concept of 'Keypaths' as my events were clashing on ids.
The thing I have that I can't see here is a selecting/switching node: essentially a page or a tab that holds multiple states but only presents one at a time.
Thus makes me very happy and very sad: happy as I don't have to write all things things now; sad becasue I don't get to write all these things now.
Its naming is a bit conflicting to component/reactive. The name "reactive" is so presumable that other people will choose in the future.
https://github.com/component/reactive
I haven't looked into Rivet.js, component/reactive or other equivalent library. I'm just planning to research which library is the best fit for me. I don't really like full-stack framework like Angular. It was nice to know yet another candidate.
Does anyone know any other reactive template engine?
Thanks. Performance-wise, I haven't tested Ractive and React against each other, but that would be a test worth doing. Ractive is definitely built with performance in mind - it uses dependency tracking to ensure that the DOM is only updated when necessary.
As far as the style goes, I'm obviously biased, and I'd encourage people to try both to see what suits them best. For me, mustache syntax is very readable, even by non-devs (which makes collaboration and rapid prototyping very easy), and the Ractive API aims to be as easy as possible.
I find React's JSX to be a bit of a barrier (I'm aware that it's not essential to use JSX with React), but as I say it's a matter of personal preference.
Yes, it's currently about that size (27k gzipped) - one of my goals for future versions is to try and wrangle that down. It's not that big a library for the amount of functionality it contains, but smaller is always better.
Syntax differences aside, seems to me that React is geared more towards interactive UI components and Ractive is oriented more towards reactive documents, kind of like Tangle[1]. Is this accurate?
The similarity seems to be in the philosophy of the implementation (manipulating a fast representation and rendering to the DOM). It's pretty cool to see that we both discovered the "secret" though :) Seems like we're validating each others' projects!
If you ever want to nerd out we hang out in #reactjs on freenode.
Hi! Yes, I was excited when React came out because it demonstrated that I wasn't the only one who felt that these problems hadn't been fully solved yet (though a part of me thought 'well I may as well give up now...'),
Yes, you could draw the Tangle comparison, though I think there's probably a fair amount of overlap - a couple of the Ractive examples are recreations of React/Angular demonstrations.
Looking forward to spending some more time with the React source code to try and learn your secrets!
I agree with React being geared more towards interactive UI components, but on the other hand you could use Ractive with WebComponents/Polymer instead of MDV to get all this powerful component lifecycle.
Still working on a solution that mix Backbone for core models + Polymer for view lifecycle and custom elements + Ractive for awesomeness updating.
The only concern I have is that some people do not like to use logicless.. I think React is powerful for letting you declare full javascript evaluations and expressions on your template code and giving you more flexible/productive way of writing.
The JavaScript expression is parsed into an AST, and references to parts of the data model are extracted so they can be dependency tracked and evaluated against the right context. Quite hard to explain concisely but I think it does what you're after.
Hey Rich, this looks like it's a lot easier to get into than Angular or Backbone, as someone who doesn't have a lot of JS experience beyond jquery. However, I'm interested in connecting it to a server.
I really like the classic "Hello, {name}" example- how would I go about supplementing that so not only is the model constantly updated on the client JS side, but also on the server's database? Is there some place where I put a .ajax() call and Ractive.js handles the rest? (So the functionality would then be to display the name in the database, but whenever modified by the user, the database's value is also modified)
At the moment, Ractive doesn't really have an opinion on the subject - it was initially developed with news interactives in mind, where very often there isn't a need to communicate to a backend.
Backbone et al are better at handling that side of things. The Ractive approach is to use an 'adaptor' - so you could create a Backbone Model or Backbone Collection adaptor that maps to a particular 'keypath' (such as 'user' or 'items'), and whenever the model changes, Ractive updates. With two-way binding, user interactions can also change the model.
This part of the library is underdeveloped and experimental at the moment, but that's the approach we'll most likely be taking.
You can use Ractive on the server however - you can use the same data on the server as on the client and call ractive.renderHTML(), which is useful for progressive enhancement.
It is my impression also that react is aimed at very large sites (like Facebook), and you need to have a strong grasp of various approaches to dom management to wield React well. Though in the hands of an expert React is the sharpest DOM management tool available and its not even close.
Ractive's approach appears to be much more suitable for use cases like a journalist interested in only learning barely enough javascript to get by.
The main issue is that to do anything complicated in angular you need to start writing tricky[1] "link" functions; the React approach completely sidesteps this complexity. There are some tradeoffs you have to accept, like JSX, but they are easily worth it.
[1] tricky is of course relative; angular is easier to code than something like backbone+jquery or backbone+knockout.
Data-binding is the most obvious feature of Ractive but there are others - easier event handling, transitions, animations, JavaScript-ish expressions within templates, server-side parsing and HTML rendering, and so on.
On the other hand, Rivets is much smaller, so if you only want the data-binding then it's a fine choice. Personally I really enjoy the freedom of writing mustaches straight into my template, rather than using data-bind attributes everywhere, but it's horses for courses.
Nice - looks very simple and lightweight! I especially like the effort put into the interactive tutorial documentation that these frameworks have. Angular and knockout both had stand out docs too!
Is there a particular niche for this framework would you say e.g. small, fast to market apps like news stories - or is is suitable for larger projects where you might normally reach for more of a "framework"?
Library author here - thanks! The interactive tutorials borrow very heavily from Knockout (in fact Knockout was a big source of inspiration all round).
It was initially designed to scratch my own itch - I'm a newsroom developer at the Guardian, where we turn around projects with fairly tight deadlines, so I guess you could say it's optimised for that. (Blog post here: http://www.guardian.co.uk/info/developer-blog/2013/jul/24/ra...) In particular I wanted an API that wouldn't be completely mysterious to journalists who are starting to dabble with code.
There's actually a separate discussion on Ractive at https://news.ycombinator.com/item?id=6096545 - I'm not sure what the HN etiquette is, can anyone enlighten me? (I appreciate both submissions though!)
I've had a look at the last slide now - I think the transitions could use a little work. With that in mind - how hard would it be to integrate with d3 do you think?
Yes, that slide is still a bit of a work in progress.
You can certainly use D3 (or any other library) alongside Ractive, though things could go awry if two libraries were trying to manipulate the same bit of the page at the same time - e.g. if an element has a style attribute like style='left: {{left}}px;' and D3 modifies the element's style, D3's changes will only last until the value of {{left}} is updated.
$scope.$apply is necessary because sometimes changes to the model happen outside Angular's event loop.
Ractive doesn't have this issue because updates always happen explicitly with ractive.set( 'key', value ) (or with array mutator methods). It's not quite as magical as Angular's frictionless updates, but it gives you slightly more control (e.g. you can do ractive.animate( 'key', value ) and so on), without needing to inherit from custom observable classes.
Can someone comment on where to find performance information on this framework? AngularJS has some very smart ideas that allow it to be magical and performant. This looks very cool, and I would like to make sure it is not just polling for changes. I'm suspicious because there is no $apply required. :)
Definitely no polling! Model changes are done explicitly with ractive.set() (or ractive.animate(), or array mutator methods). It uses a dependency tracking mechanism to update the view with the fewest calculations and DOM touches necessary.
I have a question, since this has been bugging me with other js MV* frameworks lately... Is the set() method necessary for updating single attribute? All browsers have supported getter/setter APIs (__defineGetter__ and Object.defineProperty), why not take advantage of them? Being able to say this would be cool:
div.color = 'blue';
instead of:
div.set({ color: 'blue' }); or div.set('color', 'blue');
Or would this cause other problems that I'm not thinking of?
Edit: my ruby cap is on a little tight today. Javascript programmers might not expect extra logic to be run just by updating a property. I still think it would be cool though :)
Many of these frameworks want to support IE 8, which is the default browser of windows 7. IE 8 only supports Object.defineProperty with DOM objects[0], which can be infuriating.
No one should use __defineGetter__ and __defineSetter__ because they are non-standard and deprecated[1].
It's definitely something I've thought about. There are a few reasons I still prefer ractive.set( keypath, value ), which I'll try and articulate:
1. It's explicit, and therefore more predictable. I get itchy when libraries take control out of my hands. Though I understand not everyone feels that way!
2. Performance. Getters and setters have a penalty (or did the last time I looked into it in any depth).
3. It only works for existing properties. With Ractive you don't have to declare the 'shape' of your entire model up-front - you can start with a completely empty model and set properties as and when it's convenient. (With ES6 and Object.observe maybe we can sidestep that issue one day.)
4. Performance (again). If you set several properties simultaneously (e.g. ractive.set({ opacity: 0.5, left: 10 }), or whatever), then updates won't happen until all the new data has been taken account of.
5. That irritating thing that happens when you try to do foo.bar.baz = 'bob' and you get an error because foo.bar is undefined.
6. There are some cases where you want to do something like ractive.set( keypath + '.complete', true ) - you can only do that with string-based keypaths.
As for emn13's suggestion of Knockout-style observables, my own experience is that having to inherit from custom observable classes gets cumbersome quite quickly. But different strokes for different folks!
If getters/setters aren't available, I still vastly prefer plain functions (e.g. knockout) to the stringized setter.
I mean, why would
model.set('someProp', 'someVal');
x = model.get('someProp');
be better than
model.someProp('someVal');
x = model.someProp();
And the second one is likely to perform better, allows better tooling support (nice to have), is shorter, and allows representing a property as a concept in itself `model.someProp`. You can still access a property with a variable name in the (unusual) case you need to.
If you really insist on explicit set/get, then you can still have...
model.someProp.set('someVal');
x = model.someProp.get();
Which still has no downside I can think of, and since this is JS, if you have a variable prop name, you can fall back to...
I like a lot of this, but one part I'm not so sure of is that, if I follow the docs, all get/set operations need to be from the root of the model. They take a "keypath" that starts at root, like "obj.get('subObj1.subArray[3].prop')". It seems to me like that would make it difficult to decompose a large application into component pieces. Your components, to do any get/set operations, would need to know their path from root. And what if that path changes, like an array that's modified? Seems like it could become a considerable barrier in mid-to-large applications.
You're right, all keypaths start from the root. One approach for large apps is to split the UI up into several Ractive instances (which might all be bound to a single global model, but 'start' at different keypaths).
Array modifications aren't generally a problem, because you'd reference the index from within the template - Ractive keeps the references up to date. Also, proxy event handlers are aware of the current keypath context - see this JSFiddle to see what I mean http://jsfiddle.net/KJt2Y/2/
Thanks, this is an interesting example. I'm not wild about the extra DOM it creates (the placeholder <script> tags, etc) but I'm intrigued about what's going on under the hood - will poke around the source code.
Nice little library. I think i will have a close look and implement it into apiDoc (http://apidocjs.com) Templates - for now i use crude jQuery events (quick & dirty coded).
With Ractive i think i can make the code cleaner and easier to modify.
At the moment i prefer Backbone in my other projects, but it is to "heavy" for a small single page (especially for users that did not know backbone and want to modify the templates).
You should probably explain how ractive.js differentiates itself from knockout. It's the direct competitor out there, not angularJS which is doing things very differently.
I glanced at the source and (correct me if I'm wrong) it seems array templating is done by simply comparing the length of the current and previous arrays? That's naive and buggy?
Thanks! Yes, a lot of the feedback I've had through various channels has involved 'how does this compare to x', and I'm pleased to see that a lot of people have picked up on the similarities to Knockout. On the project homepage I specifically refer to Angular because my sense is that it will be more familiar to more people, and despite the many architectural differences they're attacking the same problem space (though Angular deals with xhr/routing etc whereas Ractive is focused on DOM stuff).
I'll add a comparison table of some sort to my (lengthening!) todo list.
Could you elaborate at all on 'naive and buggy'? I think I probably know what you're getting at, but I'd be interested to hear your thoughts.
Can anyone comment on using Ractive as a replacement to Backbone.View? I'd think that making Ractive the view layer in a Backbone app would go a long way in augmenting a lot of the things that Backbone refuses to do in views (binding, smart DOM management/manipulation, actual templating support)
There's a Ractive.extend() function for this exact use case, which allows you to incorporate all the functionality your Backbone View would have in a reusable constructor. Info on the wiki: https://github.com/Rich-Harris/Ractive/wiki/Ractive.extend()
There's also a concept of 'adaptors' which are ideal for Backbone.Model <-> Ractive binding, though it's a bit experimental and incomplete at the moment. You can bind to a model manually like
model = new MyBackboneModel( attrs );
ractive = new Ractive({ el: whatever, template: tpl, data: model.attributes });
model.on( 'change', function ( model ) {
ractive.set( model.changed );
});
I really like this library.. it's been a while I've been looking for something similar. Angular was a bit "too big" for some of my projects, and backbone was just too verbose. Something like this will let me keep the code clean while still not getting involved in a big framework.
So as this is DOM manipulation, it's a competitor to jQuery, right? If so, what are the advantages over jQuery, and would it make jQuery redundant now (for new projects)?
I wouldn't say it makes jQuery redundant - the AJAX stuff is helpful (if replaceable) and it does a great job of e.g. $div.height() and so on, which can be a source of cross-browser headaches without it. Though personally yes, I find I rarely use jQuery now I've got Ractive.
The difference is the difference between declarative and imperative programming. With jQuery you have to describe the steps that the browser has to follow in order to do something (e.g. $button.toggleClass( 'selected' ), whereas with Ractive you're much closer to simply declaring your intentions (e.g. ractive.toggle( 'selected' ), assuming your template references that variable). It's an inherently more scalable approach (which isn't to knock jQuery at all - they're attacking different if overlapping problems).
Is there anyway to use any other templating system with Ractive other than the Mustache style syntax? Couldn't use microtemplates / EJS style templating for example?
No, Mustache only I'm afraid. The reason is that it's not actually using Mustache or any of the Mustache-based engines (such as Hogan.js) - it's using its own implementation.
That's because almost all other templating engines are string -> string (i.e. you add data to a string template, and get HTML) whereas Ractive is string -> DOM. Microtemplates, EJS etc would have to be reimplemented as string -> DOM engines separately if they were to work with Ractive.
2. Not at all - animation is something I need in my day job all the time, and having .animate() saves me so much time. I wasn't sure if I'd get much use out of transitions (I was jealous of ng-animate and wanted to see if I could implement something similar!) but I've found them very useful. Transitions probably need a bit more work though.
3. It just doesn't need any. The amount of code I could save by using a helper library like Underscore wouldn't be worth the potential extra hassle of version headaches etc. Personally I much prefer using 'fire and forget' libraries with no dependencies.
Yes, and you better hope 50 more come out. Early adopters do your shit work for you. "______.js is picking up speed" is code for "Thousands of hours of unpaid labor have gone into making better tools for you, and evaluating them against other tools."