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

Modern Ember

Modern Ember

An update on the current state and future of Ember. Presented at the Ember Israel Meetup.

Note: Large portions of this deck were borrowed (with permission from Tom Dale) from the EmberConf 2018 keynote.

Dan Gebhardt

August 27, 2018
Tweet

More Decks by Dan Gebhardt

Other Decks in Programming

Transcript

  1. All features shown today are available in stable, beta, or

    canary releases. Some are behind a feature flag and subject to change. modern ember * *
  2. import Component from '@ember/component'; import { computed } from '@ember/object';

    export default class extends Component { fullName: computed(/* … */) }
  3. class Person { constructor(firstName, lastName) { this.firstName = firstName; this.lastName

    = lastName; } sayHello() { console.log(`${this.firstName} ${this.lastName}`); } }
  4. export default class extends Component { @service currentUser; constructor(...args) {

    super(...args); this.set('title', 'Default Title'); console.log('constructing!'); } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  5. export default class extends Component { @service currentUser; constructor(...args) {

    super(...args); this.set('title', 'Default Title'); console.log('constructing!'); } update(title) { this.set('title', title); } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  6. export default class extends Component { @service currentUser; title =

    'Default Title'; update(title) { this.set('title', title); } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  7. TYPESCRIPT export default class extends Component { @service currentUser: User;

    title = 'Default Title'; tabs: Tab[]; constructor(...args) { super(...args); console.log('constructing!'); } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  8. import { module, test } from 'qunit'; import { setupTest

    } from 'ember-qunit'; module('Unit | Service | location', function(hooks) { setupTest(hooks); // Replace this with your real tests. test('it exists', function(assert) { let service = this.owner.lookup('service:location'); assert.ok(service); }); }); EXAMPLE UNIT TEST BLUEPRINT
  9. import { module, test } from 'qunit'; import { setupApplicationTest

    } from 'ember-qunit'; import { visit, fillIn, click } from '@ember/test-helpers'; module('Acceptance | posts', function(hooks) { setupApplicationTest(hooks); test('should add new post', async function(assert) { await visit('/posts/new'); await fillIn('input.title', 'My new post'); await click('button.submit'); const title = this.element.querySelector('ul.posts li:first').textContent; assert.equal(title, 'My new post'); }); }); EXAMPLE ACCEPTANCE TEST
  10. Step 1. $ npm install --save axios Step 2. import

    axios from 'axios'; Step 3. There is no step 3.
  11. import Component from '@ember/component'; export default Component.extend({ didInsertElement() { let

    iframe = this.element.querySelector('iframe'); let message = { name: 'didInsertElement' }; iframe.contentWindow.postMessage(message, '*'); } });
  12. Glimmer 2.5s 4.1s Glimmer (no SSR) 4.0s 4.0s First Meaningful

    Paint Fully Interactive 90th percentile, lower numbers are better
  13. export default class extends Component { @service currentUser; title =

    'Default Title'; update(title) { this.set('title', title); } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  14. export default class extends Component { @service currentUser; @tracked title

    = 'Default Title'; update(title) { this.title = title; } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  15. export default class extends Component { @service currentUser; @tracked title

    = 'Default Title'; update(title) { this.title = title; } didInsertElement() { tab(this.element); } @computed get tabCount() { return this.tabs.length; } }
  16. export default class extends Component { @service currentUser; @tracked title

    = 'Default Title'; update(title) { this.title = title; } didInsertElement() { tab(this.element); } @tracked get tabCount() { return this.tabs.length; } } // TBD: tracked vs. computed
  17. {{#each options as |option|}} {{radio-button action="select" option=option selected=selected}} {{/each}} {{#each

    options as |option|}} <RadioButton @action="select" @option={{option}} @selected={{selected}} /> {{/each}}
  18. {{#each options as |option|}} {{radio-button action="select" option=option selected=selected}} {{/each}} {{#each

    options as |option|}} <Radio @action="select" @option={{option}} @selected={{selected}} /> {{/each}}
  19. <Dialog @title="Are you sure?" @isOpen={{true}}> You have unsaved changes. Do

    you want to leave? </Dialog> {{#if @isOpen}} <div class="dialog"> <h3>{{@title}}</h3> <div>{{yield}}</div> </div> {{/if}}
  20. <Dialog @title="Are you sure?" @isOpen={{true}}> You have unsaved changes. Do

    you want to leave? </Dialog> {{#if @isOpen}} <div class="dialog"> <h3>{{@title}}</h3> <div>{{yield}}</div> </div> {{/if}}
  21. +