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 🙏

© 2026 – Pkg Stats / Ryan Hefner

wantsit

v2.1.3

Published

Super lightweight dependency injection

Readme

wantsit

Dependency Status devDependency Status Build Status Coverage Status

Super lightweight dependency resolution, autowiring and lifecycle management.

Or, yet another dependency injection framework.

Wat?

Using dependency injection decouples your code and makes it more maintainable, readable and testable.

Imagine I have some code like this:

var MadeUpDb = require('madeupdb')

var MyClass = function() {
  this._db = new Madeupdb('localhost', 'database_name', 'username', 'password')
}

MyClass.prototype.getTheThings() {
  return this._db.query('SELECT foo FROM bar')
}

MyClass is tightly coupled to MadeUpDb, which is to say I can't use this class now without having MadeUpDb available on localhost and database_name configured for username:password@localhost, nor can I use a different implementation (a mock object, in memory db, etc - perhaps for testing purposes).

If instead I did this:

var Autowire = require('wantsit').Autowire

var MyClass = function() {
  this._db = Autowire
};

...

Not only is there less boilerplate, MyClass has been freed from the responsibility of configuring and acquiring a data source (a beard might call this Inversion of Control) which lets me:

  • Concentrate on the interesting bits of MyClass (e.g. getTheThings())
  • Easily mock behaviour in tests by setting _db
  • Control resources centrally (were I to have two instances of MyClass, the can now share a db connection)
  • Introduce new functionality without changing MyClass. Want a connection pool? No problem, want to wrap MadeUpDb, AOP style? Done. Swap MadeUpDb for NewHotDB? Easy.

Amazing, right?

I'm sold, show me an example

var Autowire = require('wantsit').Autowire,
  Container = require('wantsit').Container

var Foo = function() {
  // works with this._bar or this.bar
  this._bar = Autowire
};

Foo.prototype.doSomething() {
 this._bar.sayHello()
}

...

var Bar = function() {

}

Bar.prototype.sayHello() {
  console.log('hello!')
}

...

var container = new Container()
container.register('bar', new Bar())

var foo = new Foo()
container.autowire(foo)

foo.doSomething() // prints 'hello!'

Lifecycle management

container.create will instantiate your object and autowire it:

container.create(Foo)
...

Pass a callback function if you require access to your object after creation:

container.create(Foo, function(error, foo) {
  ...
})

Constructor arguments are also supported by passing an array of arguments:

var Foo = function(message) {
  console.log(message)
}

var foo = container.create(Foo, ['Hello world!'])
...

Magic methods

There are optional methods you can implement to be told when things happen.

// called after autowiring and before afterPropertiesSet
Foo.prototype.containerAware = function(container) {

}

// called after autowiring and after containerAware
Foo.prototype.afterPropertiesSet = function([done]) {

}

If you specify an argument to afterPropertiesSet, you can defer execution of the callback:

// called after autowiring and after containerAware
Foo.prototype.afterPropertiesSet = function(done) {
  this._dep(function(error) {
    done(error)
  })
}
...

container.create(Foo, function(error, foo) {
  // will not be invoked until foo._dep (above) has returned 
})

afterPropertiesSet will be invoked on your class after is has been invoked on all dependencies that also declare it:

Foo = function() {}
Foo.prototype.afterPropertiesSet = function(done) {
  // do something that takes a while
  setTimeout(done, 1000)
}

Bar = function() {
  this._foo = Autowire
}
Bar.prototype.afterPropertiesSet = function() {
  // will not be invoked until the callback passed to 
  // foo.afterPropertiesSet has been called
}

...

container.createAndRegister('foo', Foo)
container.createAndRegister('bar', Bar)

N.b. this means that circular dependencies are not allowed as they will never initialise!

Initialisation timeouts

By default we wait up to 5000ms for a deferring afterPropertiesSet to invoke the passed callback. To override this timeout, pass an option to the container constructor:

var container = new Container({
  timeout: 10000 // or 0 to disable the timeout
})

Dynamic getters

Look-ups occur at runtime, so you can switch out application behaviour without a restart:

// create a bar
container.register('bar', function() {
  console.log('hello')
})

// this is our autowired component
var Foo = function() {
  this._bar = Autowire
}

Foo.prototype.doSomething = function() {
  this._bar();
}

// create and autowire it
var foo = container.create(Foo)

foo.doSomething() // prints 'hello!'

// overwrite bar
container.register('bar', function() {
  console.log('world')
})

foo.doSomething() // prints 'world!'

All autowired properties are converted to non-enumerable fields so we can JSON.stringify without serialising the entire object graph.

I want to register all of the things!

container.createAndRegisterAll(__dirname + '/lib')

