Bermu

如何做一个类似npm的安装指令?🐯

2018-07-26

npm shell

首先要做一个基本的shell交互命令,基于此进行node项目开发,需要引入一些基础模块。

1
2
3
4
5
6
7
var path = require('path');  //路径中间件
var co = require('co'); //koa 异步控制
var prompt = require('co-prompt'); //接受指令信息
var program = require('commander');
var fs = require('fs-extra');
var shell = require('shelljs');
var jsonFormat = require('json-format');

引入相应的模块之后,我们开始对程序有所定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
program
.version(require('./package.json').version)
.usage('[command][options]')
.option('-d, --description', 'Description of the module.');

program
.command('init')
.description('general package.json')
.option('-y,--yes', 'general package.json without prompt')
.action(init);

program
.command('install [optional...]')
.description('install modules')
.option('-S,--save', 'save modules as dependencies')
.option('-D,--save-dev', 'save modules as dependencies')
.option('-g,--global', 'save modules as global')
.action(install);


program.parse(process.argv);

上面利用了commander插件进行命令行工具的初始化设定,这里预先定义了’init’与’install’命令的声明。


接下来看到函数的具体构造过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
function init(options) {
co(function*() {
var mypackage = {};
var isPromptMode = options.yes ? false : true;
// 默认名称为当前文件夹小写
var _defaultName = path.basename(process.cwd()).toLowerCase();
// 默认入口文件为index.js
var _defaultEntryPoint = 'index.js';
// var jsArr = shell.js('*.js'); 没有js文件时,有额外输出
var jsArr = shell.ls();
// 当前目录下,如果存在js文件,将找到的第一个js文件作为默认值
for (var i = 0; i < jsArr.length; i++) {
if (path.extname(jsArr[i]) === '.js') {
_defaultEntryPoint = jsArr[i];
break;
}
}

var _testCommand = 'echo \"Error: no test specified\" && exit 1';
// 拼接将生成的package.json文件的绝对路径
var mypackagePath = path.resolve(process.cwd(), 'package.json');
var _inputName = '',
_inputVersion = '',
_inputDesc = '',
_inputEntryPoint = '',
_inputTestCommand = '',
_gitRepository = '',
_keywords = '',
_author = '',
_license = '',
_confirm = '';

if (isPromptMode) {
console.log('This utility will walk you through creating a package.json file, can overrides some common params');
_inputName = yield prompt('name: (' + _defaultName + ')');
_inputVersion = yield prompt('version:(1.0.0)');
_inputDesc = yield prompt.multiline('description: ');
_inputEntryPoint = yield prompt('entry point: (' + _defaultEntryPoint + ')');
_inputTestCommand = yield prompt('test command: ');
_gitRepository = yield prompt('git repository: ');
_keywords = yield prompt('keywords: ');
_author = yield prompt('author: ');
_license = yield prompt('license: (MIT) ');
}

// 处理生成package.json信息
mypackage.name = _inputName || _defaultName;
mypackage.version = _inputVersion || '1.0.0';
mypackage.description = _inputDesc || '';
mypackage.main = _inputEntryPoint || _defaultEntryPoint;
mypackage.scripts = {};
mypackage.scripts.test = _inputTestCommand || _testCommand;
if (_gitRepository) {
mypackage.repository = {};
mypackage.repository.type = 'git';
mypackage.repository.url = _gitRepository;
}

mypackage.keywords = _keywords.split(' ') || [];
mypackage.author = _author || '';
mypackage.license = _license || 'ISC';

if (isPromptMode) {
console.log('Aborted');
console.log(jsonFormat(mypackage) + '\n');
_confirm = yield prompt.confirm('Is this ok?(y|n)');
if (!_confirm) {
console.log('Aborted');
process.exit();
}
} else {
console.log('Wrote to ' + mypackagePath + '\n');
console.log(jsonFormat(mypackage) + '\n');
}

// 将信息写入package.json文件
fs.outputJsonSync(mypackagePath, mypackage);
/*确保入口文件存在唯一的npm init方法*/
fs.ensureFileSync(mypackage.main);
process.exit();
});
}

install方法同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function install(optiontag, options) {
var _command = ['npm', 'install'];
_command = _command.concat(optiontag);
if (options.global) {
_command.push('-g');
} else if (options.save) {
ensurePackageJsonExist();
_command.push('--save');
} else if (options.saveDev) {
ensurePackageJsonExist();
_command.push('--save-dev');
}

shell.exec(_command.join(' '), { async: true });
}

function ensurePackageJsonExist() {
if (!fs.existSync(path.join(process.cwd(), 'package.json'))) {
console.log('在当前文件下找不到\"package.json\"文件, 建议先init');
program.help();
}
}

整个流程为定义=>初始化装载=>拼接参数=>指定命令对应关系

即可达到发包时以当前目录为基准的 path –option的命令模式。

Tags: nodejs
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章