├── .gitignore ├── README.md ├── app-model.js ├── app.js ├── changelog.md ├── index.html ├── my-regular-view.js ├── my-vdom-view.js ├── package.json └── vdom-view.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Backbone.VDOMView 2 | ================= 3 | 4 | A Backbone.View implementation with [virtual-dom](https://github.com/Matt-Esch/virtual-dom). 5 | 6 | To install: 7 | ``` 8 | npm install 9 | ``` 10 | 11 | To run: 12 | ``` 13 | npm start 14 | ``` 15 | 16 | Make sure to check out the [change log](changelog.md). 17 | -------------------------------------------------------------------------------- /app-model.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Backbone = require('backbone'); 4 | 5 | module.exports = Backbone.Model.extend({ 6 | defaults: { 7 | unit: 'o', 8 | content: '' 9 | }, 10 | tick: function() { 11 | this.set('content', this.get('content').concat(this.get('unit'))); 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var $ = require('jquery'); 4 | require('backbone').$ = $; 5 | 6 | var Model = require('./app-model'); 7 | var MyView = require('./my-vdom-view'); 8 | //var MyView = require('./my-regular-view'); 9 | 10 | var myModel = new Model({ 11 | unit: 'aaaaaa' 12 | }); 13 | 14 | var myView = new MyView({ 15 | model: myModel 16 | }); 17 | myView.render().$el.appendTo('body'); 18 | 19 | setInterval(function() { 20 | myModel.tick(); 21 | }, 1000); 22 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ### v0.0.2 2 | 3 | #### Overview 4 | 5 | * The main goal is to improve the solution to be less scenario-specific and more reusable, playing with foundational methods and event handling 6 | 7 | #### Features 8 | 9 | * Switched the virtual el setup from ```initialize``` to ```setElement```. 10 | 11 | 12 | ### [v0.0.1](https://github.com/tiagorg/Backbone.VDOMView/releases/tag/v0.0.1) 13 | 14 | #### Overview 15 | 16 | * The main goal is to prove the concept of Virtual DOM over Backbone Views as it was suggested on a [Marionette.js thread](https://github.com/marionettejs/backbone.marionette/issues/2126) 17 | 18 | #### Features 19 | 20 | * Based on [virtual-dom](https://github.com/Matt-Esch/virtual-dom) 21 | * Each view's render will compare to its previous state and only diff to it. 22 | * I was able to verify it does really work by comparing DevTools output for 2 scenarios, virtual vs non-virtual: 23 | 24 | ##### Non-virtual 25 | ![screen shot 2014-12-26 at 3 32 55 pm](https://cloud.githubusercontent.com/assets/764487/5559881/db7e521c-8d14-11e4-9c44-fa0d0ea27622.png) 26 | ![screen shot 2014-12-26 at 3 33 29 pm](https://cloud.githubusercontent.com/assets/764487/5559882/e1369908-8d14-11e4-9795-78306243992a.png) 27 | 28 | Notice the increasing number of Nodes, from 628 to 629 in 10s. 29 | The Used JS Heap is pretty high and increasing. 30 | 31 | ##### Virtual 32 | ![screen shot 2014-12-26 at 3 30 55 pm](https://cloud.githubusercontent.com/assets/764487/5559883/e83f20d0-8d14-11e4-93eb-6aa1929d7b36.png) 33 | ![screen shot 2014-12-26 at 3 31 47 pm](https://cloud.githubusercontent.com/assets/764487/5559884/eb53fcaa-8d14-11e4-9d9a-c534a21de720.png) 34 | 35 | Notice the number of Nodes stays on 403 over the same 10s. 36 | There is also plenty of more JS happening (2nd image) but the Used JS Heap is much lower. 37 | 38 | #### Next steps 39 | 40 | * The code is not very neat, it is making certain assumptions about the Backbone.View's ```el``` as it is appending the internal virtual element into it. We want to avoid that by working with ```setElement``` method from Backbone.View. 41 | * As far for Marionette.js: @samccone and @jmeas suggested using Marionette.View as a base class and from there see if we can get event registration and UI working. Also, strive for supporting a ```itemView``` replacement. We should fork this project for Marionette.js specific code. 42 | * Yet another alternative to vdom would be going with HTMLBars. We should learn up until which point is it worth to continue playing with VDOM. 43 | 44 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /my-regular-view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Backbone = require('backbone'); 4 | var _ = require('underscore'); 5 | 6 | module.exports = Backbone.View.extend({ 7 | initialize: function() { 8 | this.model && this.model.on('change', this.render, this); 9 | }, 10 | 11 | template: _.template('

w<%= content %>

'), 12 | 13 | render: function(){ 14 | this.$el.html(this.template(this.model.toJSON())); 15 | return this; 16 | } 17 | }); 18 | -------------------------------------------------------------------------------- /my-vdom-view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var VDOMView = require('./vdom-view'); 4 | var _ = require('underscore'); 5 | 6 | module.exports = VDOMView.extend({ 7 | initialize: function() { 8 | this.model && this.model.on('change', this.render, this); 9 | }, 10 | 11 | template: _.template('

w<%= content %>

'), 12 | 13 | renderEl: function(){ 14 | return this.template(this.model.toJSON()); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Backbone.VDOMView", 3 | "version": "0.0.2", 4 | "description": "A Backbone.View implementation with virtual-dom", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "beefy app.js:build.js --live", 8 | "bundle": "browserify app.js -o build.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/tiagorg/Backbone.VDOMView" 13 | }, 14 | "keywords": [ 15 | "backbone", 16 | "virtual", 17 | "dom", 18 | "vdom", 19 | "view" 20 | ], 21 | "author": "Tiago Garcia", 22 | "license": "ISC", 23 | "bugs": { 24 | "url": "https://github.com/tiagorg/Backbone.VDOMView/issues" 25 | }, 26 | "homepage": "https://github.com/tiagorg/Backbone.VDOMView", 27 | "dependencies": { 28 | "underscore": "1.7.0", 29 | "backbone": "^1.1.2", 30 | "jquery": "^2.1.3", 31 | "html-to-vdom": "^0.3.0", 32 | "virtual-dom": "0.0.24" 33 | }, 34 | "devDependencies": { 35 | "beefy": "^2.1.1", 36 | "browserify": "^7.0.3" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /vdom-view.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Backbone = require('backbone'); 4 | var diff = require('virtual-dom/diff'); 5 | var patch = require('virtual-dom/patch'); 6 | var createElement = require('virtual-dom/create-element'); 7 | var VNode = require('virtual-dom/vnode/vnode'); 8 | var VText = require('virtual-dom/vnode/vtext'); 9 | var convertHTML = require('html-to-vdom')({ 10 | VNode: VNode, 11 | VText: VText 12 | }); 13 | 14 | module.exports = Backbone.View.extend({ 15 | setElement: function() { 16 | Backbone.View.prototype.setElement.apply(this, Array.prototype.slice.call(arguments)); 17 | this.virtualEl = convertHTML(this.el); 18 | this.virtualEl.tagName = this.el.tagName; 19 | this.internalEl = createElement(this.virtualEl); 20 | this.$el.html(this.internalEl); 21 | return this; 22 | }, 23 | 24 | render: function() { 25 | var newVirtualEl = convertHTML(this.renderEl()); 26 | var patches = diff(this.virtualEl, newVirtualEl); 27 | this.internalEl = patch(this.internalEl, patches); 28 | this.virtualEl = newVirtualEl; 29 | return this; 30 | }, 31 | 32 | renderEl: function() { 33 | return this.el; 34 | } 35 | }); 36 | --------------------------------------------------------------------------------