To use this, all your components must be in or under the lib directory. Anything that ends in .js will be newed up and autowired.

No constructor arguments are supported, it's Autowire all the way down.

Woah, not literally all of the things

Ok, specify a regex as the second argument - anything that matches it will be excluded

container.createAndRegisterAll(__dirname + '/lib', /excludeme\.js/)

Regex? Great, now I've got two problems. Why stop there? Pass in an array of regexes:

container.createAndRegisterAll(__dirname + '/lib', [/pattern1/, /pattern2/])

I want to have functions automatically registered

Declare them in a file with a lowercase letter. Eg:

// myFunc.js
module.exports = function() {
  return true
}

..as opposed to a class which should be in a file that starts with a capital letter:

// MyClass.js
var MyClass = function() {}

MyClass.prototype.foo = function() {
  return true
}

module.exports = MyClass
container.createAndRegisterAll(__dirname + '/lib')

// find and invoke our function
var foo = container.find('myFunc')
foo()

// find and invoke a method on our singleton
var myClass = container.find('myClass')
myClass.foo()

I want to register a function on a class

No problem, just use the createAndRegisterFunction method. The first argument is the name to register the function under, the second is the name of the method on the class, the third is the class constructor. Any subsequent arguments will be passed to the constructor.

// MyClass.js
var MyClass = function() {}

MyClass.prototype.foo = function() {
  return true
}

module.exports = MyClass
container.createAndRegisterFunction('fooFunc', 'foo', MyClass)

// find and invoke our function
var foo = container.find('fooFunc')
foo()

My dependency is optional

Pass the optional option to Autowired:

// MyClass.js
var MyClass = function() {
  this._foo = Autowired({optional: true})
};

MyClass.prototype.doSomething = function() {
  // we are now responsible for making sure this._foo is not null before using it
  if(this._foo) {
    // ...
  }
}

I don't want to use the property name to resolve my dependency

Pass the name option to Autowired:

// index.js
container.register('bar', {
  baz: function() {
    return 'hello!'
  }
})

// MyClass.js
var MyClass = function() {
  this._foo = Autowired({name: 'bar'})
};

MyClass.prototype.doSomething = function() {
  // this._foo is 'bar' from the container
  this._foo.baz()
}

Object Factories

You can also automate the creation and autowiring of classes

var ObjectFactory = require('wantsit').ObjectFactory

var Foo = function(arg1, arg2) {
  this._arg1 = arg1
  this._arg2 = arg2

  // Autowired fields will be populated automatically
  this._dep = Autowired
}

// place an instance of the factory in the container
container.createAndRegister('fooFactory', ObjectFactory, [Foo]);

// MyClass.js
var MyClass = function() {
  this._fooFactory = Autowired
}

MyClass.prototype.doSomething = function() {
  this._fooFactory.create(['one', 'two'], function(error, foo) {
    foo._arg1 // 'one'
    foo._arg2 // 'two'
  })
}

## Events

error

The error event will be emitted if a component throws an error event during invocation of it's constructor, or afterPropertiesSet/containerAware methods, or if it passes an error object to the the afterPropertiesSet callback. If a callback was passed to the create method, it will receive the error instead:

// class that throws an error during construction
var Foo = function() {
  throw new Error('Panic!')
}

...

// no callback passed to `createAndRegister` so container emits error event
var container = new Container()
container.createAndRegister('foo', Foo)
container.on('error', function(error) {
  // receives error event
})

...

// here we pass a callback which will receive the error instead
var container = new Container()
container.createAndRegister('foo', Foo, function(error) {
  // receives error event
})

ready

The ready event will be emitted once all currently registered components have initialised. If you subsequently register new components, this event will fire again.

The container will be passed as the first argument to listeners.

Full API

Constructor

var container = new Container({
  // an optional logger (e.g. Winston). Defaults to the console.
  logger: {
    info: function(message) {},
    warn: function(message) {},
    error: function(message) {},
    debug: function(message) {}
  },
  
  // how long to wait for deferred `afterPropertiesSet` methods to invoke the callback
  timeout: 5000
})

Methods

container.register(name, component) Store a thing

container.find(name) Retrieve a thing - can by by name (e.g. 'foo') or by type (e.g. Foo)

container.autowire(component) Autowire a thing

container.create(constructor, [arg1, arg2...], callback) Create and autowire a thing

container.createAndRegister(name, constructor, [arg1, arg2...], callback) Create, autowire and register a thing

container.createAndRegisterAll(path, excludes) Create, autowire and register anything under path that doesn't match excludes

In create and createAndRegister above, arg1, arg2... are passed to constructor

container.setLogger(logger) Override the default logging implementation - the passed object must have info, warn, error and debug methods.