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

Scalable, Ambitious, Future-friendly web apps with Ember.js

Scalable, Ambitious, Future-friendly web apps with Ember.js

Emberjs is an opinionated web UI framework focused on developer productivity. I will introduce the basics of the framework, and provide several examples of where ember saves an unprecedented amount of time for dev teams. Additionally, I'll cover ember-cli, the extensible build tool that the Emberjs and Angular communities are depending on for code generation, asset compilation, and running tests

Mike North

April 17, 2016
Tweet

More Decks by Mike North

Other Decks in Programming

Transcript

  1. JS UI LIBRARIES 99 2000 01 02 03 04 05

    06 07 08 09 2010 11 12 13 14 15 16 17 2 2 6 7 8 9 10 11 12 ES3 ES5 @MichaelLNorth
  2. NOW IMAGINE… • All the micro-libraries • All the build

    tools • All the pre-processors and post-processors • All of the permutations with typescript, babel, etc…
  3. 2

  4. THE EMBER ECOSYSTEM ember-cli Code Generation Asset Pipeline Plugins Extensible

    CLI Test Runner ember.js SPA routing Components Templating Data Binding Prioritized Work Queue ember-data Request Construction JSON Serialization Redux-like Data Flow Async Relationships liquid-fire animations ember-collection virtualized list
  5. THE EMBER ECOSYSTEM • Built on strong conventions & opinions

    • Focus on developer productivity • Aligned with web standards • Abstractions hold up w/ large scale & complexity • Constantly improving
  6. TEMPLATING • Handlebars • Declarative markup, an extension of HTML

    • Compiled at build time • Extensible Hello, <strong> {{firstName}} {{lastName}} </strong>!
  7. define('examples/templates/index', ['exports'], function (exports) { 'use strict'; exports['default'] = Ember.HTMLBars.template((function()

    { return { ... buildFragment: function buildFragment(dom) { var el0 = dom.createDocumentFragment(); var el1 = dom.createTextNode("Hello, "); dom.appendChild(el0, el1); var el1 = dom.createElement("strong"); var el2 = dom.createComment(""); dom.appendChild(el1, el2); var el2 = dom.createTextNode(" "); dom.appendChild(el1, el2); var el2 = dom.createComment(""); dom.appendChild(el1, el2); dom.appendChild(el0, el1); var el1 = dom.createTextNode("!"); dom.appendChild(el0, el1); return el0; }, buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { var element0 = dom.childAt(fragment, [1]); var morphs = new Array(2); morphs[0] = dom.createMorphAt(element0,0,0); morphs[1] = dom.createMorphAt(element0,2,2); return morphs; }, statements: [ ["content","firstName",["loc",[null,[1,15],[1,28]]]], ["content","lastName",["loc",[null,[1,29],[1,41]]]] ], ... }; }())); });
  8. TEMPLATING • Helpers • Block vs inline form • Easy

    to read and reason about My pet goes {{#if isDog}} arf {{else}} meow {{/if}} My pet goes {{if isDog "arf" "meow"}}
  9. My pet goes {{if isDog "arf" "meow"}} function ifHelper(condition, ifTrue,

    ifFalse) { return condition ? ifTrue : ifFalse } {{#if isEnabled}} <b>Switch is enabled</b> {{/if}} function ifHelper(condition, callbackIfTrue) { return condition ? callbackIfTrue() : ''; }
  10. ROUTING • Router - Finite State Machine • Routes -

    Manage transitions between states • URLs drive your app this is a core pillar of Ember
  11. ROUTING ember routing URL changes components templates HTML++ ember-data store

    adapter makes requests serializer transforms JSON Talks to API
  12. application post application posts post author comments index index index

    index index {{outlet}} /post/31/comments/ URL:
  13. application post application posts post author comments index index index

    index index post/comments post/comments/index /post/31/comments/ URL:
  14. …AND THIS IS A GOOD THING WEB UI LIBS ARE

    JUST A GIANT SERIES OF HACKS
  15. <my-widget title='Enter your Info'> <my-field name='Username'/> <my-field name='Password'/> </my-widget> {{#my-widget

    title='Enter your Info’}} {{my-field name=‘Username’}} {{my-field name=‘Password’}} {{/my-widget}}
  16. init on instantiation willInsertElement before the component’s element is inserted

    into the DOM didInsertElement after the component’s element has been inserted into the DOM willDestroyElement before the component’s element is removed from the DOM $(document).ready() for components Clean up before tear down EMBER.COMPONENT
  17. EMBER-DATA • Unidirectional data flow, single atom of state •

    Can talk to any API • Moves data massaging out of your business logic • Built around fetch (important for SS rendering!) • Saves tons of time if your API uses consistent conventions
  18. EMBER-DATA: MODEL • Representation of any (usually persistent) data •

    Defined by attributes, and relationships to other models • “model” is the factory that defines the structure of “records” // app/models/book.js import DS from 'ember-data'; const { attr, hasMany } = DS; export default DS.Model.extend({ title: attr('string'), publishedAt: attr('date'), chapters: hasMany('chapter') });
  19. EMBER-DATA: STORE • Where you get/create/destroy records • A single

    source of truth • This means that all changes are kept in sync! • Similar concept in Facebook/flux, angular-data
  20. EMBER-DATA: STORE // (maybe) API request for all records of

    type "author" this.store.findAll('author'); // (maybe) API request for record of type "post" with id 37 this.store.findRecord('post', 37); // API request for all records of type "author" this.store.fetchAll('author'); // API request for record of type "post" with id 37 this.store.fetchRecord('post', 37); // look in cache for all records of type "author" this.store.peekAll('author'); // look in cache for record of type "post" with id 37 this.store.peekRecord('post', 37);
  21. EMBER-DATA: ADAPTER export default DS.RESTAdapter.extend({ host: 'https://api.github.com', urlForQuery (query, modelName)

    { switch(modelName) { case 'repo': return `${this.get('host')}/orgs/${query.orgId}/repos`; default: return this._super(...arguments); } } });
  22. EMBER-DATA: SERIALIZER export default DS.RESTSerializer.extend({ normalizeResponse(store, modelClass, payload, id, requestType){

    const newPayload = { org: payload }; return this._super(store, modelClass, newPayload, id, requestType); } });