Ember.js’ Dependency Injection System

Is it the reason for Ember.js’ complex build system?

Sarbbottam Bandyopadhyay
3 min readOct 4, 2019

If you have worked with Ember.js you are probably aware of its Dependency Injection container. The core concepts of Ember.js is based around the Dependency Injection.

Dependency Injection is a form Inversion of Control where implementations are passed into an object through constructors, setters, service lookups. In Ember.js ecosystem it is often through lookups, at least in the application code.

You might have used the following or similar statements in your application.

import { inject as service } from '@ember/service';
...
import { inject as controller } from '@ember/controller';

Is Dependency Injection the reason for Ember.js’ complex build system?

I often hear that Ember.js Dependency Injection has led to its complex build system. I personally have no idea how an Ember.js application is built but I don't disgree that it is complex, at least to me. However, I was reluctant to agree that Ember.js’ use of Dependency Injection has led to its complex build system.

Dependency Injection is a well-known pattern and it is not restricted to Ember.js. I have first used it in 2009 while working on a Spring-based Java Project.

So, I created an Ember-ish application following its Dependency Injection usage to find out if it led to Ember’s complex build system.

Ember-ish DI

It’s a regular Node.js application, where index.js file is the main entry and it can be run like regular node applications just by executing node index.js.

The Dependency Injection is implemented at the Container.js, its a singleton, which exposes two methods namely register(key, value) similar to but not exactly as Ember.js register method and lookup(key) also similar to but not exactly as Ember.js’ lookup method.

//Container.js
const Container = (function() {
let instance = null;
let registry = {};
return class Container {
constructor() {
if (instance) {
return instance;
}
instance = this;
}
register(key, value) {
registry[key] = value;
}
lookup(key) {
return registry[key];
}
}
}());
module.exports = Container;

Any instance of an object or reference can be registered like so:

new Container().register('SomeService', new SomeService());

and can be looked up like so:

this.someService = container.lookup('SomeService');

Refer SomeService.js and SomeComponent.js in the above-mentioned repl for the usage.

In this application (emberish-di), the registration of dependencies are explicit and done the concerned code/file.

SomeService is registered by the SomeService.js, whereas in an Ember.js application it is done during the build time based on conventional file layout and directory names.

Like any Ember Application, this application is split across multiple files. However, using webpack or similar utilities it is possible to create a single file similar to an Ember App, without any complexity.

Conclusion

I don’t think Ember’js Dependency Injection Container is the reason for its complex build system rather the complexity arises from the implicit registration of dependencies based on conventional file layout and directory names.

Thank you for reading. Please feel free to share your thoughts.

--

--