Ember and containers

37
Let’s talk about containers. Matthew Beale -- @mixonic -- madhatted.com I build Ember apps for spiy clients in NYC Friday, July 12, 13

description

Please refer to this talk: http://www.slideshare.net/mixonic/containers-di Much more up to date, and discussing detailed use-cases.

Transcript of Ember and containers

Page 1: Ember and containers

Let’s talk about containers.

Matthew Beale -- @mixonic -- madhatted.com

I build Ember apps for spiffy clients in NYC

Friday, July 12, 13

Page 2: Ember and containers

Friday, July 12, 13

Page 3: Ember and containers

Y’all got issues.

Friday, July 12, 13

Page 4: Ember and containers

Convention over configuration.Global namespace! So easy!

new App[controllerName+‘Controller’]()

Friday, July 12, 13

Page 5: Ember and containers

• Namespaces are !ood. Less !lobals, less conflicts.

• Files map to modules. Could be useful!

• Mana!e dependencies in JS. Better/simpler build pipeline and re-usability.

Oh, maybe we should use modules….

Modules for JS

Friday, July 12, 13

Page 6: Ember and containers

THEY’RE COMING

ES6 MODULESFriday, July 12, 13

Page 7: Ember and containers

Memory management.Who cares!

Friday, July 12, 13

Page 8: Ember and containers

Friday, July 12, 13

Page 9: Ember and containers

• When do you declare an object un-used?

• What about nested collections of objects?

• How do you reset sin!letons durin! tests?

Oh, maybe we should use an Inversion of Control Container….

Herding objects is hard.

Friday, July 12, 13

Page 10: Ember and containers

Dependencies between objectsGlobal namespace! So easy!

