JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 4301
  • Score
    100M100P100Q96082F
  • License MIT

Default to the locally installed version of your CLI, use the global one if not found.

Package Exports

  • fallback-cli

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (fallback-cli) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

fallback-cli Build Status

Default to the locally installed version of your CLI, use the global one if not found.

This allows users to install your tool globally, but revert to whatever version is installed locally in node_modules. npm already handles this when running scripts defined in package.json, but this works even when invoking your CLI command directly from the console.

Install

$ npm install --save fallback-cli

Basic Usage

Let's assume you've created package called my-module, and your CLI is bin/cli.js.

First, create cli-shim.js, and place it in the same folder as your existing cli.js.

bin/cli-shim.js:

#!/usr/bin/env node
require('fallback-cli')('my-module/bin/cli.js');

Next update your package.json to point to cli-shim.js.

{
  "name": "my-module",
  "bin": "bin/cli-shim.js"
}

That's it! Now your globally installed CLI will use the locally installed version. In most cases this will even be backwards compatible with versions before you introduced fallback-cli.

Note: cli.js and cli-shim.js are arbitrary file names, use whatever you wish.

Advanced Usage

Instead of a conventional cli.js, have it export a function:

var minimist = require('minimist'); // or whatever argv processor you prefer
var version = require('./package.json').version;
myCli.version = version;
module.exports = myCli;

function myCli(args) {
  var args = minimist(args);
  // do cool stuff!
}

Similar to above, setup your cli-shim.js:

#!/usr/bin/env node
require('fallback-cli')({
  path: 'my-module/bin/cli.js',
  run: function (location, cli) {
    
    // only necessary if you legacy cli implementations that do not export a function.
    if (typeof cli !== 'function') {
      return; // legacy cli - already executed upon "require"
    }
    
    // run the new cli that does export a function. 
    cli(process.argv.slice(2));
  }
});

A couple key advantages to this approach. First, requiring cli.js no longer has side-effects. Second, you now have a nice hook for testing your cli.

Exporting your package version is not required, but highly recommended. It will allow you to use semver to modify how cli-shim.js runs things in the future.

#!/usr/bin/env node
var shimVersion = require('./package.json').version;
var semver = require('semver');

require('fallback-cli')({
  path: 'my-module/bin/cli.js',
  run: function (location, cli) {
    if (semver.gt(cli.version, shimVersion)) {
      console.log('WARNING: your globally installed version is behind the local one, consider upgrading');
    }
    if (semver.lt(cli.version, '0.2.0') {
      console.log('versions prior to 0.2.0 have a major security vulnerability, aborting');
      process.exit(1);
    }
    cli(process.argv.slice(2));
  }
});

API

fallbackCli(path)

path should be a string describing your packages name, and the path to your CLI implementation (i.e. my-module/bin/my-cli.js).

fallbackCli(path, relativePath)

By default, we expect the "shim" to be installed in the same directory as the actual CLI implementation. If that is not possible, you can use relativePath to describe where it is relative to the shim.

fallbackCli('my-module/bin/the-cli.js', '../bin/the-cli.js');

fallbackCli(options)

options.path

required

Type: string

Same as path described in fallbackCli(path) above.

options.relative

optional

Type: string

Same as relativePath described in fallbackCli(path, relativePath) above.

options.before

optional

Runs before you CLI module is require'd.

Type: callback(location, cliModulePath)

  • location - A string. Will be "local" if there is a version of your CLI installed locally in node-modules. Will be "global" if a local version is not found, and we are falling back to the global one.

  • cliModulePath - A string. The absolute path to the module that will be required.

before can optionally return a result that will be passed to the run callback (described below).

options.require

optional

Allows you to intercept the require of your cliModule.

Type: callback(cliModulePath)

  • cliModulePath - The absolute value of the path to be required.

Return: the result of requiring cliModulePath.

Defaults to using nodes built-inrequire method.

Possible uses might be invoking a preprocessor (i.e. coffescript).

options.run

optional

Used to execute your cli. Run after your CLI module is require'd.

In conventional cases, simply requireing you CLI module will cause it to execute. As described in [Advanced Usage](#Advanced Usage), there are reasons that is undesirable.

Type: callback(location, cliModule, beforeResult)

  • location - A string. Will be "local" if there is a version of your CLI installed locally in node-modules. Will be "global" if a local version is not found, and we are falling back to the global one.

  • cliModule - Whatever value you exported from your actual CLI implementation (probably a function). If you provided a require callback, it will be whatever that result is.

  • beforeResult - Whatever value you returned from your before callback.

looking for options.after?

It doesn't exist. If you need this, use options.run, and pass a callback to your CLI implementation.

Async Operation

By default, the entire process of loading your CLI and executing it happens synchronously. However, both the options.before, and options.require can be made asynchronous.

cli-shim.js:

#!/usr/bin/env node
require('fallback-cli')({
  path: 'my-module/cli',
  before: function () {
    var done = this.async();
    
    // do some stuff asynchronously, then...
    
    done(beforeResult);
  };
});

License

MIT © James Talmage