node-liftoff 更简单地创建命令行工具

发布于 2021-08-07 10:50:49 字数 14131 浏览 1184 评论 0

它是什么?

请参阅此博客文章查看此概念证明,或继续阅读。

假设您正在编写 CLI 工具。我们称之为 hacker。您想使用 Hackerfile. 这是节点,因此您 hacker 为使用它的每个项目在本地安装。但是,为了 hacker 在 PATH 中获取命令,您还需要全局安装它。

现在,当您运行 hacker 时 ,您希望使用 Hackerfile 当前目录中的配置它的功能,并希望它使用工具的本地安装来执行。此外,如果该 hacker 命令足够智能,可以遍历您的文件夹,直到找到 Hackerfile- 对于您不在项目根目录中的那些时间,那就太好了。哎呀,您甚至可能希望 hacker 通过手动指定工作目录从项目外部的文件夹启动。Liftoff 为您管理这些。

所以,一切都很好。现在,你可以找到你的本地 hackerHackerfile 轻松。不幸的是,事实证明您已经编写 Hackerfile 了咖啡脚本或其他一些 JS 变体。为了支持,你必须为它加载编译器,然后用 node.js 注册它的扩展。好消息,Liftoff 可以做到这一点,而且还有更多。

应用程序接口

constructor(opts)

创建一个 Liftoff 实例来调用您的应用程序。

使用所有选项的示例:

const  Hacker  =  new  Liftoff ( { 
  name : 'hacker' , 
  processTitle : 'hacker' , 
  moduleName : 'hacker' , 
  configName : 'hackerfile' , 
  extensions : { 
    '.js' : null , 
    '.json' : null , 
    '. coffee' : 'coffee-script/register' 
  } , 
  v8flags : [ ' --harmony ' ]  // 或 v8flags: require('v8flags') 
} );

选项名称

糖用于设置processTitle, moduleName,configName自动。

类型:String
默认:null

这些是等效的:

const  Hacker  =  Liftoff ( { 
  processTitle : 'hacker' , 
  moduleName : 'hacker' , 
  configName : 'hackerfile' 
} ) ;
const  Hacker  =  Liftoff ( { name : 'hacker' } ) ;

opts.moduleName

设置您的应用程序在运行时希望在本地找到哪个模块。

类型:String
默认:null

opts.configName

设置 Liftoff 将尝试查找的配置文件的名称。不区分大小写。

类型:String
默认:null

opts.extensions

在搜索配置文件时设置要包含的扩展名。如果需要外部模块来加载给定的扩展(例如.coffee),则应将模块名称指定为键的值。

类型:Object
默认:{".js":null,".json":null}

例子:

在这个例子中,Liftoff 将寻找myappfile{.js,.json,.coffee}. 如果.coffee找到带有扩展名的配置,Liftoff 将尝试coffee-script/require从当前工作目录中获取。

const MyApp = new Liftoff({
  name: 'myapp',
  extensions: {
    '.js': null,
    '.json': null,
    '.coffee': 'coffee-script/register'
  }
});

在这个例子中,Liftoff 将寻找.myapp{rc}.

const MyApp = new Liftoff({
  name: 'myapp',
  configName: '.myapp',
  extensions: {
    'rc': null
  }
});

在此示例中,Liftoff 将自动尝试为 interpret 支持的任何 javascript 变体加载正确的模块(只要它不需要注册方法)。

const MyApp = new Liftoff({
  name: 'myapp',
  extensions: require('interpret').jsVariants
});

opts.v8flags

此处指定的任何标志都将应用于节点,而不是您的程序。用于支持诸如myapp --harmony command, where--harmony应该传递给节点而不是您的程序的调用。此功能是使用flagged-respawn 实现的。要支持所有 v8flags,请参阅v8flags

类型:Array|Function
默认:null

如果这个方法是一个函数,它应该采用一个节点风格的回调来产生一个标志数组。

opts.processTitle

设置进程标题是什么。

类型:String
默认:null

opts.completions(类型)

一种处理 bash/zsh/任何完成的方法。

类型:Function
默认:null

opts.config 文件

要查找的配置文件对象。每个属性都以所找到文件的默认基本名称为键,值是一个以唯一名称为键的路径参数对象。

注意:此选项很有用,例如,如果.apprc除了appfile.js. 如果你只需要一个配置文件,你可能不需要这个。除了让您找到多个文件之外,此选项还允许对配置文件的位置进行更细粒度的控制。

类型:Object
默认:null

路径参数

fined模块接受表示搜索路径的字符串或具有以下键的对象:

  • path (必需的)要搜索的路径。仅使用字符串扩展到此属性。类型:String
    默认:null
  • name要查找的文件的基本名称。在查找期间附加扩展名。类型:String
    默认:顶级键入configFiles
  • extensionsname在查找期间附加到的扩展名。另见:opts.extensions。类型:String|Array|Object
    默认值:opts.extensions
  • cwd的基本目录path(如果是相对的)。类型:String
    默认值:opts.cwd
  • findUp是否path应该向上遍历以查找文件。类型:Boolean
    默认:false

