每一个项目的根目录都有一个package.json
文件,定义了这个项目所须要的各类模块,以及项目的配置信息,下面是一个比较完整的package.json文件
vue
{
"name": "vue-cli",
"version": "2.9.3",
"description": "A simple CLI for scaffolding Vue.js projects.",
"preferGlobal": true,
"bin": {
"vue": "bin/vue",
"vue-init": "bin/vue-init",
"vue-list": "bin/vue-list"
},
"repository": {
"type": "",
"url": ""
},
"keywords": [
],
"author": "litongqian",
"license": "MIT",
"bugs": {
"url": ""
},
"homepage": "",
"scripts": {
"test": "npm run lint && npm run e2e",
"start": "node index.js"
},
"dependencies": {
"async": "^2.4.0",
"chalk": "^2.1.0",
},
"devDependencies": {
"chai": "^4.1.2",
"eslint": "^3.19.0",
},
"engines": {
"node": ">=6.0.0"
}
}
复制代码
1. 其中scripts字段
指定了运行脚本命令的npm命令行缩写,好比start指定了运行npm run start
时,所要执行的命令。
node
2. bin字段vue-cli
bin项用来指定各个内部命令对应的可执行文件的位置shell
"bin": {
"vue": "bin/vue",
"vue-init": "bin/vue-init",
"vue-list": "bin/vue-list"
},复制代码
上面代码指定,vue 命令对应的可执行文件为 bin 子目录下的vue。npm
3. npm linkjson
项目目录:数组
本身开发模块的时候,好比上面的mymodule模块,若是想在hello中使用,咱们能够采用相对路径require('./mymodule')
加载模块。bash
也可使用自定义模块标识require('mymodule'),
Node加载自定义模块须要将其安装到全局的或项目的node_modules
目录之中。对于上述模块,解决方法就是在全局的node_modules
目录之中,生成一个符号连接,指向模块的本地目录。async
npm link
就能起到这个做用,会自动创建这个符号连接。函数
mymodule
,目录为hello/mymodule
,你本身的项目要用到这个模块,首先,在模块目录(src/mymodule
)下运行npm link
命令。hello/mymodule$ npm link
复制代码
上面的命令会在NPM的全局模块目录内,生成一个符号连接文件,该文件的名字就是package.json
文件中指定的模块名。
/usr/local/lib/node_modules/mymodule -> /Users/tongqianli/Desktop/work/hello/mymodule复制代码
这个时候,已经可使用mymodule
模块了。
这时能够经过添加path解决:
操做系统中都会有一个PATH
环境变量,系统调用一个命令的时候,就会在PATH变量中注册的路径中寻找,若是注册的路径中有就调用,不然就提示命令没找到。
-> export PATH=$PATH: # 将 /usr/bin 追加到 PATH 变量中
-> export NODE_PATH="/usr/lib/node_modules;/usr/local/lib/node_modules" #指定 NODE_PATH 变量
复制代码
那 NODE_PATH
就是NODE
中用来寻找模块所提供的路径注册环境变量
。咱们可使用上面的方法指定NODE_PATH环境变量。
更好的办法:
切换到项目目录,再次运行npm link
命令,并指定模块名。
hello tongqianli$ npm link mymodule复制代码
上面命令生成了本地node_modules/mymodule模块映射到全局的node_modules/mymodule ,全局,全局的映射到本地hello/mymodule。
/Users/tongqianli/Desktop/work/hello/node_modules/mymodule
-> /usr/local/lib/node_modules/mymodule
-> /Users/tongqianli/Desktop/work/hello/mymodule复制代码
而后,就能够在你的项目中,加载该模块了。
var myModule = require('myModule');
复制代码
这样一来,mymodule
的任何变化,均可以直接反映在项目之中。可是,这样也出现了风险,任何在目录中对mymodule
的修改,都会反映到模块的源码中。
若是你的项目再也不须要该模块,能够在项目目录内使用npm unlink
命令,删除符号连接。
hello tongqianli$ npm unlink mymodule复制代码
写一个简单的脚本hello
$ mkdir
hello
#建立一个文件夹
$
cd
hello && touch
hello #建立命令文件
#!/usr/bin/env node
console.log('hello world');
复制代码
文件的头部加入#!/usr/bin/env node这行代码,这里表示使用node做为脚本的解释程序,能够省略node ./hello,直接运行./hello, node的路径经过env来查找,能够避免node安装的路径不同带来找不到的问题。
打开/usr/bin/env,能够查看到PATH,操做系统经过路径找到node
而后,修改 hello 的权限。
$ chmod 755 hello
$./hello复制代码
若是想把 hello 前面的路径去除,能够将 hello 的路径加入环境变量 PATH。可是,另外一种更好的作法,是在当前目录下新建 package.json ,写入下面的内容。
{
"name": "hello",
"bin": {
"hello": "./hello"
}
}复制代码
而后执行 npm link 命令。不明白的看上面
$ npm link复制代码
执行后会产生一个全局的映射关系,可执行脚本bin/hello映射到全局node_modules/hello/hello,全局的node_modules/hello映射到本地hello,这样就可使用hello了
命令行参数能够用系统变量 process.argv 获取。
修改hello脚本
#!/usr/bin/env node
console.log('hello ', process.argv);复制代码
其中process为node进程中的全局变量,process.argv为一数组,数组内存储着命令行的各个部分,argv[0]为node的安装路径,argv[1]为主模块文件路劲,剩下为子命令或参数,以下:
$ hello a b c
# process.argv的值为[ '/usr/local/bin/node', '/usr/local/bin/hello', 'a', 'b', 'c' ]
|
脚本能够经过 child_process 模块新建子进程,从而执行 Unix 系统命令,修改hello
exec
方法用于执行bash命令,exec
方法最多能够接受两个参数,第一个参数是所要执行的shell命令,第二个参数是回调函数,该函数接受三个参数,分别是发生的错误、标准输出的显示结果、标准错误的显示结果。
#!/usr/bin/env node
var name = process.argv[2];
var exec = require('child_process').exec;
var child = exec('echo hello ' + name, function(err, stdout, stderr) {
if (err) throw err;
console.log(stdout);
});复制代码
执行$ hello litongqian
若是咱们想查看全部文件,修改hello
var name = process.argv[2];
var exec = require('child_process').exec;
var child = exec(name, function(err, stdout, stderr) {
if (err) throw err;
console.log(stdout);
});复制代码
执行$ hello ls
hello目录下有三个文件
shell.js 模块从新包装了 child_process,调用系统命令更加方便。它须要安装后使用。
npm install --save shelljs
复制代码
而后,改写脚本。
#!/usr/bin/env node
var name = process.argv[2];
var shell = require("shelljs");
shell.exec("echo hello " + name);复制代码
shelljs 只解决了如何调用 shell 命令,而 yargs 模块可以解决如何处理命令行参数。它也须要安装。
$ npm install --save yargs
复制代码
yargs 模块提供 argv 对象,用来读取命令行参数。请看改写后的 hello 。
#!/usr/bin/env node
var argv = require('yargs').argv;
console.log('hello ', argv.name);
复制代码
使用时,下面两种用法均可以。
$ hello --name=tom
hello tom
$ hello --name tom
hello tom
复制代码
也就是说,process.argv 的原始返回值以下。
$ node hello --name=tom
[ 'node',
'/usr/local/bin/hell',
'--name=tom' ]
复制代码
yargs 能够上面的结果改成一个对象,每一个参数项就是一个键值对。
经过npm publish进行发布,前提是有npm账号。如何操做能够查看npm 官方文档。
本文是经过原生node.js来开发命令工具,而vue-cli是采用commander.js来简化命令工具开发,
了解了执行流程,学习对应的模块,就能够了!,本文抛个砖头
bin项用来指定各个内部命令对应的可执行文件的位置。
"name":"someTool",
"bin": {
"someTool": "./bin/someTool.js"
}
复制代码
上面代码指定,someTool 命令对应的可执行文件为 bin 子目录下的 someTool.js。
当一个项目依赖上面的someTool工具时,同时只是本地安装
{
"name": "myproject",
"devDependencies": {
"someTool": "latest"
},
"scripts": {
start: 'someTool build' //等同于start: './node_modules/someTool/someTool.js build'
}
}复制代码
npm会寻找这个文件,在node_modules/.bin/
目录下创建符号连接。在上面的例子中,someTool.js会创建符号连接npm_modules/.bin/someTool
。因为node_modules/.bin/
目录会在运行时加入系统的PATH变量,所以在运行npm时,就能够不带路径,直接经过命令来调用这些脚本。
所以,像上面这样的写法能够采用简写。
scripts: {
start: './node_modules/someTool/someTool.js build'
}
// 简写为
scripts: {
start: 'someTool build'
}
复制代码
全部node_modules/.bin/
目录下的命令,均可以用npm run [命令]
的格式运行。在命令行下,键入npm run
,而后按tab键,就会显示全部可使用的命令。
上面代码中,scripts
字段指定了两项命令
npm run-script start
或者
npm run start
,就会执行
someTool build。
npm run
是
npm run-script
的缩写,通常都使用前者,可是后者能够更好地反应这个命令的本质。
npm run
命令会自动在环境变量$PATH
添加node_modules/.bin
目录,因此scripts
字段里面调用命令时不用加上路径,这就避免了全局安装NPM模块。
npm run
若是不加任何参数,直接运行,会列出package.json
里面全部能够执行的脚本命令。
npm内置了两个命令简写,npm test
等同于执行npm run test
,npm start
等同于执行npm run start
。
npm run
会建立一个Shell,执行指定的命令,并临时将node_modules/.bin
加入PATH变量,这意味着本地模块能够直接运行。
举例来讲,你执行ESLint的安装命令。
$ npm i eslint --save-dev
复制代码
运行上面的命令之后,会产生两个结果。首先,ESLint被安装到当前目录的node_modules
子目录;其次,node_modules/.bin
目录会生成一个符号连接node_modules/.bin/eslint
,指向ESLint模块的可执行脚本。
而后,你就能够在package.json
的script
属性里面,不带路径的引用eslint
这个脚本。
{
"name": "Test Project",
"devDependencies": {
"eslint": "^1.10.3"
},
"scripts": {
"lint": "eslint ."
}
}
复制代码
等到运行npm run lint
的时候,它会自动执行./node_modules/.bin/eslint .
。
若是直接运行npm run
不给出任何参数,就会列出scripts
属性下全部命令。
$ npm run
Available scripts in the user-service package:
lint
jshint **.js
test
mocha test/复制代码