5 Years!

<html>
  <head>
    <script src="/public/ember.js"></script>
  </head>
  <body>
    <script type="text/x-handlebars">
      Hello, <strong>{{firstName}} {{lastName}}</strong>!
    </script>

    <script type="text/x-handlebars" data-template-name="say-hello">
      <div class="my-cool-control">{{name}}</div>
    </script>

    <script>
      App.ApplicationController = Ember.Controller.extend({
        firstName: "Trek",
        lastName: "Glowacki"
      });
    </script>
  </body>
</html>
<div id="logo">
  <img {{bind-attr src=logoUrl}} alt="Logo">
</div>

2013

2014

Quoted string fixes 😱

IE6-7 Fixes / Deprecation

ES6 Module Adoption

Promises in testsΒ 

Query Params / Nest this.route

The Road to 2.0 RFC

Ember.computed.readonly
Router.extend({ location: 'auto' })
{{log "hello world"}}
{{#each items as |item|}}

Metamorph

2015

Inside FastBoot

HTMLBars

Glimmer

Ember 2.0

bindAttr

ObjectController / ArrayController

RFC Process

"The Ember Project"

<div class=(if isAdmin "Admin")>
{{#each items as |item i|}}
{{component dynamic}}

2016

Ember's First LTS Release

Component Composition

Introducing Zoey

Glimmer 2 Alpha -> Beta -> Release!

WeakMaps

App.visit("/demo").then(...);
{{#alert-box as |box|}}
  {{#box.close}}...{{/box.close}}
{{/alert-box}}
{{render}}

2017

The Web in May 2011

Complete ES 5.0 NONE

Flexbox NONE

Typed Arrays Β 31%

WebSockets NONE

IndexedDB 31%

QuerySelectorAll 49%

addEventListener 49%

CSS2 (:hover [attr]) 95% (not IE6)

CSS3 (:nth-child, :not) 51%

Web Workers 49%

keyEvent.which 63%

The Web, Today

Complete ES 6 ALL

Flexbox ALL

Typed Arrays Β ALL

WebSockets ALL

IndexedDB ALL

QuerySelectorAll ALL

addEventListener ALL

CSS3 (:nth-child, :not) ALL

Web Workers ALL

@font-face ALL

Service Worker

WebAssembly

Page Visibility ALL

Media Queries ALL

Border Radius / Box Shadow ALL

5 Years is Forever

in Web Time

Ember Innovations Over the Years

  • Ahead of Time template compilation

  • Ember CLI

  • RFCs and the 6 Week Release Cycle

  • Adopting ES6 Modules and Promises

  • HTMLBars

  • Glimmer

  • FastBoot

  • Glimmer 2

  • Engines

Ahead of the Curve

5 Years!

A lot of our cool ideas are now standard

Another 5 Years?

  • Routable Components

  • Deprecating Controllers

  • <angle-bracket> Components

  • Pods

  • Breakage in 2.0

What Didn't Work

What Worked?

MARCH

JULY

NOVEMBER

ES2015 Modules

Ember 2.x

What Have We Learned?

Big Up Front Design

Small Kernel

+
​Addon

Drop-In

(Compatibility)

Experimentation is πŸ”‘

ember-redux
ember-concurrency
​ember-orbit

liquid-fire
smoke-and-mirrors

😎

Active Work

<angle-brackets>

"Module Unification"

RFC Merged

Implementation Begun

Glimmer 2

Less Modular Than We Thought

?

Ember

HTMLBars

Extract and Rationalize

Ember

View Layer

Glimmer

2.10 is a Drop-In Replacement for 2.9

Ember View Layer

Glimmer

Ember

?

Glimmer

Ember 2.9

Ember 2.10

Tests Run on Both at the Same Time

(Thanks Everyone for the Help!)

This is how we do it.

Glimmer VM

Real-Time

First Interactivity

Response to Interaction

  • "60 fps"
  • "Jank"
  • "Main thread stall"
  • "Time to first paint"
  • "Time to first interactivity"
  • "Boot time"

Normal real-time systems trade bootup time for lower latency once booted.

Β 

The old "memory vs. speed" debate was resolved in favor of speed long ago.

The Web's Problem

Boot Up Fast and

Stay Fast Once

Booted

You can go the fastest if you don't care about updating.

How can we have our cake and eat it too?

Working on Glimmer forced the issue.

Ember was already very fast at updates, and we couldn't afford update regressions.

Last year...

promises of architectural benefits

Some benefits already landed in Ember...

Wins

Size & Speed

Compatible!

Wins

Architecture

<div><span>{{hello world}}</span></div>
[
  [11, 'div'], [11, 'span'],
  [1, [33, ['hello'], [[28, 'world']]
  [14], [14]
]
1:  append
11: open-element
14: close-element
28: lookup
33: helper

Wire Format

Goals

  • Do as much work ahead of Β time as possible.
  • Not Executable JavaScript.
  • Reduce in-browser work and improve compactness over time.
  • Take advantage of the declarative nature of the template syntax.

Wins

Architecture

<div><span>{{hello world}}</span></div>

Static Content

.helper hello

​open "div"
open "span"
lookup "world"   ; look up this.world and push onto the stack
calljs hello, 1  ; call the hello helper with one argument
close
close

Append Pass

revalidate 0   ; if `world` changed, recompute `hello world` and update the text node

Update Pass

Template

Wire Format

[[11,'div'],[11,'span'],[1,[33,['hello'],[[28,'world']],[14],[14]]

A Word on Benchmarks

Microbenchmark, Initial Render

Microbenchmark, Update

More Realistic Content, Initial Render

More Realistic Content, Update

Sweet Spot of Initial Render and Updating Performance

Wins

Architecture

<title-bar @name={{hello world}} title="hello" />

Components

.component title-bar
.block default
.block inverse
.layout dynamic

​init-state
fetch s0
dup s0, 1
load s0
pushblk block
pushblk inverse
lookup "world"
calljs hello, 1
begin
pushdynscope

Append Pass

Template

Wire Format

[[5,"title-bar",[9,"title","hello"],[["name"],[[33,["hello"],[[28,"world"]]]]]]]
5:  component
9:  static-attr
28: lookup
33: helper
createcomp s0, 0, 0
compdrop s0
compself s0
complayout s0
vcall dynamic
retframe
popscope
popdynscope
commit
load s0

Wins

Architecture

<title-bar @name={{hello world}} title="hello" />

Lighter Components

.component title-bar
.block layout

​init-state
fetch s0
dup s0, 1
load s0
pushblk block
pushblk inverse
lookup "world"
calljs hello, 1
begin
pushdynscope

Append Pass

Template

Wire Format

[[5,"title-bar",[9,"title","hello"],[["name"],[[33,["hello"],[[28,"world"]]]]]]]
createcomp s0, 0, 0
compdrop s0
compself s0
complayout s0
vcall dynamiccall layout
retframe
popscope
popdynscope
commit
load s0

Wins

Architecture

<title-bar @name={{hello world}} title="hello" />

Append Pass

Template

Wire Format

[[5,"title-bar",[9,"title","hello"],[["name"],[[33,["hello"],[[28,"world"]]]]]]]
.component title-bar
.block layout

​init-state
fetch s0
dup s0, 1
load s0
lookup "world"
calljs hello, 1
begin
complayout s0
call layout
retframe
popscope
commit
load s0

Lighter Components

Steve Jobs' "Hierarchy of Skepticism"

1

Build tooling

2

No documentation

3

bindAttr / metamorph

4

custom class system

Ember Community Survey

Ember cannot easily integrate with the rest of the commonjs/es module ecosystem.

Monolithic build: if you use Ember, you must import and ship all of Ember to your users

Ember.Object and custom class system instead of "plain" JS classes and APIs

I think Ember is too opinionated, too rigid, and tries to do too much. For example, to create reactive properties you have to use Ember.Object

Size and speed are also very bad categories for Ember compared to other frameworks

build process (tree shaking)

There are too many abstractions and new people in project with pure JS experience are mostly confused

Ember Community Survey

For large, ambitious, web applications, I can't imagine using anything else. Ember's strong conventions help me avoid having to make so many decisions I used to have to make with other frameworks.

Β 

I'm subtracting one point because I've tried to coach several novice JS developers along in Ember, and they have all gotten frustrated with the steep learning curve. It seems that Ember is still too tough for inexperienced programmers.

Β 

I'm subtracting another point because it is still impossible to write Ember apps using Typescript. My development workflow is significantly hampered by not having the refactoring and design-time validation tools afforded by TS.

Introducing Glimmer.

import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'input',
  attributeBindings: ['disabled', 'type:kind'],
  disabled: false,
  kind: 'range'
});
<input disabled type="slider" />
import Ember from 'ember';

export default Ember.Component.extend({
  tagName: 'input',
  attributeBindings: ['disabled', 'type:kind'],
  disabled: false,
  kind: 'range',
  classNameBindings: 'type',
  type: 'primary'
});
<input disabled type="slider" class={{type}} />
import Component from '@glimmer/component';

export default class extends Component {
  type = "primary"; 
}
import Component from "@glimmer/component";

export default class extends Component {
  firstName: string;
  lastName: string;
}

TypeScript

import Component from "@glimmer/component";

export default class extends Component {
  firstName: string;
  lastName: string;
}

TypeScript

import Component from "@glimmer/component";

export default class extends Component {
  firstName: string;
  lastName: string;

  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

"Computed Properties"

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  @tracked firstName;
  @tracked lastName;

  @tracked('firstName', 'lastName')
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

Decorators

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  @tracked firstName: string;
  @tracked lastName: string;

  @tracked('firstName', 'lastName')
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

@tracked + TypeScript

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  @tracked name: string;

  setName(name: string) {
    this.name = name;
  }
}

"Just JS" Actions

<button onclick={{action setFirstName "Zahra"}}>
  Change
</button>

Component JS

Template

import Component, { tracked } from "@glimmer/component";

export default class extends Component {
  @tracked firstName: string;
  @tracked lastName: string;

  @tracked('firstName', 'lastName')
  get fullName() {
    return `${this.firstName} ${this.lastName}`
  }
}

No .get or .set

29kb

Back to Ember

This is the Component API we want for Ember.

(see Godfrey's RFC #213)

Improved Directory Structure

("Module Unification")

TypeScript

@glimmer/application
ember
@ember/router
@ember/data
...

+

+

+

=

npm install your way to ember

EmberConf 2017

By Yehuda Katz

EmberConf 2017

  • 279
Loading comments...

More from Yehuda Katz