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

EmberFest 2017 - Ember @ Netflix

Lauren Tan
February 24, 2018

EmberFest 2017 - Ember @ Netflix

This talk was presented at EmberFest 2017
by Lauren Tan and Offir Golan. Recording available here -
https://pusher.com/sessions/meetup/emberfest/ember-netflix

For a few years now, Netflix has been leveraging Ember to build ambitious applications that help us manage and produce billions of dollars in content. In this talk, we'll share our lessons learned, talk about some of the common problems we've faced, and how we've solved them.

Lauren Tan

February 24, 2018
Tweet

More Decks by Lauren Tan

Other Decks in Programming

Transcript

  1. ember-cp-validations ember-light-table ember-burger-menu ember-time-machine ember-parachute ember-data-copyable ember-require-module ember-validators ember-cli-nvd3 ember-addon-genie

    ember-bootstrap-cp-validations ember-cli-inject-meta ember-changeset-cp-validations ember-cli-jsoneditor ember-host-manager ember-query-builder
  2. ember-changeset ember-lazy-video ember-pipeline ember-composable-helpers ember-parachute ember-metrics ember-one-way-controls ember-crumbly ember-deep-set ember-in-viewport

    ember-test-component ember-cli-flash ember-changeset-validations ember-api-feature-flags ember-route-action-helper ember-macaroni
  3. Studio Apps Wrap Pitch Negotiation Production Prep Post Origin Story

    Watson Budget Gravity Murdock Jet Moneyball Amadeus Orion Sherlock
  4. Authentication ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓

    Data Loading ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ Shared Data Models ✓ ✓ ✓ ✓ ✓ ✓ ✓ Data Tables ✓ ✓ ✓ ✓ ✓ ✓ ✓ Data Entry ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ Deployment ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓ ✓
  5. export default Service.extend(Evented, { /** * Handle an unauthorized response.

    Invoke this method if you are making a * non ember-data request that receives a 401. * * @method handleUnauthorizedResponse * @public */ handleUnauthorizedResponse() { run.cancel(this._refreshTokenTimer); this.trigger('sessionExpired'); }, // ... });
  6. import Ember from 'ember'; export default Ember.Route.extend({ model({ search })

    { return this.store.queryRecord('user', { search }); } });
  7. import Ember from 'ember'; export default Ember.Controller.extend({ queryParams: [ 'buyingTeam',

    'category', 'genre', 'programmingStatus', 'title' ], buyingTeam: null, category: null, genre: null, programmingStatus: null, title: null });
  8. import Ember from 'ember'; export default Ember.Route.extend({ queryParams: { buyingTeam:

    { refreshModel: true }, category: { refreshModel: true }, genre: { refreshModel: true }, programmingStatus: { refreshModel: true }, title: { refreshModel: true } } });
  9. import Ember from 'ember'; const { Mixin } = Ember;

    const { assign } = Object; export default function makeMixin(props = {}) { return Mixin.create(assign({}, props)); } https://ember-twiddle.com/de8c4d4aaf2b2e30f6593b671967c5a6?openFiles=utils.make-mixin.js%2C
  10. import Ember from 'ember'; import makeMixin from '../utils/make-mixin'; const mixinA

    = makeMixin({ value: 'a' }); const mixinB = makeMixin({ value: 'B' }); export default Ember.Controller.extend(mixinB, { appName: 'Ember Twiddle' }); https://ember-twiddle.com/de8c4d4aaf2b2e30f6593b671967c5a6?openFiles=utils.make-mixin.js%2C
  11. import QueryParamsBuilder from './index'; export default class EventQueryParamsBuilder extends QueryParamsBuilder

    { static TypeMap() { return { 'buying_teams': { type: 'array', defaultValue: undefined, refreshModel: true }, 'title': { type: 'string', defaultValue: undefined, refreshModel: true } }; } }
  12. export default Ember.Controller.extend(myQueryParams.Mixin, { queryParamsDidChange({ shouldRefresh, queryParams }) { if

    (shouldRefresh) { this.get('fetchUsers').perform(queryParams.search); } }, fetchUsers: task(function*(search) { yield timeout(500); const res = yield fetch( `https://api.github.com/search/users?q=${search}` ).then(res => res.json()); this.set('users', res.items); }).restartable() });
  13. const EmberApp = require('ember-cli/lib/broccoli/ember-app'); module.exports = function(defaults) { let app

    = new EmberApp(defaults, { 'studio-data-core': { importAll: true } }); return app.toTree(); };
  14. // app/models/series.js import DS from 'ember-data'; const { Model, hasMany,

    belongsTo } = DS; export default Model.extend({ statusType: belongsTo('status-type'), episodes: hasMany('episode') }); // mirage/models/series.js import { Model, belongsTo, hasMany } from 'ember-cli-mirage'; export default Model.extend({ statusType: belongsTo(), episodes: hasMany() }); Ember Data Models → Mirage Models
  15. // Merge models from autogenerated Ember Data models with user

    defined models if (hasEmberData && config.discoverEmberDataModels) { let models = {}; assign(models, getModels(), config.models || {}); config.models = models; } // ... // Register all models schema.registerModels(config.models);
  16. Object.keys(requirejs.entries) .filter(module => !!module.match(modelMatchRegex)) .forEach(path => { let paths =

    path.split('/'); let modelName = paths[paths.length - 1]; let model = require(path, null, null, true).default; if (isDsModel(model)) { DsModels[modelName] = model; } });
  17. Object.keys(requirejs.entries) .filter(module => !!module.match(modelMatchRegex)) .forEach(path => { let paths =

    path.split('/'); let modelName = paths[paths.length - 1]; let model = require(path, null, null, true).default; if (isDsModel(model)) { dsModels[modelName] = model; } });
  18. Object.keys(getDsModels()).forEach(modelName => { let model = models[modelName]; let attrs =

    {}; model.eachRelationship((name, r) => { if (r.kind === 'belongsTo') { attrs[name] = belongsTo(r.type, r.options); } else if (r.kind === 'hasMany') { attrs[name] = hasMany(r.type, r.options); } }); mirageModels[modelName] = MirageModel.extend(attrs); });
  19. Object.keys(getDsModels()).forEach(modelName => { let model = models[modelName]; let attrs =

    {}; model.eachRelationship((name, r) => { if (r.kind === 'belongsTo') { attrs[name] = belongsTo(r.type, r.options); } else if (r.kind === 'hasMany') { attrs[name] = hasMany(r.type, r.options); } }); mirageModels[modelName] = MirageModel.extend(attrs); });
  20. Object.keys(getDsModels()).forEach(modelName => { let model = models[modelName]; let attrs =

    {}; model.eachRelationship((name, r) => { if (r.kind === 'belongsTo') { attrs[name] = belongsTo(r.type, r.options); } else if (r.kind === 'hasMany') { attrs[name] = hasMany(r.type, r.options); } }); mirageModels[modelName] = MirageModel.extend(attrs); });
  21. EMBER-X-TABLE Chris Garrett @pzuraq Erik Bryn @ebryn Offir Golan @offirgolan

    Alex Alvarez @alexander-alvarez Jan Buschtöns @buschtoens