例子:

在这个例子中,Liftoff 将寻找.hacker.js相对于cwd中声明的文件configFiles

const  MyApp  =  new  Liftoff ( { 
  name : 'hacker' , 
  configFiles : { 
    '.hacker' : { 
      cwd : '.' 
    } 
  } 
} ) ;

在本例中,Liftoff 将.hackerrc在主目录中查找。

const  MyApp  =  new  Liftoff ( { 
  name : 'hacker' , 
  configFiles : { 
    '.hacker' : { 
      home : { 
        path : '~' , 
        extensions : { 
          'rc' : null 
        } 
      } 
    } 
  } 
} ) ;

在这个例子中,Liftoff 将在 cwd 中查找,然后在树中查找 .hacker.js 文件。

const MyApp = new Liftoff({
  name: 'hacker',
  configFiles: {
    '.hacker': {
      up: {
        path: '.',
        findUp: true
      }
    }
  }
});

在这个例子中,name被覆盖,键被忽略,所以 Liftoff 寻找.override.js

const  MyApp  =  new  Liftoff ( { 
  name : 'hacker' , 
  configFiles : { 
    hacker : { 
      override : { 
        path : '.' , 
        name : '.override' 
      } 
    } 
  } 
} ) ;

在本例中,Liftoff 将使用主目录作为cwd并查找~/.hacker.js.

const  MyApp  =  new  Liftoff( { 
  name : 'hacker' , 
  configFiles : { 
    '.hacker' : { 
      home : { 
        path : '.' , 
        cwd : '~' 
      } 
    } 
  } 
} ) ;

prepare(opts, callback(env))

使用提供的选项为您的应用程序准备环境,并使用计算的环境作为第一个参数调用您的回调。可以在将环境用作 的第一个参数之前修改环境execute

带有选项解析的示例配置:

const Liftoff = require('liftoff');
const MyApp = new Liftoff({name:'myapp'});
const argv = require('minimist')(process.argv.slice(2));
const onExecute = function (env, argv) {
  // Do post-execute things
};
const onPrepare = function (env) {
  console.log('my environment is:', env);
  console.log('my liftoff config is:', this);
  MyApp.execute(env, onExecute);
};
MyApp.prepare({
  cwd: argv.cwd,
  configPath: argv.myappfile,
  preload: argv.preload,
  completion: argv.completion
}, onPrepare);

带有修改环境的示例

const Liftoff = require('liftoff');
const Hacker = new Liftoff({
  name: 'hacker',
  configFiles: {
    '.hacker': {
      home: { path: '.', cwd: '~' }
    }
  }
});
const onExecute = function (env, argv) {
  // Do post-execute things
};
const onPrepare = function (env) {
   env.configProps = ['home', 'cwd'].map(function(dirname) {
    return env.configFiles['.hacker'][dirname]
  }).filter(function(filePath) {
    return Boolean(filePath);
  }).reduce(function(config, filePath) {
    return mergeDeep(config, require(filePath));
  }, {});

  if (env.configProps.hackerfile) {
    env.configPath = path.resolve(env.configProps.hackerfile);
    env.configBase = path.dirname(env.configPath);
  }

  Hacker.execute(env, onExecute);
};
Hacker.prepare({}, onPrepare);

opts.cwd

更改此启动的当前工作目录。相对路径是针对 计算的process.cwd()

类型:String
默认:process.cwd()

示例配置:

const argv = require('minimist')(process.argv.slice(2));
MyApp.launch({
  cwd: argv.cwd
}, invoke);

匹配 CLI 调用:

myapp --cwd ../

opts.configPath

不要搜索配置,使用提供的配置。注意: Liftoff 将假定当前工作目录是包含配置文件的目录,除非使用cwd.

类型:String
默认:null

示例配置:

var argv = require('minimist')(process.argv.slice(2));
MyApp.launch({
  configPath: argv.myappfile
}, invoke);

匹配 CLI 调用:

myapp --myappfile /var/www/project/Myappfile.js

使用cwdconfigPath一起使用的示例:

这些在功能上是相同的:

myapp --myappfile /var/www/project/Myappfile.js
myapp --cwd /var/www/project

这些可以从共享目录运行 myapp,就好像它位于另一个项目中一样:

myapp --myappfile /Users/name/Myappfile.js --cwd /var/www/project1
myapp --myappfile /Users/name/Myappfile.js --cwd /var/www/project2

预加载

在调用启动回调之前尝试从本地工作目录请求的字符串或模块数组。

类型:String|Array
默认:null

示例配置:

var argv = require('minimist')(process.argv.slice(2));
MyApp.launch({
  preload: argv.preload
}, invoke);

