pluginjector
v1.0.7
Published
Inject plugins into your module with `this` automatically bound to your core module for methods.
Downloads
13
Maintainers
Readme
pluginjector
Simple no nonsense dependency injection for extensibility and testability
Install from NPM
Help with development on GitHub
Donations accepted. 😃 😃 😃 $5 $5 😘 😘 😘
- Usage -
Note: Uses ES6/ES2015 features and may fail on Node versions prior to v6.
Pass your core module object to pluginjector then inject plugins
const pluginjector = require('pluginjector')
const inject = pluginjector(myModule)
const myNewModule = inject(myPlugin)
Overwrite properties in your module
const myModule = { val: 1 }
const myPlugin = { val: 2 }
const newModule = pluginjector(MyModule)(myPlugin)
assert(newModule.val === 2) // true
Overwrite methods in your module
const myModule = {
method (){return 'method'}
}
const myPlugin = {
method (){return ('plugin')}
}
const newModule = pluginjector(MyModule)(myPlugin)
assert(newModule.method() === 'plugin') // true
Namespace your plugins
const myPlugin {
method( return 'method' )
}
const myNewModule = inject({pluginname: myPlugin})
assert(myNewModule.myPlugin.method() === 'method') // true
Bind this
to your methods with a simple flag
more detailed look at this later
const myModule = {val: 1}
const myPlugin = {
pluginjectorBindThis: true,
method (){ return this.val }
}
const newModule = pluginjector(myModule)({myPlugin})
assert(newModule.myPlugin.method() === 1) // true
Pass in files to be imported
const newModule = inject('../path/to/my/file')
const newNamespacedModule = inject({pluginName: '../path/to/my/file'})
// filenames are automatically namespaced in camelCase
const nModule = inject('../location/my-plugin')
assert( !!nModule.myPlugin ) // true
Include a default directory and your users can pass in just the plugin name.
const inject = (myModule, {dir: '../path/to/default/directory'})
const newModule = inject('pluginName')
const newNamespacedModule = inject({differentPluginName: 'pluginName'})
Lazily inject different plugins as needed
const inject = pluginjector(myModule)
const newModule = inject({data: 'abc'})
inject({moreData: 'def'})
assert(newModule.data + newModule.moreData === 'abcdef') // true
Original core is shallow copied to minimize possibility of undesired mutations
let inject = plugininjector({data: 'core module'})
const newModule = inject({data: 'new module'})
inject = pluginjector(myModule)
const anotherNewModule = inject({})
assert(newModule.data === 'new module') // true
assert(anotherNewModule.data === 'core module') // true
Optionally use core module as prototype instead of shallow copy
const inject = pluginjectore(coreModule, {proto: true})
const newModule = inject(plugin)
assert(coreModule.isPrototypeOf(newModule)) // true
More detail to understand handling of this
binding
const myModule = { val: 1 }
const myPlugin = {
// `this` will naturally point to parent module for first layer
// of methods unless you namespace it
method(){ return this.val }
obj1: {
// all methods here will get `this` bound to parent module
pluginjectorBindThis: true, // flag, any truthy value
method(){ return this.val },
method2(){ return this.obj2.val }
},
obj2: {
// no flag, so these will not get special binding
val:2,
method: ()=>{ return this.val }
},
obj3: {
// falsey flag doesn't count
pluginjectorBindThis: false,
val:3,
method: ()=>{ return this.val }
}
}
let newModule = require('pluginjector')(myModule)(myPlugin)
assert(newModule.method() === 1) // true
assert(newModule.obj1.method() === 1) // true
assert(newModule.obj1.method2() === 2) // true
assert(newModule.obj2.method() === 2) // true
assert(newModule.obj3.method() === 3) // true
// with namespace,but no flag, `this` points to `newModule.plugin`
newModule = require('pluginjector')(myModule)({plugin: myPlugin})
assert(newModule.plugin.method() === 1) // false, `this.val` does not exist