Epoxy is a lightweight (~200 sloc) IoC container for NodeJS. Notable features:
- automatic dependency injection ( in multiple flavours )
- multiple injection patterns -
constant, constructor, factory, singleton
- circular depedency detection and resolution
- made with 💜 and ES2015
npm install epoxy-di
// ./index.js
const { Container, Providers } = require( 'epoxy-di' )
const ioc = new Container( [
Providers.CurrentDirectory,
Providers.NodeModules
] )
ioc.create( 'app' )
// ./app.js
exports = module.exports = (
http,
router = 'handlers/router'
) => {
return http.createServer( router )
}
// ./handlers/router
exports = module.exports = (
index = 'handlers/index',
notFound = 'handlers/404'
) => ( req, res ) => {
switch( req.url ) {
case '/':
case '/index':
return index( req, res )
default:
return notFound( req, res )
}
}
constructor( [ providers = Providers.CurrentDirectory ] )
The Container
constructor accepts a list of providers. If none are provided, it will default to the current directory provider.
Creates the module with the given id. Resolves dependencies automatically and caches factories and instances along the way.
Adds providers after container creation.
Registers a factory for the provided id with the container. Useful for mocking out modules or providing overrides.
Providers are sources ( paths at the moment ) where to look for dependencies when resolving modules. Providers are relative to the file where create is called.
There are two predefined providers shipped with epoxy:
CurrentDirectory
- provides modules in the current directory ( default )
NodeModules
- provides node modules
There are multiple strategies provided for dependency discovery and type definition for a module:
exports = module.exports = ( http, handler, port ) => {
return class {
constructor( ) {
this.server = http.createServer( a )
}
}
}
exports[ '@type' ] = 'constructor'
exports[ '@inject' ] = [
'http',
'middleware/handler',
'config/port'
]
exports = module.exports = (
http,
handler = 'middleware/handler',
port = 'config/port'
) => {
return class {
constructor( ) {
this.server = http.createServer( a )
}
}
}
exports[ '@type' ] = 'constructor'
Multiple injection types are supported:
Constant
- module injected as-is, and cached
Constructor
- module treated as a constructible, injected with new
Factory
- module treated as a factory; injection is done by calling the factory each time to get a fresh instance
Singleton
- same as Factory
, but the first resulting instance is cached and injected for all subsequent times
Circular dependencies are allowed and will be resolved ( with the help of lazyref ), but generally if you come to a situation where you have a circular dependency in your project it is likely that you have a design flaw that you can correct rather than keep a cicular dependency.
- async modules
- performance benchmarks
- more robust depedency parsing
MIT