npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

fluency-injection

v1.1.2

Published

A TypeScript dependency injection framework for Node.js, inspired by Angular2 dependency injection using decorators.

Downloads

2

Readme

Fluency Injection

A TypeScript dependency injection framework for Node.js, inspired by Angular2 dependency injection using decorators.

It is designed to make Node.js dependency injection more fluid by using TypeScript decorators.

Inspiration

Any users that have built applications with Angular2 may notice some similarities between this framework and the Angular2 dependency injection framework.

Firstly it uses the same decorator (e.g. @Inject() and @Injectable) and method (e.g. bootstrap() and provide()) names in order to keep a consistent API as I envisage this framework being used in node applications, meaning that you may be using both this framework and Angular2 in the same app.

Secondly, the mechanism for getting the constructor parameter types uses the Reflect Metadata library, which is also used by Angular2.

Why Use This Library?

  1. It makes providing dependencies to classes much more readable and avoids spaghetti-code.
  2. Unit testing becomes very easy as you can test the class by creating a new instance of it, providing mocked dependencies in order to control the flow of the class logic.
  3. It will feel familiar with users of Angular2.

Installation

  • Install the fluency-injection package using npm install --save fluency-injection.
  • Make sure to also install the reflect-metadata package using npm install --save reflect-metadata as it is a peer dependency of the framework.

Documentation

tsconfig.json

In your tsconfig.json file make sure to enable the experimentalDecorators and emitDecoratorMetadata options as these are required for Reflect to get the constructor parameter types.

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

For more information see the tsconfig documentation.

Bootstrapping the Main Class

To initialise the IoC container, call the bootstrap method with the Main Class.

This initialises the Main Class and resolves all dependencies recursively.

import { Injectable, bootstrap } from 'fluency-injection';

@Injectable
class TestDependency {
  constructor() {}

  public sayHello() {
    console.log('Hello!');
  }
}

@Injectable
class Main {
  constructor(testDependency: TestDependency) {
    testDependency.sayHello();
  }
}

bootstrap(Main);

The above example will attempt to initialise the Main class by creating an instance of the TestDependency class (and so on, until all dependencies have been provided).

The output will be 'Hello'.

Note: All dependencies are singletons so if you wish to create new instances, create a factory class or provide the class as a value (see below).

In the example above, if another class tried to inject the TestDependency class, it would receive the same instance as the Main class.

Providing Custom Dependencies

Sometimes you may need to inject an external library into a class (e.g. a logging framework).

In order to do this, call the provide method with a token (can be any unique value) and an object with either the value you wish to provide to the classes that try to inject using the token, or a factory function which be executed for each injection and must return the depedency.

import { Inject, Injectable, bootstrap, provide } from 'fluency-injection';
import * as externalLibrary from 'external-library';
import * as anotherExternalLibrary from 'another-external-library';

let Token = Symbol('token'),
  AnotherToken = Symbol('anotherToken');

provide(Token, {
  useValue: externalLibrary
});

provide(AnotherToken, {
  useFactory: () => {
    return new anotherExternalLibrary();
  }
});

@Injectable
class Main {
  constructor(@Inject(Token) externalLibrary: any,
              @Inject(AnotherToken) anotherExternalLibrary: any) {
    console.log(externalLibrary); // Will be the value provided to the application using the provide method.
    console.log(anotherExternalLibrary); // Will be the value returned by the factory function passed to the provide method.
  }
}

bootstrap(Main);

In the above example the provide method is used to make the dependency injection framework aware of what to inject when you use the token with the Inject decorator.

The @Inject decorator is then used to tell the framework that you want the value that was provided using the token to be injected as a a constructor parameter.

Note: The token must be unique as it is used to store the value, and used to retrieve it. As such, a good practice is to create a tokens directory that exports symbols that can then be used to both provide and inject the dependency.

The @Injectable Decorator

Due to the way that TypeScript works, metadata for the constructor parameters is only output when there are decorators in the file. As such, if you don't use any decorators in a file the dependency injection framework won't be able to use the parameter types to inject the correct dependecies.

To output the metadata for the file, use the @Injectable decorator.

Better still, use the @Injectable decorator on all injectable classes.

import { Injectable } from 'fluency-injection';

@Injectable
class Dependency {}

Known Caveats

  • All classes must have a decorator of some form attached to them (or a property/method/param on them), otherwise the metadata will not be output correctly by TypeScript.

Contact

Feel free to raise issues in the issue tracker on GitHub or email me for support at [email protected].