匹配 CLI 调用:

myapp --preload coffee-script/register

callback(env)

在您的环境准备好后调用的函数。在调用之前修改环境的好地方execute。调用时,this将是您的 Liftoff 实例。该env参数将包含以下键:

  • cwd: 当前工作目录
  • preload:一系列升空尝试预加载的模块
  • configNameSearch: 搜索的配置文件
  • configPath:配置文件的完整路径(如果找到)
  • configBase:配置文件的基本目录(如果找到)
  • modulePath:您的项目所依赖的本地模块的完整路径(如果找到)
  • modulePackage:本地模块的 package.json 的内容(如果找到)
  • configFiles:每个找到的配置文件的文件路径对象(如果找不到,文件路径值将为空)

execute(env, [forcedFlags], callback(env, argv))

基于env给定的启动应用程序的函数。可选地采用 的数组forcedFlags,这将在启动期间强制使用这些节点或 V8 标志重新生成。在应用程序执行后,使用环境和命令行参数(减去节点和 v8 标志)调用您的回调。

例子:

const Liftoff = require('liftoff');
const MyApp = new Liftoff({name:'myapp'});
const onExecute = function (env, argv) {
  // Do post-execute things
  console.log('my environment is:', env);
  console.log('my cli options are:', argv);
  console.log('my liftoff config is:', this);
};
const onPrepare = function (env) {
  var forcedFlags = ['--trace-deprecation'];
  MyApp.execute(env, forcedFlags, onExecute);
};
MyApp.prepare({}, onPrepare);

callback(env, argv)

在您的应用程序执行后调用的函数。调用时,this将是您的 Liftoff 实例,argv将是所有命令行参数(减去节点和 v8 标志),env并将包含以下键:

  • cwd: 当前工作目录
  • preload:一系列升空尝试预加载的模块
  • configNameSearch: 搜索的配置文件
  • configPath:配置文件的完整路径(如果找到)
  • configBase:配置文件的基本目录(如果找到)
  • modulePath:您的项目所依赖的本地模块的完整路径(如果找到)
  • modulePackage:本地模块的 package.json 的内容(如果找到)
  • configFiles:每个找到的配置文件的文件路径对象(如果找不到,文件路径值将为空)

events

on('preload:before', function(name) {})

在预加载模块之前发出。(但仅适用于由 指定的模块 opts.preload)。

var Hacker = new Liftoff({name:'hacker', preload:'coffee-script'});
Hacker.on('preload:before', function (name) {
  console.log('Requiring external module: '+name+'...');
});

on('preload:success', function(name, module) {})

当模块被预加载时发出。

var Hacker = new Liftoff({name:'hacker'});
Hacker.on('preload:success', function (name, module) {
  console.log('Required external module: '+name+'...');
  // automatically register coffee-script extensions
  if (name === 'coffee-script') {
    module.register();
  }
});

on('preload:failure', function(name, err) {})

当请求的模块无法预加载时发出。

var Hacker = new Liftoff({name:'hacker'});
Hacker.on('preload:failure', function (name, err) {
  console.log('Unable to load:', name, err);
});

on('loader:success, function(name, module) {})

当加载了与扩展匹配的加载器时发出。

var Hacker = new Liftoff({
  name: 'hacker',
  extensions: {
    '.ts': 'ts-node/register'
  }
});
Hacker.on('loader:success', function (name, module) {
  console.log('Required external module: '+name+'...');
});

on('loader:failure', function(name, err) {})

当无法加载扩展的加载器时发出。为每个失败的加载器发出一个错误。

var Hacker = new Liftoff({
  name: 'hacker',
  extensions: {
    '.ts': 'ts-node/register'
  }
});
Hacker.on('loader:failure', function (name, err) {
  console.log('Unable to load:', name, err);
});

on('respawn', function(flags, child) {})

当 Liftoff 重新生成您的进程时发出(当一个 v8flags 被检测到)。

var Hacker = new Liftoff({
  name: 'hacker',
  v8flags: ['--harmony']
});
Hacker.on('respawn', function (flags, child) {
  console.log('Detected node flags:', flags);
  console.log('Respawned to PID:', child.pid);
});

此命令将触发事件: hacker --harmony commmand

例子

看看如何 gulp 使用起飞。

对于一个简单的例子,试试 hacker project

要尝试该示例,请执行以下操作:

  1. 安装示例项目hackernpm install -g hacker
  2. Hackerfile.js用一些任意的 javascript做一个吧。
  3. 在它旁边安装黑客npm install hacker
  4. 运行hacker,而在同一个父文件夹。

项目地址:https://github.com/js-cli/js-liftoff

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

漫雪独思

文章 0 评论 0

垂暮老矣

文章 0 评论 0

鹊巢

文章 0 评论 0

萌酱

文章 0 评论 0

雨说

文章 0 评论 0

冰葑

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文