App.fooController = Ember.Controller.create({

Friday, July 12, 13

Page 11: Ember and containers

• Namespaces are !ood. Less !lobals, less conflicts. App.everythin!IsNotASolution

• Often, it will be useful to attach a dependency based on type.

• Knowin! and possibly stubbin! dependencies in tests would be nice.

Oh, maybe we should use Dependency Injection….

Dependencies between objects

Friday, July 12, 13

Page 12: Ember and containers

Friday, July 12, 13

Page 13: Ember and containers

352 PAGESFriday, July 12, 13

Page 14: Ember and containers

• Factories receive instance variables.

• Resolvers find factories.

• Containers mana!e injections.

Three Components

Friday, July 12, 13

Page 15: Ember and containers

1 var Factory = Ember.Object.extend(); 2 3 // Receives instance variables as a new instance. 4 Factory.create(injections); 5 6 // Can receive injections for future instances. 7 Factory.extend(injections); 8 9 10 // Today in Ember, injections are only sent to instances.11 // Don't worry yourself about this too much, it may change.

Ember Factories

Friday, July 12, 13

Page 16: Ember and containers

Ember Resolvers

1 Ember.DefaultResolver = Ember.Object.extend({ 2 namespace: null, 3 4 resolve: function(fullName) { 5 var parsedName = this.parseName(fullName); 6 7 // Some magic for specific types, but usually getting to: 8 return this.resolveOther(parsedName); 9 },10 11 resolveOther: function(parsedName) {12 var className = classify(parsedName.name) + classify(parsedName.type),13 factory = get(parsedName.root, className);14 if (factory) { return factory; }15 }16 })

Resolves fullNames like controller:application

Must provide `resolve`

Friday, July 12, 13

Page 17: Ember and containers

Ember Containers

1 var container = new Ember.Container(); 2 3 container.register('worker:uploader', MyUploader); 4 container.injection('controller', 'uploader', 'worker:uploader'); 5 6 container.resolve('worker:uploader'); //=> MyUploader 7 container.lookup('worker:uploader'); //=> instance of MyUploader 8 9 container.lookup('controller:application').get('uploader');10 //=> same instance of MyUploader11 12 container.reset();

Friday, July 12, 13

Page 18: Ember and containers

Friday, July 12, 13

Page 19: Ember and containers

In your own app

Thus, `worker` is available on FilePickerController instances

1 var App = Ember.Application.create();2 3 App.register('worker:uploader', MyUploader);4 App.inject('controller:filePicker', 'worker', 'worker:uploader');5 6 // Ah, so simple.

Friday, July 12, 13

Page 20: Ember and containers

In Ember Data

1 Ember.onLoad('Ember.Application', function(Application) { 2 Application.initializer({ 3 name: "store", 4 5 initialize: function(container, application) { 6 application.register('store:main', application.Store); 7 8 // Eagerly generate the store so defaultStore is populated. 9 // TODO: Do this in a finisher hook10 container.lookup('store:main');11 }12 });13 14 Application.initializer({15 name: "injectStore",16 17 initialize: function(container, application) {18 application.inject('controller', 'store', 'store:main');19 application.inject('route', 'store', 'store:main');20 }21 });22 });

Thus, `store` is available on controllers and routes

Friday, July 12, 13

Page 21: Ember and containers

In your tests

1 Ember.Container.prototype.stub = function(fullName, instance) { 2 instance.destroy = instance.destroy || function() {}; 3 this.cache.dict[fullName] = instance; 4 }; 5 6 var container; 7 8 module('UserController saves', { 9 setup: function(){ container = App.__container__ }10 });11 12 test('is saves', function(){13 expect(1);14 container.stub('main:store', function(){15 this.save = function(){ ok(true) };16 });17 controller = container.lookup('controller:user');18 controller.send('submit');19 });

Friday, July 12, 13

Page 22: Ember and containers

THEY’RE COMING

ES6 MODULESFriday, July 12, 13

Page 23: Ember and containers

THEY’RE HERE

ES6 MODULES

EMBER APP KIT

Friday, July 12, 13

Page 24: Ember and containers

In your own app

Thus, `worker` is available on FilePickerController instances

1 var App = Ember.Application.create();2 3 App.register('worker:uploader', MyUploader);4 App.inject('controller:filePicker', 'worker', 'worker:uploader');5 6 // Ah, so simple.

GLOBAL

Flashback to…

Friday, July 12, 13

Page 25: Ember and containers

• Namespaces are !ood. Less !lobals, less conflicts.

• Files map to modules. Could be useful!

• Mana!e dependencies in JS. Better/simpler build pipeline and re-usability.

Oh, maybe we should use modules….

Modules for JS

Flashback to…

Friday, July 12, 13

Page 26: Ember and containers

https://github.com/stefanpenner/ember-app-kit

Grunt pipeline, es6-module-transpiler

Friday, July 12, 13

Page 27: Ember and containers

1 module "appkit/app" { 2 var App = Ember.Application.create(); 3 export default App; 4 // <script type="text/javascript">import App from “appkit/app”;</script> 5 } 6 7 module "appkit/templates/application" { 8 var template = Ember.Handlebars.compile("Howdy Washington!"); 9 export default template;10 }

Real scopes. No globals.

Files become ES6 modules

Friday, July 12, 13

Page 28: Ember and containers

Friday, July 12, 13

Page 29: Ember and containers

Ember Resolvers

1 Ember.DefaultResolver = Ember.Object.extend({ 2 namespace: null, 3 4 resolve: function(fullName) { 5 var parsedName = this.parseName(fullName); 6 7 // Some magic for specific types, but usually getting to: 8 return this.resolveOther(parsedName); 9 },10 11 resolveOther: function(parsedName) {12 var className = classify(parsedName.name) + classify(parsedName.type),13 factory = get(parsedName.root, className);14 if (factory) { return factory; }15 }16 })

Resolves fullNames like controller:application

Must provide `resolve`

Flashback to...

IMPLIES APP.SOMETHING

Friday, July 12, 13

Page 30: Ember and containers

1 module "appkit/app" { 2 var App = Ember.Application.create(); 3 4 import applicationTemplate from "appkit/templates/application"; 5 Em.TEMPLATES['application'] = applicationTemplate; 6 7 export default App; 8 // <script type="text/javascript">import App from “appkit/app”;</script> 9 }10 11 module "appkit/templates/application" {12 var template = Ember.Handlebars.compile("Howdy Washington!");13 export default template;14 }

Quick fix...

But do that for everything? No way.

Friday, July 12, 13

Page 31: Ember and containers

• Factories receive instance variables.

• Resolvers find factories.

• Containers mana!e injections.

Three Components

Flashback to…

OH HAI

Friday, July 12, 13

Page 32: Ember and containers

80 function resolveOther(parsedName) { 81 var prefix = this.namespace.modulePrefix; 82 Ember.assert('module prefix must be defined', prefix); 83 84 var pluralizedType = typeMap[parsedName.type] || parsedName.type; 85 var name = parsedName.fullNameWithoutType; 86 87 var moduleName = prefix + '/' + pluralizedType + '/' + underscore(name); 88 var module; 89 90 if (define.registry[moduleName]) { 91 module = requireModule(moduleName); 92 93 if (typeof module.create !== 'function') { 94 module = classFactory(module); 95 } 96 97 if (Ember.ENV.LOG_MODULE_RESOLVER){ 98 Ember.logger.info('hit', moduleName); 99 }100 101 return module;102 } else {103 if (Ember.ENV.LOG_MODULE_RESOLVER){104 Ember.logger.info('miss', moduleName);105 }106 107 return this._super(parsedName);108 }109 }

/vendor/loader.js

Friday, July 12, 13

Page 33: Ember and containers

1 module "appkit/app" { 2 var App = Ember.Application.create(); 3 export default App; 4 // <script type="text/javascript">import App from “appkit/app”;</script> 5 } 6 7 module "appkit/templates/application" { 8 var template = Ember.Handlebars.compile("Howdy Washington!"); 9 export default template;10 }

Ember & ES6 modules, no hacks

Friday, July 12, 13

Page 34: Ember and containers

• Views

• Controllers

• Templates

• Routes

Today, works with...

Yay, good-guy classes are fetched via containers

Friday, July 12, 13

Page 35: Ember and containers

• Some Views

• Models

• Helpers

Today, busted with...

Boo, Scumbag classes are not referenced via the container

Friday, July 12, 13

Page 36: Ember and containers

• Subcontainers. Flush only part of the app.

• Sin!leton controllers live forever. Problem? Feature?

• Ember.Container could become a micro-lib. Uses no Ember internally.

The future

Friday, July 12, 13

Page 37: Ember and containers

Questions? Ideas?

Matthew Beale - @mixonic - madhatted.com

Friday, July 12, 13