inversify-components
Small framework on top of InversifyJS to enable component based dependency injection. Each component describes its interfaces and bindings with the help of descriptors, and never accesses the dependency injection container directly. This enables you to:
- Develop loosely coupled and independent components, without exploiting your whole dependency injection container
- Enable / disable / mock whole components in your application
- Use scoped child containers, for example bind dependencies only to a http request
- Implement the extension point pattern to "plug-in" extensions of components from other components
Installation
Install inversify-components and set it as an dependency in your local package.json:
npm i --save inversify-components
Usage
Basic setup instructions
- Create the inversify-components container:
;;// Also supports options:// let container = new ContainerImpl({ defaultScope: "Singleton" });
- Create your main application, which acts as the composition root:
;
- Register all components (see below) you would like to use:
;container.componentRegistry.addFromDescriptordescriptor;
- Register all bindings of all registered component descriptors
container.componentRegistry.autobindcontainer.inversifyInstance;
- Optional: Configure some of your components:
container.componentRegistry.lookupnameOfComponent.addConfiguration;
- Start your application
container.setMainApplicationnew App;container.runMain;
Components and component descriptors
inversify-components allows you to basically split your applications into independent components. To achieve this, each component exports
a component descriptor
:
; ;
Notice that each binding gets the unique component name as a prefix. This guarantees that there are not duplicate service bindings across all registered components.
Grab inversify container
You are also able to grab the inversify coontainer in a ComponentDescriptor
:
; ;
So if needed, you are always in full control inside your dependency descriptors.
Changing the scope of a binding
The above component descriptor executes bindings for the root
scope. This is the default scope for inversify-components, which
is executed automatically at autobind
. But you could also register bindings for a specific scope, and execute this scope
at application runtime to a specific point in time:
; ; // In your MainApplication / App, as soon as you would like to open the above "request" scope:// 1) Create inversify child container; // 2) Possibly bind some dependent values to this container, e. g. the current request headers and body:scopedRequestContainer.bind"request-body".toConstantValuecurrentRequestBody; // 3) Execute scoped "request" bindings in this containercontainer.componentRegistry.autobindscopedRequestContainer, , "request"; // 4) Go on in your compoisiton root with child containerscopedRequestContainer.get... // Maybe your request handler?
Using extension points
To enable plugging into your component, you can define extension points. This is done using symbols.
Component A: The component which owns the extension point and wants to load plugins:
;; ;
Component B: The component which adds a plugin to extension point firstExtensionPoint:
;
Configuration
The basic style of configuring components is described in this gist. This style enables you to define default and required configurations without hassle.
Set default configuration
You can set a default configuration for your component by adding it to your descriptor:
;
Inject configuration values
In all of your classes, you can inject your component meta data, which includes the components configuration:
;; }