inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.16k stars 713 forks source link

Dependency tree #535

Closed gagle closed 7 years ago

gagle commented 7 years ago

How can I get the dependency tree of a chain of injectables A injects B injects C?

I'm trying to implement some kind of framework on top of inversify. I would like to do the following list of things:

  1. Automatic binding of components.
  2. Asynchronous initialization.

Point 1 is resolved, so this is not a problem but with point 2 I'm having some difficulties and I don't know if I could solve it without a change in inversify. We already know the problem with issue #418.

Acomponent is a singleton class wich implements some lifecycle functions such as init() and destroy(). Concrete components of this framework will inherit from the base Component class.

export interface ComponentLifecycle {
  init: () => Promise<void>;
  destroy: () => Promise<void>;
}

By automatic binding I mean that I don't want the user to use inversify directly. For now what I'm doing is a thin wrapper arround inject() and injectable(). Each time injectable() is called I store in the metadata of a ComponentContainer class the class Component that is going to be injected later:

export function injectable() {
  return (target: any) => {
    const components: Array<Newable<Component>>
      = Reflect.getMetadata(COMPONENTS_KEY, ComponentContainer) || [];
    components.push(target);
    Reflect.defineMetadata(COMPONENTS_KEY, components, App);

    inversifyInjectable()(target);
  };
}

Then later there's some point when I read all the injectables, create the container and bind all of them in the following way:

const componentCtors = Reflect.getMetadata(COMPONENTS_KEY, ComponentContainer) || [];
const container = new Container();
for (const ctor of componentCtors) {
  container.bind(ctor).toSelf().inSingletonScope();
}

I always know the main component so I can resolve the dependencies by using resolve() or get().

To try to solve the async init I could call to the init() function manually in the same order that injectables dependencies are resolved by inversify. If A injects B and B injects C, classes are instantiated in a predictable way: C, B, A.

So I think that here I have a chance to call init() in the same order that te components are instantiated.

gagle commented 7 years ago

I just built the tree dependency tree by reading the metadata of each class, keys inversify:tagged and inversify:tagged_props

remojansen commented 7 years ago

Hi @gagle sorry for the late reply I was on holidays... checkout the metadata middleware feature I have a feeling that maybe could be useful for your use case.

gagle commented 7 years ago

Hi @remojansen , this definitely will work to get the metadata in a consistent way. Thanks!