Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ember: How the Concepts Scale Up

Ember: How the Concepts Scale Up

428167a3ec72235ba971162924492609?s=128

Yehuda Katz

February 18, 2014
Tweet

Transcript

  1. HOW THE CONCEPTS SCALE UP

  2. HOW THE CONCEPTS SCALE UP

  3. None
  4. None
  5. None
  6. Routing

  7. None
  8. None
  9. None
  10. None
  11. None
  12. None
  13. None
  14. None
  15. The Basics

  16. The Basics App.Router.map(function()  {
    this.resource('app',  {  path:  ':app_id'  });


    });
  17. application.handlebars loading.handlebars http://skylight.io/app/direwolf

  18. application.handlebars app.handlebars http://skylight.io/app/direwolf appkit/routes/app.js   export  default  Ember.Route.extend({
    model:

     function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });
  19. application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

  20. application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars fetch model...

  21. application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

  22. application.handlebars index.handlebars application.handlebars loading.handlebars application.handlebars app.handlebars

  23. Ember Routing • Coming in from the URL should have

    the same code path as navigating around the application after the model is loaded.
  24. Nested App.Router.map(function()  {
    this.resource('app',  {  path:  ':app_id'  },  function()

     {
        this.resource('endpoint',  {  path:  ':endpoint_id'  );
    });
 });
  25. application.handlebars app.handlebars http://skylight.io/app/direwolf appkit/routes/app.js   export  default  Ember.Route.extend({
    model:

     function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/app/index.js   export  default  Ember.Route.extend({
    model:  function()  {
        return  this.modelFor('app')
            .get('endpoints');
  }
 }); app/index.handlebars 
 !  {{#each}}
      {{link-­‐to  title  this}}
  {{/each}}
  26. application.handlebars app.handlebars http://skylight.io/app/direwolf/Agent%23status appkit/routes/app.js   export  default  Ember.Route.extend({
    model:

     function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/endpoint.js   export  default  Ember.Route.extend({
    model:  function(params)  {
      return  this.store.find('app',
            params.endpoint_id);
 }
 }); endpoint.handlebars
  27. application.handlebars app.handlebars http://skylight.io/app/direwolf/Agent%23status appkit/routes/app.js   export  default  Ember.Route.extend({
    model:

     function(params)  {
        return  this.store.find('app',
            params.app_id);
    }
 });   appkit/routes/endpoint.js   export  default  Ember.Route.extend({
    model:  function(params)  {
      return  this.store.find('app',
            params.endpoint_id);
 }
 }); endpoint.handlebars nav.handlebars
  28. Ember Routing • Coming in from the URL should have

    the same code path as navigating around the application after the model is loaded. • There is a single, consistent place to put setup and teardown logic for each page on the screen. • Nesting is built-in. Virtually every application has nesting, and your Week 1 code should serve you well in Week 2.
  29. The Setup Flow

  30. Setup Flow export  default  Ember.Route.extend({      renderTemplate:  function()  {

             this.render('nav',  {  outlet:  'nav'  });      },   !    redirect:  function()  {          var  user  =  this.modelFor('application'),                  apps  =  user.get('apps');   !        if  (!apps  ||  apps.get('length')  <  1)  {              this.replaceWith('setup');          }      }
 });
  31. Ember Routing • Coming in from the URL should have

    the same code path as navigating around the application after the model is loaded. • There is a single, consistent place to put setup and teardown logic for each page on the screen. Think keyboard shortcuts. • Nesting is built-in. Virtually every application has nesting, and your Week 1 code should serve you well in Week 2.
  32. Components

  33. Components ~ HTML Functions {{time-­‐explorer  rightMargin=152
        

                           brushExtent=dateRange
                                      endpoint=model
                                  timeRanges=timeRanges    
                    selectedTimeRange=selectedTimeRange}}  
  34. Component Implementation <svg>      <defs>        

     <pattern  id="explorer-­‐grabber-­‐pattern"  width="1"  height="1">              <rect  class="border"  width="11"  height="22"></rect><rect  class="background"  x="1"  y="1"  width="9"  height="20"  rx="2"  ry="2"></rect>
            <rect  class="line"  x="3"  y="3"  width="1"  height="16"></rect><rect  class="line"  x="5"  y="3"  width="1"  height="16"></rect>
            <rect  class="line"  x="7"  y="3"  width="1"  height="16"></rect>          </pattern>          <linearGradient  id="left-­‐fade-­‐gradient"  x1="0"  x2="100%"  y1="0"  y2="0">              <stop  class="start"  offset="0%"></stop><stop  class="end"  offset="100%"></stop>          </linearGradient>          <linearGradient  id="right-­‐fade-­‐gradient"  x1="0"  x2="100%"  y1="0"  y2="0">              <stop  class="start"  offset="0%"></stop><stop  class="end"  offset="100%"></stop>          </linearGradient>          <linearGradient  id="brush-­‐background-­‐gradient"  x1="0"  x2="100%"  y1="0"  y2="0">              <stop  class="start"  offset="85%"></stop><stop  class="end"  offset="100%"></stop>          </linearGradient>      </defs>   </svg>   ! <div  class="controls">      <a  class="control  zoom-­‐in"  {{bind-­‐attr  class="canZoomIn:active"}}  title="Zoom  in">+</a>      <a  class="control  zoom-­‐out"  {{bind-­‐attr  class="canZoomOut:active"}}  title="Zoom  out">-­‐</a>      {{select-­‐popup  options=timeRanges  class="control"  value=selectedTimeRange}}   </div>
  35. Component Implementation

  36. Isolation Manages Complexity

  37. Well-Defined Boundaries

  38. Components

  39. None
  40. Empty Help us keep the lights on. Enter your credit

    card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card Card Number MM / YY CVC Save Credit Card We stole this graphic from GitHub for the wireframes; don't use in production! Credit Card Invalid This red glow is a placeholder until the final design is completed in Photoshop. Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 9999 9999 9999 9999 06 / 09 123 Save Credit Card The credit card you entered was invalid. When we can detect invalid information on the client (such as the Luhn checksum or expiry dates in the past), we should highlight the invalid field and display the error to the right of the Save button. Incomplete The Save button is dimmed until the entire form is filled out. Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card MM / YY CVC Save Credit Card 4242 4242 4242 4242 Only one error should be displayed at a time. If there is more than one error, just show the first. {{billing-credit-card-form}} Component States Saved Clicking transitions to the Update Credit Card state. Update Thank you for being a Skylight customer. Credit Card Card Number MM / YY CVC Update Credit Card Cancel 4••• •••• •••• 4242 Expires 04/15 Update Credit Card Thank you for being a Skylight customer. Credit Card Saving Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 4242 4242 4242 4242 06 / 17 123 Saving… Error Saving Help us keep the lights on. Enter your credit card information below, and we'll continue helping you make your Rails app the fastest it can be. Credit Card 9999 9999 9999 9999 06 / 09 123 Save Credit Card The CVC you provided was incorrect. Because the server must validate any changes, the red glow should be removed and Save button enabled as soon as any changes to the field occur.
  41. Feature Flags

  42. Feature Flag Template {{#if  featureEnabled}}{{yield}}{{/if}}

  43. Feature Flag JS export  default  Ember.Component.extend({      flag:  null,

         inverse:  false,   !    init:  function()  {          this._super();          var  flag  =  this.get('flag');   !        Ember.defineProperty(this,  'featureEnabled',  Ember.computed(function()  {              var  value  =  this.get('config.flags.'+flag);              if  (this.get('inverse'))  {  value  =  !value;  }              return  value;          }).property('config.flags.'+flag,  'inverse'));      }   });
  44. Injections

  45. config/initializers/config.js.es6 /*      This  initializer  injections  global  configuration  options

     onto  object  instances,  so  they  do  not
    need  to  rely  on  accessing  globals.   !    Currently  all  of  the  config  options  are  defined  in  config/environment.js,  but  this  may  change  over  time.   !    To  access  a  config  option  on,  e.g.,  a  model,  do:   !        this.config.flags.keyRequests;  //=>  false          this.config.defaultRanges  =  [  {  },  {  },  ...  ];   */   export  default  {      name:  "config",      initialize:  function(container,  application)  {          container.register('config:main',  Ember.Object.extend(CONF));   !        ['model',  'view',  'controller',  'route',  'component'].forEach(function(type)  {              container.injection(type,  'config',  'config:main');          });      }   };
  46. environment.js var  FEATURE_FLAGS  =  {      keyRequests:  false,  

       appDashboard:  false   };   ! window.CONF  =  {    zeroClipboard:  {          moviePath:  "/assets/zeroclipboard/ZeroClipboard.swf",          trustedDomains:  ['*'],          allowScriptAccess:  "always"      },      trialDays:  30,      flags:  FEATURE_FLAGS,      defaultTimeRanges:  [          {  name:  'Last  6  hours',  timestamp:  'recent',  duration:  21600  },          {  name:  'Last  30  minutes',  timestamp:  'recent',  duration:  1800  },          {  name:  'Last  5  minutes',  timestamp:  'recent',  duration:  300  }      ]   };
  47. ES6 Modules

  48. ES6 Module import  $  from  'jquery';
 import  {  config  }

     from  'app/config';
 
 var  viewA  =  Ember.Object.extend({
    //  ...
 });
 
 var  viewB  =  Ember.Object.extend({
    //  ...
 });
 
 export  viewA;
 export  viewB; define(['jquery',  'app/config',  'exports'],
    function($,  appConfig,  exports)  {
        var  config  =  appConfig.config;
 
        var  viewA  =  Ember.Object.extend({
            //  ...
        });
 
        var  viewB  =  Ember.Object.extend({
            //  ...
        });
 
        exports.viewA  =  viewA;
        exports.viewB  =  viewB;
    }); AMD Module
  49. Improvements • Cyclic Dependencies • Named and Default exports together

    (including cycles!) • Much, much prettier syntax, with familiar semantics • Why not?
  50. ES6 Module Transpiler • Maintained by Square • Supports almost

    all of ES6 modules • Emits AMD-, Node- or Globals-based output • Compatibility with existing AMD and Node modules (including default exports) • Ships out of the box with Ember App Kit
  51. Ember's Concepts Grow With You

  52. Ember's Concepts Grow With Your App

  53. Week 1 ➡️ Week 2 ➡️ Week 50

  54. SCALABLE CONCEPTS FOR AMBITIOUS WEB APPS

  55. Thank You! @wycats plus.google.com/+YehudaKatz yehudakatz.com @tomdale plus.google.com/+TomDale tomdale.com