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 🙏

© 2025 – Pkg Stats / Ryan Hefner

injectt

v1.0.0

Published

Straightforward Dependency Injection for Node and the browser

Downloads

8

Readme

Injectt

Straightforward Dependency Injection for Node and the browser

npm install injectt

An Example

src/a.js

class ClassA {
  costructor(b, c, param1, param2) {
    this.b = b;
    this.c = c;
    this.param1 = param1;
    this.param2 = param2;
  }

  // service name, requried
  static get $provides() {
    return "a";
  }

  // dependencies which will be passed
  // to the constructor, optional
  static get $requires() {
    return ["b", "c"];
  }
}

module.exports = ClassA;

src/b.js

class ClassB {
  costructor(c) {
    this.c = c;
  }

  static get $provides() {
    return "b";
  }

  static get $requires() {
    return ["c"];
  }
}

module.exports = ClassB;

src/c.js

class ClassC {
  costructor() {}

  static get $provides() {
    return "c";
  }
}

module.exports = ClassC;

main.js

const path = require("path");
const Injectt = require("injectt");

const di = new Injectt();

// load all the services recursively
// (only available in Node, not in browser)
di.load(path.resolve(__dirname, "src"));

// or register the classes by hand:
//di.registerClass(require("./src/a"));
//di.registerClass(require("./src/b"));
//di.registerClass(require("./src/c"));

const a = di.get("a", "hello world", 42);

// the first argument of .get() is the service name
assert(a instanceof ClassA);
assert(a.b instanceof ClassB);
assert(a.c instanceof ClassC);

// anything in .get() after the service name will be passed as
// additional parameters to service's constructor
assert(a.param1 === "hello world");
assert(a.param2 === 42);

// we can also store a variable of any type, not only services
di.registerInstance(42, "theAnswer");
assert(di.get("theAnswer") === 42);

Lifecycle

A service can have an optional static property $lifecycle which should be a string "perRequest", "unique" or "singleton".

Omitting the property is the same as setting it to "perRequest".

perRequest

Each call to .get() is considered a request. Services with the lifecycle of perRequest are only instantiated once per each request.

In the example above both a and b, which is a dependency of a, receive an instance of ClassC. Because this happens during execution of the same .get() call both services receive the same instance of ClassC.

unique

If ClassC had $lifecycle set to "unique" then services a and b would have received different instances of the same class ClassC. Unique services are never reused.

singleton

Consider the following:

const a1 = di.get("a");
const a2 = di.get("a");

As we have two .get() calls these are two separate requests. So service c is instantiated twice.

// ClassC.$lifecycle === "perRequest"
assert(a1.c === a1.b.c);
assert(a2.c === a2.b.c);
assert(a1 !== a2);
assert(a1.c !== a2.c);

The third possible value for $lifecycle is "singleton". Singleton services are instantiated only once during the whole life of the DI container.

In our example if ClassC was singleton then an instance of it whould have been constructed during the first .get() and then reused for any number of subsequent .get()'s.

// ClassC.$lifecycle === "singleton"
assert(a1.c === a1.b.c);
assert(a2.c === a2.b.c);
assert(a1 !== a2);
assert(a1.c === a2.c);

API

  • constructor()

    Constructs an instance of DI container.

    NOTE The container self-registers its own instance as a service named "di".

  • registerInstance(instance, name)

    Register variable instance value as service name. When the service is requested exactly this value will be returned.

    Returns service name

  • registerClass(classFunc)

    Register a class referred to by classFunc as a service. The class should have at least static property $provides defined which is used as service name. When the service is requested it will be either instantiated or possibly reused if it were instantiated before.

    Static properties which have a special meaning:

    • $provides - (required) service name

    • $requires - an array of dependicies names which will be instantiated and passed to the constructor in the same order

    • $lifecycle - one of:

      • perRequest - (default) service is instantiated once per each request

      • unique - service instances are never reused, new instances are always instantiated

      • singleton - service is instantiated only once per the whole lifetime of the container

    Returns service name

  • load(root [, options])

    Options:

    {
      dirInclude: null | [String] | [RegExp],
      dirExclude: null | [String] | [RegExp],
      fileInclude: null | [String] | [RegExp],
      fileExclude: null | [String] | [RegExp],
    }

    Passing null in *include/*exclude options means "skip this check".

    Default options:

    {
      dirInclude: null,
      dirExclude: [/^__/], // directory names must not start with two underscores
      fileInclude: [/\.js$/], // file names must end with .js extension
      fileExclude: [/\.test\.js$/], // but skip test files
    }

    Recursively loads and registers all the services in the given directory root. To be considered a service the file should match fileInclude option, do not match fileExclude option, and export a class with $provides static property defined. Subdirectories are checked againt dirInclude/dirExclude options.

    NOTE: This method is not available in the browser version of the library

  • has(name)

    Checks if a service is registered. Returns boolean.

  • search(re)

    Does search among the services by applying regular expression re to each service name

    Returns an array of matched names

  • getClass(name)

    Retrieves the class (constructor function really) of a service without instantiating it.

    name could also be a RegExp or an Array of strings, in which case getClass() will return a Map(name --> constructor function) of matching services.

  • get(name, ...extra)

    Instantiates if needs to and returns a service registered as name passing all the rest of the parameters to service constructor

    name could also be a RegExp or an Array of strings, in which case get() will return a Map(name --> instance) of matching services.

  • singletons(...extra)

    Returns Map(name -> instance) of all the singleton services

Additional Notes

  • Cyclic dependencies are not allowed (an error is thrown).

  • If requested dependecy is not found an error is thrown. You can mark a dependency as optional by adding "?" at the end of the name:

    class SomeClass {
      constructor(a, b, c) {
        // b might be null
      }
    
      static get $provides() {
        return "someClass";
      }
    
      // b is optional, becomes null if not found
      static get $requires() {
        return ["a", "b?", "c"];
      }
    }

Modern style

Usually we use ES6 imports in the browser and we often have "static class properties" proposal enabled via Babel.

In which case ClassA could be rewritten like this:

class ClassA {
  static $provides = "a";
  static $requires = ["b", "c"];

  constructor(a, b) {
    this.a = a;
    this.b = b;
  }
}

export default ClassA;
import Injectt from "injectt";
import ClassA from "./src/a";

const di = new Injectt();
di.registerClass(ClassA);
// ...

Credits

Inspired by Roy Jacobs' Intravenous