通过分析grunt,了解基于nodejs开发一些命令行工具,比如fis,spm、doxmate等等
我们打开grunt的官网:http://gruntjs.com/getting-started,看到有一句命令
npm install -g grunt-cli
很多工具的安装基本上都是这样的命令,比如fis的安装,等等
npm install -g fis
当运行这个命令的时候,到底发生什么呢,其实这个要看npm里面的代码是怎么写的(这个另开专题说明,不在此文章之内),先看整体的,我们 在cmd命令工具中输入npm config list的时候,看到下面的信息
看红色的那块,这就是我们通过-g的方式安装的时候,都会安装到次目录当中,至于更多的npm命令可以查过我的blog的一篇文章
http://303182519.github.io/nodejs/2014/02/11/npm.html
我们打开grunt的github源码地址:
https://github.com/gruntjs/grunt-cli
可以看到有一个叫package.json的文件,打开看看,这是一个nodejs包的说明,其他的项目我就不说了,挑几个重点的,看注释
{
"name": "grunt-cli",
"description": "The grunt command line interface.",
"version": "0.1.13",
"author": "Grunt Team",
"homepage": "http://gruntjs.com/",
"repository": {
"type": "git",
"url": "git://github.com/gruntjs/grunt-cli.git"
},
"bugs": {
"url": "http://github.com/gruntjs/grunt-cli/issues"
},
"licenses": [
{
"type": "MIT",
"url": "http://github.com/gruntjs/grunt-cli/blob/master/LICENSE-MIT"
}
],
"bin": { //这是命令行
"grunt": "bin/grunt"
},
"engines": {
"node": ">= 0.8.0"
},
"scripts": {
"test": "node bin/grunt test"
},
"preferGlobal": true,
"dependencies": { //这是依赖包,会随着这行的命令行 npm install -g grunt-cli 一起下载的包
"nopt": "~1.0.10",
"findup-sync": "~0.1.0",
"resolve": "~0.3.1"
},
"devDependencies": { //这是做grunt这个工具用到的一个测试工具
"grunt": "~0.4.0",
"grunt-contrib-jshint": "~0.2.0"
}
}
当我们输入npm install -g grunt-cli 的时候,npm就会分析这个package.json里面的一个bin和dependencies,根据bin的内容生成两个文件在你的系统上,文件存放的路径请看上面的npm config list里面的prefix。一个是给linux系统,一个是给window系统用的,我们用编辑器打开cmd后缀的文件
:: Created by npm, please don't edit manually.
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\node_modules\grunt-cli\bin\grunt" %*
) ELSE (
node "%~dp0\node_modules\grunt-cli\bin\grunt" %*
)
大概的意思就是,这个文件是npm生成的,请不要手动编辑他。判断里面当前目录有没有node.exe,没有的话,就直接通过node命令运行当前目录下的\node_modules\grunt-cli\bin\grunt
其实也就是相当于通过node xx.js运行一个js,只是这里用npm包装了一层。
而依赖包dependencies就会安装到grunt-cli下的一个node_modules下。
而至于为什么我们能通过grunt命令运行当前目录的东西,是因为我们之前安装npm的时候,向我们的环境变量里填加了当前的路径
这里面基本上都是js代码了
//在Linux系统下,我们可以把JS文件当作shell脚本来运行
#!/usr/bin/env node
'use strict';
process.title = 'grunt';
// Especially badass external libs.
var findup = require('findup-sync');
var resolve = require('resolve').sync;
// Internal libs.
var options = require('../lib/cli').options;
var completion = require('../lib/completion');
var info = require('../lib/info');
var path = require('path');
//获取当前进程的工作目录
var basedir = process.cwd();
var gruntpath;
// Do stuff based on CLI options.
if ('completion' in options) {
completion.print(options.completion);
} else if (options.version) {
info.version();
} else if (options.gruntfile) { //Note: if both `gruntfile` and `base` are set, use `gruntfile`
basedir = path.resolve(path.dirname(options.gruntfile));
} else if (options.base) {
basedir = path.resolve(options.base);
}
try {
//返回当前目录的grunt文件的路径
gruntpath = resolve('grunt', {basedir: basedir});
} catch (ex) {
gruntpath = findup('lib/grunt.js');
// No grunt install found!
if (!gruntpath) {
if (options.version) { process.exit(); }
if (options.help) { info.help(); }
info.fatal('Unable to find local grunt.', 99);
}
}
//运行
// Everything looks good. Require local grunt and run it.
require(gruntpath).cli();
沙发是我的