UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

1,101 lines (824 loc) 62.9 kB
<!DOCTYPE html> <!--#################################################################### THIS IS A GENERATED FILE -- ANY CHANGES MADE WILL BE OVERWRITTEN INSTEAD CHANGE: source: [object Object] @page guides/technical ######################################################################## --> <html lang="en"> <head> <meta charset="utf-8"> <title>CanJS - Technical Highlights</title> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <link rel="stylesheet" type="text/css" href="../static/bundles/bit-docs-site/static.css"> <link rel="shortcut icon" sizes="16x16 24x24 32x32 48x48 64x64" href="/docs/images/canjs_favicon.ico"> <link rel="apple-touch-icon" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png"> <link rel="apple-touch-icon-precomposed" sizes="57x57" href="../../docs/images/canjs_favicon_57x57.png"> <link rel="apple-touch-icon" sizes="72x72" href="../../docs/images/canjs_favicon_72x72.png"> <link rel="apple-touch-icon" sizes="114x114" href="../../docs/images/canjs_favicon_114x114.png"> <link rel="apple-touch-icon" sizes="120x120" href="../../docs/images/canjs_favicon_128x128.png"> <link rel="apple-touch-icon" sizes="144x144" href="../../docs/images/canjs_favicon_144x144.png"> <link rel="apple-touch-icon" sizes="152x152" href="../../docs/images/canjs_favicon_152x152.png"> <meta content="yes" name="apple-mobile-web-app-capable"> <meta name="apple-mobile-web-app-status-bar-style" content="white-translucent"> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-2302003-11', 'auto'); ga('send', 'pageview'); </script> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger"/> <label for="nav-trigger">Menu</label> <div id="everything"> <div id="left" class="column"> <div class="top-left"> <div class="brand"> <div class="logo"> <a href="../../index.html" alt="CanJS"></a> <div class="dropdown project-dropdown"> <a href="https://donejs.com/">DoneJS</a> <a href="http://stealjs.com/">StealJS</a> <a href="http://jquerypp.com/">jQuery ++</a> <a href="https://funcunit.com/">FuncUnit</a> <a href="http://documentjs.com/">DocumentJS</a> </div> </div> <div class="version"> <div class="version-number"> 3.0.0 </div> <div class="dropdown version-dropdown"> <a href="https://v2.canjs.com">2.3.27</a> </div> </div> </div> <div class="search-bar"> <p> &nbsp; </p> </div> </div> <div class="bottom-left"> <div class="social-side-container"> <ul class="social-side"> <li> <a class="header-mobile github" href="https://github.com/canjs/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/github.png">Github</a> </li> <li> <a class="header-mobile twitter" href="https://twitter.com/canjs" target="_blank"><img class="social-icon-small" src="../../docs/images/twitter.png">Twitter</a> </li> </ul> <ul class="social-side"> <li> <a class="header-mobile" href="https://gitter.im/canjs/canjs" target="_blank">Chat</a> </li> <li> <a class="header-mobile" href="http://forums.donejs.com/c/canjs" target="_blank">Forum</a> </li> </ul> </div> <ul> <li class=" parent expanded"> <a class="page" href="../guides.html" title="Welcome to CanJS! These guides are here to help you develop and improve your relationship with CanJS. After all, picking a JavaScript framework is a commitment. We want CanJS to be the framework you marry. This page helps you know how advance through the different stages of this relationship:"> Guides </a> <ul> <li> <span>introduction</span> <ul> <li class=" "> <a class="page" href="mission.html" title="Learn about CanJS&#x27;s mission, why it matters, and how we&#x27;ve worked (and will keep working) to accomplish it."> Mission </a> </li> <li class="current parent expanded"> <a class="page" href="technical.html" title=""> Technical Highlights </a> </li> <li class=" "> <a class="page" href="who-uses-canjs.html" title=""> Who uses CanJS? </a> </li> </ul> </li> <li> <span>experiment</span> <ul> <li class=" "> <a class="page" href="chat.html" title="This guide walks through building real time chat application with CanJS&#x27;s Core libraries. It takes about 30 minutes to complete."> Chat Guide </a> </li> <li class=" "> <a class="page" href="todomvc.html" title="This guide walks through building a slightly modified version of TodoMVC with CanJS&#x27;s Core libraries and can-fixture. It takes about 1 hour to complete."> TodoMVC Guide </a> </li> <li class=" "> <a class="page" href="atm.html" title="This guide walks through building and testing an ATM application with CanJS&#x27;s Core libraries. It teaches how to do test driven development (TDD) and manage complex state. It takes about 2 hours to complete."> ATM Guide </a> </li> <li class=" "> <a class="page" href="setup.html" title="CanJS is packaged in multiple ways so that it can fit into any development workflow. Learn how to setup CanJS in different environments."> Setting up CanJS </a> </li> </ul> </li> <li> <span>commitment</span> <ul> <li class=" "> <a class="page" href="api.html" title="This page walks through how to use and understand CanJS&#x27;s API documentation."> API Guide </a> </li> <li class=" "> <a class="page" href="examples.html" title=""> Examples </a> </li> <li class=" "> <a class="page" href="../roadmap.html" title="Learn about CanJS&#x27;s future plans and how we make them, and how you can influence them."> Roadmap </a> </li> <li class=" "> <a class="page" href="../migrate-3.html" title=""> Migrating to 3.0 </a> </li> </ul> </li> <li> <span>contribute</span> <ul> <li class=" "> <a class="page" href="contributing/bug-report.html" title="Learn how to submit a bug report."> Bug Report </a> </li> <li class=" "> <a class="page" href="contributing/code.html" title="Learn how contribute a code change to CanJS."> Code </a> </li> <li class=" "> <a class="page" href="contributing/documentation.html" title="Learn how to improve CanJS&#x27;s site and documentation."> Documentation </a> </li> <li class=" "> <a class="page" href="contributing/evangelism.html" title="Learn about resources that can help you spread the word about CanJS."> Evangelism </a> </li> <li class=" "> <a class="page" href="contributing/feature-suggestion.html" title="Learn how to suggest a feature."> Feature Suggestion </a> </li> <li class=" "> <a class="page" href="contributing/releases.html" title="Release and hosting information for CanJS maintainers."> Releases </a> </li> </ul> </li> </ul> </li> <li class=" "> <a class="page" href="../can-core.html" title="The best, most hardened and generally useful libraries in CanJS."> Core </a> </li> <li class=" "> <a class="page" href="../can-ecosystem.html" title="Useful libraries that extend or add important features to the core collection."> Ecosystem </a> </li> <li class=" "> <a class="page" href="../can-infrastructure.html" title="Utility libraries that power the core and ecosystem collection."> Infrastructure </a> </li> <li class=" "> <a class="page" href="../can-legacy.html" title="Former libraries that we still accept patches for, but are not under active development."> Legacy </a> </li> </ul> </div> </div> <div id="right" class="column"> <div class="top-right"> <div class="top-right-top"> <ul class="top-right-bitovi"> <li class="dropdown"> <a href="http://bitovi.com" class="bitovi icon-bits">Bitovi</a> <ul class="dropdown-menu"> <li><a href="http://bitovi.com">Bitovi.com</a></li> <li><a href="http://bitovi.com/blog/">Blog</a></li> <li><a href="http://bitovi.com/consulting/">Consulting</a></li> <li><a href="http://bitovi.com/training/">Training</a></li> <li><a href="http://bitovi.com/open-source/">Open Source</a></li> </ul> </li> </ul> <div class="brand"> <div class="logo"> <a href="../../index.html" alt="CanJS"></a> </div> </div> <ul class="top-right-links"> <li> <a href="https://gitter.im/canjs/canjs">Chat</a> </li> <li> <a href="http://forums.donejs.com/c/canjs">Forum</a> </li> <li> <a class="github-button nav-social" href="https://github.com/canjs/canjs" data-count-href="/canjs/canjs/stargazers" data-count-api="/repos/canjs/canjs#stargazers_count">Star</a> </li> <li> <a href="https://twitter.com/canjs" class="twitter-follow-button nav-social" data-show-count="true" data-show-screen-name="false">Follow @canjs</a><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> </li> </ul> </div> <div class="breadcrumb"> <li><a href="../../index.html">CanJS</a></li> / <li><a href="../guides.html">Guides</a></li> / <li><a href="technical.html">Technical Highlights</a></li> <li class="breadcrumb-dropdown">/ <a> On this page</a> <ul class="on-this-page"></ul> </li> <div class="nav-toggle" title="Back to top"></div> </div> </div> <div class="bottom-right"> <article> <section class="title"> <div class="page-type"> <h1>Technical Highlights</h1> <div>page</div> </div> <section class="description"> </section> </section> <section class="on-this-page-table"> </section> <section class="title-footer"> <ul class="title-links"> <!-- <li><a href="#">docco</a></li> --> <li><a href="//github.com/canjs/canjs/tree/v3.0.0/docs/can-guides/introduction/technical.md">source</a></li> <!-- <li><a href="#">download</a></li> --> <!-- <li><a href="#">tests</a></li> --> </ul> </section> <section class="body"> <p>CanJS is a JavaScript MVVM library, with browser support all the way back to IE9.</p> <p>While CanJS does a lot of things, there are several features that stand apart.</p> <h3>1. Computes</h3> <p>Computes are like event streams, but much easier to compose and friendlier to use, because they always have a synchronous value.</p> <p>They can be used for observable values:</p> <pre><code class="language-javascript">var tally = compute(12); tally(); // 12 tally.on(&quot;change&quot;,function(ev, newVal, oldVal){ console.log(newVal,oldVal) }) </code></pre> <p>Or an observable value that derives its value from other observables.</p> <pre><code class="language-javascript">var person = new Person({ firstName: 'Alice', lastName: 'Liddell' }); var fullName = compute(function() { return person.firstName + ' ' + person.lastName; }); fullName.on('change', function(ev, newVal, oldVal) { console.log(&quot;This person's full name is now &quot; + newVal + '.'); }); person.firstName = 'Allison'; // The log reads: //-&gt; &quot;This person's full name is now Allison Liddell.&quot; </code></pre> <h3>2. Observable maps and lists</h3> <p>Object-oriented observables that mix in functional behavior, compose state naturally, and are easy to test. These objects and arrays provide the backbone of a strong ViewModel layer and the glue for data binding templates.</p> <pre><code class="language-javascript">var Person = DefineMap.extend( { first: &quot;string&quot;, last: {type: &quot;string&quot;}, fullName: { get: function(){ return this.first+&quot; &quot;+this.last; } }, age: {value: 0}, }); var me = new Person({first: &quot;Justin&quot;, last: &quot;Meyer&quot;}) me.fullName //-&gt; &quot;Justin Meyer&quot; me.age //-&gt; 0 </code></pre> <h3>3. Models</h3> <p>On the surface, encapsulates the data layer and connects to the backend. Behind the surface, a collection of opt-in behaviors provide complex optimizations.</p> <ul> <li><a href="../../can-connect/real-time/real-time.html">Automatic real-time support</a>: Live updates to sets of data that includes or excludes instances based on set logic.</li> <li>Opt-in performance optimizations: <a href="../../can-connect/fall-through-cache/fall-through-cache.html">Fallthrough caching</a>, <a href="../../can-connect/data/combine-requests/combine-requests.html">request combination</a>, <a href="../../can-connect/data/localstorage-cache/localstorage-cache.html">localstorage</a> and <a href="../../can-connect/data/memory-cache/memory-cache.html">in-memory</a> data cache</li> <li><a href="../../can-connect/constructor/store/store.html">Prevents memory leaks</a>: reference counting and removal of unused instances</li> </ul> <pre><code class="language-javascript">var todoConnection = superMap({ idProp: &quot;_id&quot;, Map: Todo, List: TodoList, url: &quot;/services/todos&quot;, name: &quot;todo&quot; }); Todo.getList({}).then(function(todos){ ... }); </code></pre> <p>CanJS has a lot of features. This page will dive into details on the best ones and why they’re valuable to developers.</p> <h2>Modularity</h2> <p>CanJS, as of the 3.0 release, has been broken up into several dozen completely independent modules, each with it’s own separate npm package and version number using <a href="http://semver.org">Semantic Versioning</a>.</p> <p>The obvious advantage of library modularity is that pieces can be used without the whole. You can choose to use Observables or can-fixture without the rest of the framework. You could even mix and match CanJS libraries with other libraries like React quite easily.</p> <p>However, that’s not the main benefit modularity provides to users.</p> <p>Why is this important? It makes it easy to balance stability and innovation.</p> <p>For users that have an existing application, this modularity means they can leave functional parts of their application code alone, forever, while using new CanJS features and modules in future new areas of the application.</p> <h3>Adopt new framework features without any upgrade effort or library bloat</h3> <p>As new modules are released, containing yet unknown better ways to build applications (i.e. a better template engine or a new model layer), you can incorporate them, without replacing the existing modules. And they’ll share the same lower level dependencies.</p> <p>For example, say an entire application is built with CanJS 3.0. The following year, the developer is tasked with adding a new feature. At that point, a new templating engine called Beard has been released, with a new set of features superior to Stache. The developer can simply leave the remainder of the application using CanJS 3.0 (can-stache), and import can-beard in the new area of the application. It will likely still share the same lower level dependencies, since those are less likely to change very often, so this adds an insignificant amount of code weight.</p> <p>Angular 1.x to 2.0 is a good counterexample to this approach. The recommended upgrade strategy was to either rewrite your application with 2.0 (a lot of extra work) or load your page with 1.X and 2.0, two full versions of the framework (a lot of code weight). Neither is preferable.</p> <p>With the modularity described in CanJS, applications can import multiple versions of the high level APIs while avoiding the work of rewriting with future syntaxes and the extra code weight of importing two full frameworks.</p> <h3>Faster, more stable framework releases</h3> <p>Because CanJS’s pieces can push out updates independently, small bug fixes and performance enhancements can be released immediately, with much lower risk. For example, if a bug is observed and fixed in can-compute, a new version of can-compute will be pushed out that day, as soon as tests pass.</p> <p>By contrast, with the typical all-in-one structure, there will usually be a much longer delay between the can-compute bug fix and the next release. This is because making a new release for CanJS as a whole is a much more involved, risky endeavour. The can-compute change has to be tested much more rigorously against the framework as a whole. Plus there might be other changes in other areas in progress that need to land before the release can go out.</p> <p>It’s similar to the difference between making plans with your best friend vs 10 of your friends. The larger group is going to move much more slowly because there are many more pieces to coordinate.</p> <h2>Observables</h2> <h3>What are they</h3> <p>Observables are special types of data that allow their property changes to be &quot;observed&quot; using typical event listeners. In modern web applications, they also enable “data bound” templates, which cause sections of the UI to be automatically re-rendered whenever certain data properties change, a powerful feature that removes large amounts of repetitive application code.</p> <p>CanJS has an observable layer that is powerful, performant, and flexible. It binds together various parts of applications, using expressive property definitions.</p> <pre><code class="language-javascript">var define = require(&quot;can-define&quot;); var Person = function(first, last){ this.first = first; this.last = last; }; define(Person.prototype,{ first: { type: &quot;string&quot; }, last: { type: &quot;string&quot; }, fullName: { get: function(){ return this.first+&quot; &quot;+this.last; } } }); </code></pre> <p>Observables are very powerful and easy to use on their own, but in CanJS applications, they are also used as a ViewModel, a layer that sits between the model and the view and contains the state of the application. More on ViewModels <a href="#ViewModels">below</a>.</p> <h3>Why they’re powerful</h3> <p>Observables as a concept enable an important architectural advantage in large applications.</p> <p>Say you have an application with three discrete components.</p> <p>Without observables, you might have component A tell component B to update itself when something happens, like user input.</p> <p>With observables, you would separate the state of your application into a separate layer, and each component would be able to change parts of the state it cares about and listen to parts of the state it needs. When the same user input occurs, component A would update the observable state object. Component B would be notified that a property of the observable state has changed, and update itself accordingly.</p> <p>Why is this better? Because this allows each component to be untied from the rest. They each get passed the state they need, but are unaware of the rest of the components and their needs. The architecture diagram changes from this:</p> <p><img src="../../docs/can-guides/images/introduction/no-observables.png" style="width:100%;max-width:750px" alt="Diagram of app without observables"/></p> <p>To this:</p> <p><img src="../../docs/can-guides/images/introduction/with-observables.png" style="width:100%;max-width:750px" alt="Diagram of app using observables"/></p> <p>Not only is this simpler to understand, these components are more easily testable and shareable, and changes are more contained are less risky to have unwanted side effects. All of these advantages are possible because of observables.</p> <h3>Synchronous, Object oriented, and Functional</h3> <p>In CanJS observables, changes to a property in an object or array immediately and synchronously notify any event listeners.</p> <p>This is in contrast to dirty checking observables, such as those used in Angular 1.X, which did not immediately notify listeners, but did so asynchronously after a digest cycle.</p> <p>Synchronous code is always easier to debug and test.</p> <p>CanJS observables are both object oriented and functional, leaving it up to the developer to decide which approach works better for the problem at hand.</p> <p>They are object oriented because you can create observables out of any normal object or array, such as the example shown above. They are functional because you can use filter, map, and other functional helpers to compose properties that derive their value based on the changing state of other properties. For example:</p> <pre><code class="language-javascript">var TodoList = DefineList.extend({ &quot;#&quot;: Todo, get completed(){ return this.filter({complete: true}) } }); var todos = new TodoList([{complete: true}, {complete:false}]); todos.completed.length //-&gt; 1 </code></pre> <p>There is also a <a href="https://github.com/canjs/can-stream">can-stream project</a> that converts observables into event-streams.</p> <h3>Computed properties</h3> <p>Observables can define properties that depend on other properties, and they'll automatically recompute only when their dependent properties change. The <code>fullName</code> property above is an example of a computed property.</p> <pre><code class="language-javascript">var person = new Person(&quot;Justin&quot;, &quot;Meyer&quot;); person.first //-&gt; &quot;Justin&quot; person.last //-&gt; &quot;Meyer&quot; person.fullName //-&gt; &quot;Justin Meyer&quot; </code></pre> <p>When <code>first</code> or <code>last</code> are changed, <code>fullName</code> is immediately changed as well, and any listeners of the <code>fullName</code> property synchronously notified.</p> <h3>Data bound templates</h3> <p>Although not directly a feature of observables, data bound templates are a feature of CanJS Views that are tied closely with the observable layer.</p> <p>Templates in CanJS bind to property changes and update the DOM as needed.</p> <p>For example, there may be a template that looks like this:</p> <pre><code>&lt;div&gt;{{fullName}}&lt;/div&gt; </code></pre> <p>If first is changed:</p> <pre><code class="language-javascript">person.first = 'Jane'; </code></pre> <p><code>fullName</code> recomputes, then the DOM automatically changes to reflect the new value.</p> <p>Observables express complex relationships between data, without regard to its display. Views express properties from the observables, without regard to how the properties are computed. The app then comes alive with rich functionality.</p> <p>DIAGRAM - circular arrows pointing back to each layer</p> <h3>Expressive property definition syntax</h3> <p>Can-define supports an expressive, powerful syntax for defining properties on observable objects. It supports get, set, initial value, and type conversion</p> <h3>Batched events</h3> <p>Observable property changes causing synchronous events that update the DOM is great for most scenarios, but there are times where this could cause performance problems. To prevent unnecessary DOM updates, events can be batched using <code>canBatch.start</code> and <code>canBatch.stop</code>.</p> <p>Consider a todo list with a completeAll method that marks every todo in the list as complete and completeCount that counts the number of complete todos:</p> <pre><code class="language-javascript">var Todo = DefineMap.extend({ name: &quot;string&quot;, complete: &quot;boolean&quot; }); var TodoList = DefineList.extend({ &quot;#&quot;: Todo, completeAll: function(){ this.forEach(function(todo){ todo.complete = true; }) }, completeCount: function(){ return this.filter({complete: true}).length; } }) </code></pre> <p>When completeAll is called, the {{todos.completeCount}} magic tag will update once for every completed count. We can prevent this by wrapping completeAll with calls to start and stop:</p> <pre><code class="language-javascript">completeAll: function(){ canBatch.start(); this.forEach(function(todo){ todo.complete = true; }); canBatch.end(); }, </code></pre> <h3>Inferred dependencies</h3> <p>In other libraries that support computed properties, you declare your dependencies, like this:</p> <pre><code class="language-javascript">fullName: Ember.computed('firstName', 'lastName', function() { return `${this.get('firstName')} ${this.get('lastName')}`; }) </code></pre> <p>In CanJS, computed properties are able to determine their own dependencies without needing to explicitly declare them, therefore requiring less boilerplate code and repetition.</p> <p>The way this works is by keeping track of any properties referenced when the computed function first runs, and binding the computed property to those property change events.</p> <p>Each time the computed function is run, these dependencies are re-evaluated, so even if there are different dependencies hiding in a conditional, those will be bound to the next time around.</p> <pre><code class="language-javascript">origFullName: { get: function(){ if(this.gender == &quot;female&quot; &amp;&amp; this.married) { return this.first+&quot; &quot;+this.last; } else { return this.first+&quot; &quot;+this.maiden; } } } </code></pre> <h3>Compiled property behavior</h3> <p>In CanJS 3.0, getting and setting properties whose behavior is defined through can-define is 3x faster than the previous version. This was achieved by generating compiled functions for getting and setting each property based on the property definition when the object is defined. The previous implementations used conditionals to check if each property had, for example, a type definition, or a get function, etc, and run each behavior if it was found. Now, each property has an optimized function that runs only the behaviors that are defined.</p> <p>This may not seem significant, but in fact this allows CanJS observables to provide the rich behaviors of can-define without sacrificing any performance. Competitor libraries either don’t allow for the same rich behaviors or are much slower performing gets and sets.</p> <h3>Compared to other frameworks</h3> <p>In Angular 1.X, there are no direct observables. It uses dirty checking with regular JavaScript objects, which means at the end of the current $digest cycle, it will run an algorithm that determines what data has changed. This has performance drawbacks, as well as making it harder to write simple unit tests.</p> <p>Angular 2.0</p> <p>In React, there is no observable data layer. You could define a fullName like we showed above, but it would be recomputed every time render is called, whether or not it has changed. Though it's possible to isolate and unit test its ViewModel, it's not quite set up to make this easy. For more details on how other React-based frameworks compare, read <a href="./comparison.html">this</a>.</p> <h2>ViewModels</h2> <p>ViewModels are a type of observable that represents the state of a CanJS component. In CanJS, the ViewModel is it’s own layer, completely independent from the template and the component.</p> <p>The introduction of a strong ViewModel provides key advantages for maintaining large applications:</p> <ul> <li><p>Decouples the presentation from its business logic - A ViewModel is essentially an object and methods representing the state of a View. This separation of concerns enables simple, dumb HTML-based Views containing minimal logic, while the ViewModel manages the complexities of application logic.</p></li> <li><p>Enables designer/developer cooperation - Because the view is stripped of code and application logic, designers can safely and comfortably change the View without fear of breaking things.</p></li> <li><p>Enables easier <a href="https://donejs.com/Features.html#section=section_ComprehensiveTesting">testing</a> - ViewModels can be unit tested easily. Because they represent the view's state without any knowledge of the DOM, they provide a simple interface for testing.</p></li> </ul> <h3>Independent ViewModels</h3> <p>CanJS ViewModels are unique in their independence from other layers. ViewModels and Views are completely decoupled, and can be developed completely isolated from a template.</p> <p>For example, here's a typical ViewModel, which is often defined in its own separate file like viewmodel.js and exported as its own module:</p> <pre><code class="language-javascript">export const ViewModel = Map.extend({ define: { fullName: { get () { return this.attr(&quot;first&quot;) + &quot; &quot; + this.attr(&quot;last&quot;); } } } }) </code></pre> <p>The template (view) lives in its own file, so a designer could easily modify it without touching any JavaScript. This template renders the ViewModel property from above:</p> <pre><code>&lt;div&gt;{{fullName}}&lt;/div&gt; </code></pre> <p>A custom HTML element, also known as a component, would be used to tie these layers together:</p> <pre><code class="language-javascript">import Component from 'can/component/'; import ViewModel from &quot;./viewmodel&quot;; import template from './template.stache!'; Component.extend({ tag: 'my-component', viewModel: ViewModel, template }); </code></pre> <p>The ViewModel is defined as its own module and exported as an ES6 module, so it can be imported into a unit test, instantiated, and tested in isolation from the DOM:</p> <pre><code class="language-javascript">import ViewModel from &quot;./viewmodel&quot;; QUnit.test('fullName works', function() { var vm = new ViewModel(); vm.attr('first', 'John'); vm.attr('last', 'Doe'); QUnit.equal(vm.attr('fullName'), 'John Doe'); }); </code></pre> <p>In other frameworks, ViewModels don't enjoy this level of independence. Every React class has a render function, which is essentially a template, so the View, ViewModel, and component definition are typically part of the same module. Every Angular directive is a ViewModel. In CanJS, separating the ViewModel, template, and custom element is encouraged, making each module more decoupled and easier to unit test.</p> <h2>MVVM</h2> <p>CanJS applications employ a <a href="https://en.wikipedia.org/wiki/Model_View_ViewModel">Model-View-ViewModel</a> architecture pattern.</p> <p><img src="../../docs/can-guides/images/introduction/mvvm.png" style="width:100%;max-width:750px" alt="Model-View-ViewModel Diagram"/></p> <p>The following video introduces MVVM in CanJS, focusing on the strength of the ViewModel with an example. (Note: the syntax used in this video shows CanJS 2.3, which has some slight differences from 3.0, but the concepts are the same).</p> <h3>MVVM overview</h3> <p><strong>Models</strong> in CanJS are responsible for loading data from the server. They can be reused across ViewModels. They often perform data validation and sanitization logic. Their main function is to represent data sent back from a server. Models use intelligent set logic that enables real time integration and caching techniques.</p> <p><strong>Views</strong> are templates. Specifically, templates that use handlebars syntax, but with data bindings and rewritten for better performance. Handlebars templates are designed to be logic-less.</p> <p><strong>ViewModels</strong> were covered in detail above.</p> <h3>Composed, hierarchical state</h3> <p>CanJS applications are composed from hierarchical components, each containing their own independent state (it’s own ViewModel). This architecture is at the core of CanJS’s approach to building large applications.</p> <p>The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application.</p> <p>Hierarchical State Machines (HSMs) is one way to describe this concept. UML diagrams allow for modeling of <a href="https://en.wikipedia.org/wiki/UML_state_machine#Hierarchically_nested_states">hierarchically nested states</a>, such as those in CanJS applications. Check out the <a href="../../guides/atm.html">ATM guide</a> for an example of a hierarchical state machine implemented using hierarchical ViewModels.</p> <p>React, and other competing frameworks, have a big global state object that contains the application’s state. The problem with this approach, at least in any application with even moderate complexity, is that this monolithic layer becomes a dependency of every component in the application. This creates additional downstream problems:</p> <ul> <li><p>Changes to the state object can have non-obvious and harmful side effects, causing unexpected bugs.</p></li> <li><p>It becomes harder to work independently on one component of the project. Thus, scaling the team and parallelizing the effort becomes trickier, as several developers might have to touch the same central state layer.</p></li> <li><p>Individual components become less reusable in other contexts because of their dependency on this external state layer.</p></li> <li><p>Individual components become harder to test in isolation, since testing them requires importing or mocking large external dependencies</p></li> </ul> <h2>Views</h2> <p>CanJS views are <a href="http://handlebarsjs.com/">Handlebars</a> templates, with special features baked in, like event bindings, custom elements, and performance optimizations.</p> <pre><code>&lt;header id=&quot;header&quot;&gt; &lt;h1&gt;todos&lt;/h1&gt; &lt;todo-create/&gt; &lt;/header&gt; &lt;ul id=&quot;todo-list&quot;&gt; {{#each todos}} &lt;li class=&quot;todo {{#if complete}}completed{{/if}}&quot;&gt; &lt;div class=&quot;view&quot;&gt; &lt;input class=&quot;toggle&quot; type=&quot;checkbox&quot; {($checked)}=&quot;complete&quot;&gt; &lt;label&gt;{{name}}&lt;/label&gt; &lt;button class=&quot;destroy&quot;&gt;&lt;/button&gt; &lt;/div&gt; &lt;input class=&quot;edit&quot; type=&quot;text&quot; value=&quot;{{name}}&quot;/&gt; &lt;/li&gt; {{/each}} &lt;/ul&gt; </code></pre> <h3>Handlebars</h3> <p>Handlebars templates are a superset of Mustache templates that includes some convenient helper methods.</p> <p>Developers love Mustache templates because they are designed to be &quot;logic-less&quot;, meaning no if statements, else clauses, for loops. There are only tags. The resulting simplicity makes templates easier to read and understand. It also makes it possible for designers to modify templates more easily, with less of a risk of breaking something.</p> <p>CanJS’s version of Handlebars is called <a href="../../can-stache.html">can-stache</a>.</p> <h3>One, two-way, and event bindings</h3> <p>CanJS templates support data and event bindings through the <a href="../../can-stache-bindings.html">can-stache-bindings</a> module.</p> <p>Data binding means Stache templates bind to observable property changes and update the DOM as needed.</p> <h4>Data binding</h4> <p>For example, there may be a template that looks like this:</p> <pre><code>&lt;div&gt;{{firstName}}&lt;/div&gt; </code></pre> <p>Initially, if person is an observable like <code>{firstName: ‘Mila’}</code>, then the DOM would render like:</p> <pre><code>&lt;div&gt;Mila&lt;/div&gt; </code></pre> <p>An invisible binding is created for any properties of observable data. If <code>first</code> is changed:</p> <pre><code class="language-javascript">person.firstName = 'Jane'; </code></pre> <p><code>firstName</code> triggers a change. The Stache binding changes the DOM to reflect the new value.</p> <pre><code>&lt;div&gt;Jane&lt;/div&gt; </code></pre> <p>When a change occurs that triggers a data binding, Stache is very precise about modifying only the most localized part of the template needed to reflect the change. More on that below.</p> <h4>Event and input binding</h4> <p>Setting up an event binding on an element is simple:</p> <pre><code>&lt;div ($click)=&quot;doSomething()&quot;/&gt; </code></pre> <p>The value of the event binding can be inline JavaScript that modifies data in the template, or it can be a method on the ViewModel, if the template is part of a custom element.</p> <p>Stache also supports setting up two way data bindings with input values:</p> <pre><code>&lt;input value='{{plateName}}'&gt; </code></pre> <p>The plateName property will always reflect the value of this input, and vice versa.</p> <h4>Passing data between custom elements</h4> <p>Similar to the typical data bindings shown in the example above, components pass parts of their ViewModel to the ViewModels of child components, all the way down the application hierarchy. This is done using HTML attributes when instantiating a custom element.</p> <p>Stache allows users to control the direction of data flow from parent to child components, for maximum flexibility. Properties that are passed from one component to another can create bindings in either direction, or both directions.</p> <p>Sometimes you want changes in the parent component to update the child component:</p> <pre><code>&lt;my-component {child-prop}=&quot;value&quot;/&gt; </code></pre> <p>Sometimes you want changes in the child to update the parent:</p> <pre><code>&lt;my-component {^child-prop}=&quot;value&quot;/&gt; </code></pre> <p>Sometimes you want changes in the parent to update the child, and vice versa. This is especially useful when binding to the value of an input:</p> <pre><code>&lt;my-component {(child-prop)}=&quot;value&quot;/&gt; </code></pre> <h3>Custom elements</h3> <p>One of the most important concepts in CanJS is splitting up your application functionality into independent, isolated, reusable custom HTML elements.</p> <p>The major advantages of building applications based on custom HTML elements are:</p> <ol> <li><p>Ease of page composition - Designers can do it! Non-developers can express complex behavior with little to no JavaScript required. All you need to build a new page or feature is HTML.</p></li> <li><p>Forced modularity - Because the nature of HTML elements are isolated modules, custom HTML elements must be designed as small, isolated components. This makes them easier to test, debug, and understand.</p></li> <li><p>Reuse - Custom elements are designed to be reusable across pages and applications.</p></li> </ol> <p>Consider the following example:</p> <pre><code>&lt;order-model get-list=&quot;{ period='previous_week' }&quot; {^value}=&quot;*previousWeek&quot; /&gt; &lt;order-model get-list=&quot;{ period='current_week' }&quot; {^value}=&quot;*currentWeek&quot; /&gt; &lt;bit-c3&gt; &lt;bit-c3-data&gt; &lt;bit-c3-data-column key=&quot;Last Week&quot; {value}=&quot;*previousWeek.totals&quot; /&gt; &lt;bit-c3-data-column key=&quot;This Week&quot; {value}=&quot;*currentWeek.totals&quot; /&gt; &lt;/bit-c3-data&gt; &lt;/bit-c3&gt; </code></pre> <p>This code demonstrates:</p> <ol> <li><p>An element that can load data</p></li> <li><p>Composable widget elements (a graph with a line-series)</p></li> </ol> <p>If our designer wanted to add another period, all they would need to do is add another <code>&lt;order-model&gt;</code> and <code>&lt;bit-c3-data-column&gt;</code> element.</p> <p>Here’s a working version of the same example in a JSBin.</p> <p><a href="http://jsbin.com/puwesa/embed?html,output">Custom HTML Elements on jsbin.com</a></p> <p>Just like HTML’s natural advantages, composing entire applications from HTML building blocks allows for powerful and easy expression of dynamic behavior.</p> <h4>Benefits of custom elements</h4> <p>First, it's important to understand the background of custom elements and their advantages.</p> <p>Before custom HTML elements existed, to add a datepicker to your page, you would:</p> <ol> <li><p>Load a datepicker script</p></li> <li><p>Add a placeholder HTML element</p></li> </ol> <pre><code>&lt;div class='datepicker' /&gt; </code></pre> <ol> <li>Add JavaScript code to instantiate your datepicker</li> </ol> <pre><code class="language-javascript">$('.datepicker').datepicker() </code></pre> <p>With custom HTML elements, to add the same datepicker, you would:</p> <ol> <li><p>Load a datepicker script</p></li> <li><p>Add the datepicker to your HTML or template:</p></li> </ol> <pre><code>&lt;datepicker value=&quot;{date}&quot;/&gt; </code></pre> <p>That might seem like a subtle difference, but it is actually a major step forward. The custom HTML element syntax allows for instantiation, configuration, and location, all happening at the same time.</p> <p>Custom HTML elements are one aspect of <a href="http://webcomponents.org/">Web Components</a>, a collection of browser specs that have <a href="http://caniuse.com/#search=components">yet to be implemented</a> across browsers.</p> <h4>Defining a custom element</h4> <p><a href="../../can-component.html">can-component</a> is a modern take on web components.</p> <p>Components in CanJS have three basic building blocks:</p> <ul> <li><p>a template</p></li> <li><p>a viewModel object</p></li> <li><p>event handlers</p></li> </ul> <pre><code class="language-javascript">var Component = require(&quot;can-component&quot;); var DefineMap = require(&quot;can-define/map/map&quot;); var stache = require(&quot;can-stache&quot;); var HelloWorldVM = DefineMap.extend({ visible: {value: false}, message: {value: &quot;Hello There!&quot;} }); Component.extend({ tag: &quot;hello-world&quot;, view: stache(&quot;{{#if visible}}{{message}}{{else}}Click me{{/if}}&quot;), ViewModel: HelloWorldVM, events: { click: function(){ this.viewModel.visible = !this.viewModel.visible; } } }); </code></pre> <p>Another way to define a component is with a <a href="https://github.com/donejs/done-component">web component</a> style declaration, using a single file with a <code>.component</code> extension:</p> <pre><code>&lt;can-component tag=&quot;hello-world&quot;&gt; &lt;style type=&quot;less&quot;&gt; i { color: red; } &lt;/style&gt; &lt;template&gt; {{#if visible}}&lt;b&gt;{{message}}&lt;/b&gt;{{else}}&lt;i&gt;Click me&lt;/i&gt;{{/if}} &lt;/template&gt; &lt;script type=&quot;view-model&quot;&gt; export default { visible: true, message: &quot;Hello There!&quot; }; &lt;/script&gt; &lt;script type=&quot;events&quot;&gt; export default { click: function(){ this.viewModel.attr(&quot;visible&quot;, !this.viewModel.attr(&quot;visible&quot;)) } }; &lt;/script&gt; &lt;/can-component&gt; </code></pre> <h4>Loading data with custom elements</h4> <p>The beauty and power of custom HTML elements is most apparent when visual widgets (like graphs) are combined with elements that express data.</p> <p>Back to our original example:</p> <pre><code>&lt;order-model findAll=&quot;{previousWeek}&quot; [previousWeekData]=&quot;{value}&quot;/&gt; &lt;order-model findAll=&quot;{currentWeek}&quot; [currentWeekData]=&quot;{value}&quot;/&gt; &lt;bit-graph title=&quot;Week over week&quot;&gt; &lt;bit-series data=&quot;{../previousWeekData}&quot; /&gt; &lt;bit-series data=&quot;{../currentWeekData}&quot; color=&quot;Blue&quot;/&gt; &lt;/bit-graph&gt; </code></pre> <p>This template combines a request for data with an element that expresses it. It's immediately obvious how you would add or remove features from this, allowing for quick changes and easy prototyping. Without custom elements, the same changes would require more difficult code changes and wiring those changes up with widget elements that display the data.</p> <p>Data custom elements are part of can-connect's <a href="../../can-connect/can/tag/tag.html">can-tag</a> feature.</p> <h3>Minimal DOM updates</h3> <p>Virtual DOM</p> <p>Consider the following Stache template:</p> <pre><code>{{#rows}} &lt;div&gt;{{name}}&lt;/div&gt; {{/rows}} </code></pre> <p>And the following change to its data:</p> <pre><code class="language-javascript">rows[0].name = 'changed'; // change the first row's name </code></pre> <p>A data binding for that row would be invoked. The data binding results in the following code being run:</p> <pre><code class="language-javascript">textNode.nodeValue = 'changed'; </code></pre> <p>Similarly, if the binding existed as an attribute, like <code>&lt;div class={{className}}&gt;</code>, the data binding would use <code>setAttribute</code> to make the update.</p> <p>This is significant because Stache takes pains to localize any changes to a template, changing only the most minimal piece necessary. Updates to the DOM are relatively expensive, so stache tries to keep the path between a data change and the DOM change as frictionless as possible.</p> <p>In Backbone, you would need to manually re-render the template or roll your own rendering library.</p> <p>In React and other virtual DOM libraries, that would result in the virtual DOM being re-rendered. A diff algorithm comparing the new and old virtual DOM would discover the changed node, and then the specific DOM node would be updated.</p> <p>Stache, by comparison, performs less logic than Virtual DOMs would require in order to update the DOM in the most minimal way necessary because the virtual DOM comparison step is not necessary, which is visible in the following benchmark that tests the time needed to update the DOM when a single property changes:</p> <p><img src="../../docs/can-guides/images/introduction/dom-updates.png" style="width:100%;max-width:750px" /></p> <p>You can run this test yourself at <a href="http://output.jsbin.com/giyobi/1">JS Bin</a></p> <p>This performance gap is more visible when rendering a large number of items in the page:</p> <p><img src="../../docs/can-guides/images/introduction/rendering-performance.png" style="width:100%;max-width:750px" /></p> <p><em>For a small set of todos the difference is negligible but as the number increases the gap widens to the point where React is 6 times slower than Stache when rendering 1000 todos.</em></p> <p>You can run this test for yourself at <a href="http://output.jsbin.com/monoqagofa/1">JS Bin</a>.</p> <p>With synchronously observable objects and data bindings that change minimal parts of the DOM, Stache aims to hit the sweet spot between powerful and performant.</p> <h3>Template minification</h3> <p>While templates provide obvious benefits to application maintainability, they can be a bane on performance unless they are correctly integrated into the build tool chain.</p> <p>An ecosystem library called <a href="../../steal-stache.html">steal-stache</a> provides an easy hook to load Stache templates using ES6 import statements and include the compiled templates into the minified result of the build.</p> <p>Steal-stache returns a renderer function that will render the template into a document fragment.</p> <pre><code class="language-javascript">import todosStache from &quot;todos.stache&quot; todosStache([{name: &quot;dishes&quot;}]) //-&gt; &lt;documentFragment&gt; </code></pre> <p>When the build is run, this import statement will tell StealJS that &quot;todos.stache&quot; is a dependency, and will include it in the minification like any other script dependencies in the application.</p> <h3>In-template dependency declarations<