Advanced
Plugins API
While Featurevisor CLI is packed with various core functionalities, it also has a plugins API allowing you to extend it with further tooling as per your needs.
CLI#
The entire CLI is built on top of the plugins API. This means that all the core functionalities are implemented as plugins internally.
You can create your own plugins either locally at individual project level, or even share them with others in the form of reusable npm packages.
Installing plugins#
Additional plugins can be installed from npm directly.
$ cd my-featurevisor-project$ npm install --save featurevisor-plugin-example
Plugins can also be created locally without needing any additional npm package or publishing to a central registry.
Registering plugins#
You can register plugins via configuration file found at featurevisor.config.js
:
module.exports = { environments: ['staging', 'production'], tags: ['web', 'mobile'], // register plugins here plugins: [ require('featurevisor-plugin-example'), // require("./plugins/my-local-plugin"), ],}
Running a plugin#
Once registered, you can run the plugin via the CLI:
$ npx featurevisor exampleHello world!
Creating a plugin#
A plugin is a simple JavaScript module that exports an object following below structure:
module.exports = { // this will be made available as "example" command: // // $ npx featurevisor example // command: 'example', // handle the command handler: async function ({ rootDirectoryPath, projectConfig, parsed, datasource, }) { console.log('Hello world!') if (somethingFailed) { return false // this will exit the CLI with an error } }, // self-documenting examples examples: [ { command: 'example', description: 'run the example command', }, { command: 'example --foo=bar', description: 'run the example command with additional options', }, ],}
Using TypeScript#
For type-safety, you can make use of the Plugin
type:
import { Plugin } from '@featurevisor/core'const examplePlugin: Plugin = { command: 'example', handler: async function ({ rootDirectoryPath, projectConfig, parsed, datasource, }) { // handle the command here... }, examples: [ // examples here... ],}export default examplePlugin
Advice for reusable plugins#
Above example shows how to create a simple plugin. However, if you are creating a plugin that you wish to share with others, it's recommended to make it configurable when registering them.
Instead of exporting the plugin object directly from a module, we can export a function that returns the plugin object:
// npm package: featurevisor-plugin-examplemodule.exports = function configureExamplePlugin(options) { // use `options` here as needed // return the plugin object return { command: 'example', handler: async function ({ rootDirectoryPath, projectConfig, parsed, datasource, }) { // ... }, examples: [ // ... ], }}
When registering the plugin, the configuration options can be passed based on project specific needs:
module.exports = { environments: ['staging', 'production'], tags: ['web', 'mobile'], plugins: [ require('featurevisor-plugin-example')({ // custom options here... someProperty: 'some value', }), ],}
Handler options#
rootDirectoryPath#
This is the root directory path of the Featurevisor project where the CLI was executed from.
projectConfig#
This is the fully processed configuration object as found in featurevisor.config.js
file in the root of your Featurevisor project.
For full details of what this object contains, refer to the configuration documentation.
parsed#
This object will contain the parsed command line arguments.
For example, if the command was:
$ npx featurevisor example --foo=bar
Then parsed
object will be:
{ foo: 'bar'}
It uses yargs internally for parsing the command line arguments.
datasource#
Datasource allows reading/writing data from/to the Featurevisor project, so that you don't have to deal with the file system directly.
Read further in datasource documentation.
Here's a quick summary of reading and writing various types of entities using the datasource API:
Revision#
See state files for more details.
const revision = await datasource.readRevision()await datasource.writeRevision(revision + 1)
Features#
See features for more details.
const features = await datasource.listFeatures()const fooFeatureExists = await datasource.featureExists('foo')const fooFeature = await datasource.readFeature('foo')await datasource.writeFeature('foo', { ...fooFeature, ...newData })await datasource.deleteFeature('foo')
Segments#
See segments for more details.
const segments = await datasource.listSegments()const fooSegmentExists = await datasource.segmentExists('foo')const fooSegment = await datasource.readSegment('foo')await datasource.writeSegment('foo', { ...fooSegment, ...newData })await datasource.deleteSegment('foo')
Attributes#
See attributes for more details.
const attributes = await datasource.listAttributes()const fooAttributeExists = await datasource.attributeExists('foo')const fooAttribute = await datasource.readAttribute('foo')await datasource.writeAttribute('foo', { ...fooAttribute, ...newData })await datasource.deleteAttribute('foo')
See more in datasource documentation.