The Journey through Ember.js Glue
January 27, 2017
Michael North
SO Ember Conf
https://mike.works
Addepar
Apple
Buffer
Checkmate
Dollar Shave
Club
Ericsson
Facebook
Freshbooks
Github
Google
Heroku
Intercom
Iora Health
LinkedIn
Microsoft
Netflix
Pagerduty
Pivotshare
Practice Fusion
Thoughtbot
Ticketfly
Travis-CI
Tumblr
Twitch
Yahoo
Zenefits
Teaching developers at…
and learning from
Library
vs
Framework
A Quilt of Libraries
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
A Quilt of Libraries
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
fetch
A Quilt of Libraries
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
fetch
A Quilt of Libraries
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
fetch
A Framework
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
A Framework
Written For You
You Write
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
INITIALIZERS ROUTES
STORE EM.COMPONENT TEMPLATES
ADAPTERS
The Glue
Initializing App Routing Loading Data
Managing App
State
Defining
Components
Rendering
The Glue
➡ 📞 Hooks - A construct of opinionated frameworks
➡ 👷 Productivity - Through reducing # of decisions
➡ Additionally, through mastering tools
➡ 🤝 Idioms - Using local expressions to fit naturally
➡ Knowing the local ways is the path to fitting in
The Glue
APP INITIALIZATION
ASKING THE STORE FOR DATA
⚠ Private API Warning
The following content will include gratuitous use of private
APIs. This does not mean you should build apps on them.
This journey should only serve to enhance your understanding
of framework internals, in an effort to align your thinking with
the “natural ideas” of the underlying foundation.
Booting Up
Ember.Application
Booting Up
Ember.Application!#_bootSync
domReady
{
}
Booting Up
Ember.Application!#_bootSync
domReady
}
this.runInitializers();
{
Initializers
➡ 🍱 Modular boot process
Initializers
import Lemon from 'fruits/lemon';
export function initialize(app) {
app.register('fruits:lemon', Lemon);
}
export default {
name: 'my-initializer',
after: 'other-initializer',
initialize
};
Initializers
➡ 🍱 Modular boot process
➡ 🕐 Happens WHILE Application boots
➡ ⌛ deferReadiness, advanceReadiness
➡ 💡Think: Registry, not Container
Booting UpdomReady
{
this.advanceReadiness();
Ember.Application!#_bootSync
}
this.runInitializers();
Booting UpdomReady
{
}
this.didBecomeReady();
{
this.advanceReadiness()
Ember.Application!#_bootSync
}
this.runInitializers();
Booting Up
Ember.Application#didBecomeReady
Ember.Application!#_bootSync
{
}
if (this.autoboot) {
!// Instantiate a Ember.ApplicationInstance
let instance = this.buildInstance();
instance._bootSync();
instance.startRouting();
}
{Ember.Application#didBecomeReady
}
Ember.Application!#_bootSync Booting Up
{Ember.ApplicationInstance!#_bootSync
}
this.setupRegistry();
!// define root element
!// define location
this.runInstanceInitializers();
if (isInteractive) {
this.setupEventDispatcher();
}
Ember.Application#didBecomeReady
Ember.Application!#_bootSync Booting Up
Instance Initializers
➡ 🍱 Modular boot process
➡ 🕐 Happens AFTER ApplicationInstance boots
➡ ♻ Re-runs on Fastboot builds
➡ 💡Think: Container, not Registry
{Ember.ApplicationInstance!#_bootSync
}
this.setupRegistry();
!// define root element
!// define location
this.runInstanceInitializers();
if (isInteractive) {
this.setupEventDispatcher();
}
Ember.Application#didBecomeReady
Ember.Application!#_bootSync Booting Up
if (this.autoboot) {
!// Instantiate a Ember.ApplicationInstance
let instance = this.buildInstance();
instance._bootSync();
instance.startRouting();
}
{Ember.Application#didBecomeReady
}
Ember.Application!#_bootSync Booting Up
Ember.ApplicationInstance#startRouting
}
let initialURL = location.getURL();
let initialTransition = this.handleURL(initialURL);
Ember.Router#startRouting {
Ember.Application#didBecomeReady
Ember.Application!#_bootSync
Booting Up
vs
Application
ApplicationInstance
vs
Initializer
InstanceInitializer
Debugging: Initializers
Debugging: Initializers
Debugging: Instance Initializers
Debugging: Registry
Debugging: Registry
Debugging: Registry
Debugging: Container
Debugging: Container
Debugging: Container
Asking the Store for Data
export default Ember.Route.extend({
model() {
return this.store.findAll('course');
}
});
Asking the Store for Data
DS.Store!#_fetchAll
DS.Store#findAll
Asking the Store for Data
DS.Store#findAll
DS.Store!#_fetchAll(modelClass, array, options)
STRING ARRAY OBJECT
Asking the Store for Data
STRING ARRAY OBJECT
DS.Store#findAll
DS.Store!#_fetchAll(“course", [], {} )
Asking the Store for Data
DS.Store#findAll
Options
{
reload: true, !// New request from scratch
backgroundReload: true !// Cached data now, then refresh
}
DS.Store!#_fetchAll(“course", [], {} )
Asking the Store for Data
reload backgroundReload
🚫 ✅
✅ ✅
🚫 🚫
✅ 🚫
Cached data new, updated live w/ new stuff
No point
Cached data only (peek)
Fetch fresh data only
Asking the Store for Data
DS.Store#findAll
DS.Store!#_fetchAll(modelClass, array, options)DS.Store!#_fetchAll("course", this.peekAll("course"), {})
Asking the Store for Data
DS.Store!#_fetchAll
DS.Store#findAll
{
let adapter = this.adapterFor('course');
if (options.reload !|| adapter.shouldReloadAll(array)) {
return this._findAll();
}
if (!options.backgroundReload) {
return array;
}
}
DS.Store!#_fetchAll
DS.Store#findAll
{DS.Store!#_findAll
let promise = adapter.findAll();
let serializer =
adapter.serializer !||
store.serializerFor('course');
return promise.then((adapterPayload) !=> {
return serializer.normalizeResponse(adapterPayload);
});
Asking the
Store for Data
}
DS.Store!#_fetchAll
DS.Store#findAll
{DS.Store!#_findAll
Asking the
Store for Data
DS.RESTAdapter#findAll {
let url = this.buildURL();
return this.ajax(url, 'GET', { data: query });
}
DS.Store!#_fetchAll
DS.Store#findAll
{DS.Store!#_findAll
let promise = adapter.findAll();
let serializer =
adapter.serializer !||
store.serializerFor('course');
return promise.then((adapterPayload) !=> {
let payload = serializer.normalizeResponse(adapterPayl
store.push(payload);
});
Asking the
Store for Data
}
Debugging Adapters
Debugging Adapters
Debugging Adapters
Debugging Serializers
Just because ember does a lot for you…
Challenge: One adventure/week
Thanks!

A Debugging Adventure: Journey through Ember.js Glue