4

I don't understand.. if I can use import in Aurelia, why do I have to wire up the constructor with @autoinject() and all that? I'm sure I'm missing something, but, from what I can tell, I can just use my imported module whenever I want.

import something from "whatever"

export class SomeViewModel {
    activate() {
        // use something
    }
}
Alex Dresko
  • 5,179
  • 3
  • 37
  • 57
  • Dependency injection is a good thing, and it's orthogonal to modules. Because no system does feature DI on modules, we still do it to constructors. – Bergi May 25 '16 at 00:23

2 Answers2

11

Typically, in an Aurelia application, the thing you are importing isn't an instance of Something it's the class Something. To actually use whatever has been imported, you need an instance of it.

import Something from 'whatever';

let something = new Something();

When you use Aurelia's Dependency Injection system, you are utilizing a design pattern called "Inversion of Control." Instead of your class (or you) being in charge of instantiating its dependencies, it lists what dependencies it has and then has instances of the dependencies injected in to its constructor function.

This helps with testability, as now you can pass mocked instances of the dependencies to a class in your test fixtures (note that in your tests, your tests will pass the mocks to the constructor, and not rely on Aurelia's DI container).This also allows you to tap in to the Dependency Injection container's ability to be configured to create dependencies using different object lifestyles such as singletons and transient.

--- Edits to answer OP's questions from comments ---

If I import a module defined as export default class Something into an aurelia view model using constructor injection, it does not need to be instantiated. It is an instance of the class Something.

This is because Aurelia's Dependency Injection container is instantiating an instance for you. This is why your code looks like this:

import {inject} from 'aurelia-framework';
import Something from 'somewhere';

@inject(Something)
export class Foo {
  constructor(something) {
    this.something = something;
  }
  //...
}

and not

import Something from 'somewhere';
export class Foo {
  constructor(Something) {
    this.something = something;
  }
  //...
}

You are telling Aurelia "I need one of these, please give it to me," and Aurelia says "Sure thing, I've created one or I already had one lying around, here it is."

In other words, it appears that aurelia's constructor DI only works with class exports, and it does instantiate the class. It looks like if I want to import something like moment js into my aurelia view model, I should just continue doing things the way I've always done them (not using aurelia's DI). Does that sound correct?

This is correct. Libraries like moment give you a function to use, and not a class that can be instantiated by Aurelia. For these you would continue to use them as in the past.

Ashley Grant
  • 10,879
  • 24
  • 36
  • "Typically, in an Aurelia application, the thing you are importing isn't an instance of Something it's the class Something" That does not appear to be true. If I `import` a module defined as `export default class Something` into an aurelia view model using constructor injection, it does not need to be instantiated. It is an instance of the class `Something`. As a test to determine aurelia's DI capabilities, I tried importing a module defined as `export default function whatever` into an aurelia view model, but could not figure out how to get that to work with aurelia's DI. – Alex Dresko May 25 '16 at 11:36
  • In other words, it appears that aurelia's constructor DI only works with class exports, and it does instantiate the class. It looks like if I want to import something like moment js into my aurelia view model, I should just continue doing things the way I've always done them (not using aurelia's DI). Does that sound correct? – Alex Dresko May 25 '16 at 12:12
  • I've answered these questions in the answer above. – Ashley Grant May 25 '16 at 14:37
  • Please clarify or correct this "Typically, in an Aurelia application, the thing you are importing isn't an instance of Something it's the class Something. To actually use whatever has been imported, you have to instantiate an instance of it." It sounds opposite of what you're trying to say. – Alex Dresko May 25 '16 at 23:14
  • Also, per my understanding, aurelia's DI does not help with testability any more than `import`ing a module does. People have been mocking module dependencies with requirejs for a long time now. And if your aurelia module requires old school modules like moment, you've still got to fall back to those older techniques if you want to mock those dependencies. It seems the only thing aurelia's DI gets you is the ability to determine if you want a transient or singleton instance at runtime. Please correct me if I'm wrong. I would like for this answer to help as many people as possible. – Alex Dresko May 25 '16 at 23:20
  • You're correct that Aurelia's DI doesn't help with testability. The testability win comes from using the dependency injection pattern. When you are testing your classes, you will be passing mocked dependencies to the constructory yourself. – Ashley Grant May 25 '16 at 23:50
  • I've updated the language in the answer to "you need an instance." – Ashley Grant May 25 '16 at 23:52
5

Well technically you can use the imported modules without Aurelia's DI, but in most situations that would be a bad thing. The Dependency Injection layer gives you so much versatility and flexibility. It handles caching, it supports singleton and transient dependencies, handles lifetime and makes thing neater from an architectural perspective.

Dwayne Charrington
  • 6,524
  • 7
  • 41
  • 63