NGN 2.0.0+ can be extended through plugins. A NGN plugin is a JavaScript module which depends on/extends an NGN module (or part of a module) within a system.
In order to create an NGN plugin, a module must have a reference to NGN and any other modules loaded before it. This module provides the references to any instance of NGN available within the JavaScript runtime.
import Reference from 'https://cdn.skypack.dev/@ngnjs/plugin'
// Create a reference to NGN
const NGN = new Reference()
export default class MyPlugin extends NGN.EventEmitter {
constructor () {
super(...arguments)
console.log('Hello')
}
}
NGN.MyPlugin = MyPlugin // Optional
Let's deconstruct the code above.
-
The reference module is imported (i.e. this module). The
Reference
class performs all of the lookups necessary to find NGN, returning a proxy to all of the core NGN modules and any plugins. -
Next, notice the class extends the
NGN.EventEmitter
class, which is a part of the NGN core library. -
Finally, the optional last line exposes the new module to NGN, making it available for use in other modules.
It is also possible to require specific components from an NGN environment, use different versions, & require a minimum version. See the unit tests for working examples.
It is possible to require a specific feature, which includes features added by other plugins.
const NGN = new Reference()
// Does nothing (No-op) since both items existin the NGN core.
NGN.requires('EventEmitter', 'Middleware')
// Throws an error
NGN.requires('DoesNotExist')
NGN references use the npm package nomenclature for defining minimum requirements.
// A specific version
const NGN = new Reference('2.0.0')
// Any version in the 2.x.x range
const NGN = new Reference('^2.0.0')
// Any version in the 2.0.x range
const NGN = new Reference('~2.0.0')
// Anything greater than 2.0.0
const NGN = new Reference('>2.0.0')
// Anything greater than or equal to 2.0.0
const NGN = new Reference('>=2.0.0')
// Anything less than 2.0.0
const NGN = new Reference('<2.0.0')
// Anything less than or equal to 2.0.0
const NGN = new Reference('<=2.0.0')
Plugins can require other plugins, creating a dependency chain. When a required plugin is missing, an error is thrown.
Only plugins that are registered with NGN can be recognized by other plugins. See the last line of the usage example to understand how a plugin can register itself with NGN.
Plugins can be "required" the same way a core NGN element is required:
const NGN = new Reference('^2.0.0').requires('EventEmitter', 'MyPlugin')
If an application needs a specific version of a plugin, it can be required like this:
const NGN = new Reference('^2.0.0').requires('EventEmitter', 'MyPlugin:>=1.0.0')
The code above indicates a MyPlugin
plugin greater than or equal to semantic version 1.0.0
must be present.
Plugins may or may not be versioned. This is a choice for plugin authors, but it is a recommended practice. The plugin system looks for a version
attribute or method on each plugin to determine which version is registered. Here's an example of how a version can be specified on a custom plugin:
import Reference from 'https://cdn.skypack.dev/@ngnjs/plugin'
// Create a reference to NGN
const NGN = new Reference()
export default class MyPlugin extends NGN.EventEmitter {
constructor () {
super(...arguments)
console.log('Hello')
}
static get version () {
return '1.0.1'
}
// Alternative option
// static version () {
// return '1.0.1'
// }
}
NGN.MyPlugin = MyPlugin // Optional
The code above uses a static attribute (or method) to identify the version number. When using classes or class-like structures, it is important to use the static
keyword. This allows the attribute/method to be accessed before the class is instantiated/invoked.
It is possible to use more than one version of NGN if multiple versions are available. Remember, references were introduced in NGN 2.0.0. They are not available in the 1.x.x release line.
const NGN = new Reference()
const CURRENT = NGN.use('2.0.0')
const BETA = NGN.use('2.1.0-beta')
class MyPlugin extends CURRENT.EventEmitter {
...
}
class MyNewPlugin extends BETA.EventEmitter {
...
}
References will always identify plugins within the referenced version of NGN, but sometimes users wish to use the original NGN namespace.
For example:
import NGN from 'https://cdn.skypack.dev/@ngnjs/ngn'
import MyPlugin from 'https://domain.com/plugin/index.js'
console.log(NGN.MyPlugin)
To make this scenario work, the plugin needs to export itself to NGN. This can be done with a named reference:
const NGN = new Reference()
class CustomPlugin extends NGN.EventEmitter {
...
}
NGN.export('MyPlugin', CustomPlugin)