Code Monkey home page Code Monkey logo

rsdi's Introduction

Dependency Injection Container

Getting Started

// your classes 
class CookieStorage {}
class AuthStorage {
  constructor(storage: CookieStorage) {}
}

// configure DI container
import DIContainer, { object, get, factory, IDIContainer } from "rsdi";

export default function configureDI() {
    const container = new DIContainer();
    container.addDefinitions({
        "ENV": "PRODUCTION",               // define raw value
        "AuthStorage": object(AuthStorage).construct(
            get("Storage")                         // refer to another dependency       
        ),
        "Storage": object(CookieStorage),         // constructor without arguments       
        "BrowserHistory": factory(configureHistory), // factory (will be called only once)  
    });
}
    
function configureHistory(container: IDIContainer): History {
    const history = createBrowserHistory();
    const env = container.get("ENV");
    if (env === "production") {
        // do what you need
    }
    return history;
}

// in your entry point code
const container = configureDI();
const env = container.get<string>("ENV"); // PRODUCTION
const authStorage = container.get<AuthStorage>("AuthStorage");  // object of AuthStorage
const history = container.get<History>("BrowserHistory");  // History singleton will be returned

All definitions are resolved once and their result is kept during the life of the container.

Features

  • Simple but powerful
  • Does not requires decorators
  • Works great with both javascript and typescript

Motivation

Popular solutions like inversify or tsyringe use reflect-metadata that allows to fetch argument types and based on those types and do autowiring. Autowiring is a nice feature but the trade-off is decorators. Disadvantages of other solutions

  1. Those solutions work with typescript only. Since they rely on argument types that we don't have in Javascript.
  2. I have to update my tsconfig because one package requires it.
  3. Let my components know about injections.
@injectable()
class Foo {  
}

Why component Foo should know that it's injectable?

More details thoughts in my blog article

Raw values

import DIContainer from "rsdi";

const container = new DIContainer();
container.addDefinitions({   
    "ENV": "PRODUCTION",  
    "AuthStorage": new AuthStorage(),
    "BrowserHistory": createBrowserHistory(),
});
const env = container.get<string>("ENV"); // PRODUCTION    
const authStorage = container.get<AuthStorage>("AuthStorage"); // instance of AuthStorage     
const authStorage = container.get<History>("BrowserHistory"); // instance of AuthStorage     

When you specify raw values (i.e. don't use object, factory definitions) rsdi will resolve as it is.

Object definition

  
import DIContainer, { object, get } from "rsdi";
  
const container = new DIContainer();
container.addDefinitions({
   "Storage": object(CookieStorage),         // constructor without arguments
   "AuthStorage": object(AuthStorage).construct(
      get("Storage")                         // refers to existing dependency       
   ),  
   "UsersController": object(UserController),
   "PostsController": object(PostsController),
   "ControllerContainer": object(ControllerContainer)
     .method('addController', get("UsersController"))
     .method('addController', get("PostsController"))
});

object(ClassName) - the simplest scenario that will call new ClassName(). When you need to pass arguments to the constructor, you can use constructor method. You can refer to the existing definitions via get helper. If you need to call object method after initialization you can use method it will be called after constructor. You also can refer to the existing definitions via get method.

Factory definition

You can use factory definition when you need more flexibility during initialisation. container: IDIContainer will be pass as an argument to the factory method.

import DIContainer, {  factory, IDIContainer } from "rsdi";

const container = new DIContainer();
container.addDefinitions({       
  "BrowserHistory": factory(configureHistory),   
});

function configureHistory(container: IDIContainer): History {
    const history = createBrowserHistory();
    const env = container.get("ENV");
    if (env === "production") {
        // do what you need
    }
    return history;
}
const history = container.get<History>("BrowserHistory"); 

rsdi's People

Contributors

radzserg avatar dependabot[bot] avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.