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

d-inject

v0.1.6

Published

Simple DI container for singleton dependencies

Downloads

10

Readme

d-inject

Dependency Status Build Status

Overview

d-inject is an opinionated way to manage and organize dependencies in Node.JS projects. This project has been inspired by Java dependency injection libraries like Google Guice and Spring Framework. This uses the singleton pattern along with lazy-loading for efficiency.

Explanation

createInjector creates a dependency injection container for you to manage dependencies. You can have many dependency injection containers

get will get a dependency from the DI container. We call get with a string representing the name of the dependency and it will return back the value (object) associated with that key (string).

set will set a dependency into the DI container. set takes two arguments. The name of the dependency and the (factory) function that produces the object. Note that this little detail allows us to implement lazy loading (so we don't load it until we absolutely have to - a technique taken from functional data structures for infinite sequences).

inject is a convenience method. The first argument is a function (single argument) that takes in dependencies as its arguments, the rest of the arguments (variadic) are the dependency names that the function requires as arguments. The Depndency Injection mechanism will inspect the dependencies that the function requires, create an object with the dependencies as properties and call the function with its arguments and returns it.

Examples

Let's look at some ways that this library can be used. Say I have a function with dependencies

a.js
----
function doSomething(arg) {
 return arg.hello('How are you');
}

function a(deps) {
    assert(deps != null);
    assert(deps.b != null);
    return doSomething(b);
}

module.exports = a;

As you can see the function a, has a dependency on b. If b is not present then a cannot work. Let's say that b looks like this

b.js
----
module.exports = function(greeting) {
    console.log('------');
    console.log(greeting);
    console.log('------');
};

There are two ways we can use the d-inject library to make our lives easier. Let's see one way to do it. This is commonly used when dependencies can only be inferred at runtime. These examples are written using ECMAScript 6

main.js
-------
let a = require('./a');
let b = require('./b');
let injectorInstance = require('d-inject).createInjector();

// lets load b into the injector, I can retrieve it by asking the injector for bInstance
injectorInstance.set('bInstance', function() { return b });

// note a relies on b, I can go to the dependency injection container and ask for b
let configuredA = injectorInstance.inject(a, 'bInstance');

// let's inject the configuredA object into the container instance
injectorInstance.set('aInstance', function() { return configuredA });

configuredA.doSomething('Hello');
# ------
# Hello
# ------

This was a simple example to illustrate the functionality. Let's take a look at something you are likely to encounter when using this in your projects

controller.js
-------------
function controller(deps) {

  assert.object(deps.service, 'service is missing');
  
  return function(req, res, next) {
    let id = req.params.id;
    //using dependency here
    let result = service.get(id);
    res.send({'result': result});
  }
}

module.exports = controller;
service.js
-------------
function service(deps) {
  assert.object(deps.runtimeDep, 'runtimeDep is missing');
  
  //getFromDbSync implementation not shown
  
  return function(id) {
    //using dependency here
    return getFromDbSync(id, deps.runtimeDep);
  }
}

module.exports = service;

So service has a runtime dependency. However, controller knows ahead of time that it needs service as its direct dependency. We can configure what we know ahead of time but we won't execute it until runtime when we have all our dependencies

configureAOT.js
---------------

function register(diContainer) {
    function controller() {
        let controllerClass = require('./controller');
        return diContainer.inject(controllerClass, 'service');
    }
    
    // registration 
    // remember we use factory functions to enable lazy-loading
    diContainer.set('controller', controller); 
}

module.exports = register;

Note we did not configure service as it has a runtime dependency.

Let's say we are running our application so you can see how runtime dependencies are being set

main.js
-------
let injectorInstance = require('d-inject).createInjector();

let dbInfo = process.env.DBINFO;    //runtime dependency (obtain DBINFO from environment variable)

// configure service now that we have the runtime information
let service = require('./service');

// configure service (at runtime)
injectorInstance.set('service', function() { service({runtimeDep: dbInfo}); })

// now call register
let staticDeps = require('./configureAOT');
staticDeps(injectorInstance);

// now everything is configured!
// remember controller returns a function that handles requests
http.createServer(injectorInstance.get('controller'));  
server.listen();

This made our code simpler. We were able to hook up dependencies in an organized fashion.