http://www.jianshu.com/p/c04dea6e46de

首先有必要解释下什么是命令行(Command Line)类型的模块。
npm的模块一共分为三类:

  1. 绑定型(Binding):本地模块,C++书写,如node-png
  2. 库型(Library):JS书写,直接使用require('module')这种方式,如Socket.IO-node
  3. 命令行型(Command Line): 以命令行形式使用,如json-command

显而易见,提供命令行形式调用方式的模块就属于命令行型的。那么如何来申明自己的模块以什么命令调用,调用执行代码又如何制定呢?

这里就要说到npm模块的核心文件:package.json,此文件是npm模块的配置信息(npm help json可以获取详细信息)。

其中有一个key就叫“bin”,具体形式为“{ "bin": {"command-name" : "command-file"}}”,意思是申明用户可以直接使用“command-name”这个命令,而输入该命令后就会去执行“command-file”这个文件。
比如json-command这个模块,安装好后就可以看到它的package.json文件中bin配置项为“{"bin" : {"json" : "./bin/json.js"}}”。这就申明了命令行名字为“json”,对应地会去执行“bin目录下的json.js”这个文件。

其次还要解释下npm中安装模块的两种模式:

  1. 全局模式: npm -g install module-name,这种模式模块会被安装在node安装记录的lib所在目录的node_modules文件夹中,全局使用
  2. 本地模式: npm install module-name,这种模式模块只会被安装在当前目录的node_modules文件夹中,非全局使用

理解了什么叫“命令行型的模块”和“npm模块的安装模式”之后,再来看看什么叫“npm中本地安装命令行类型的模块是不注册Path的”?
这句话的意思是说:比如像json-command这样的命令行类型的模块,如果是“全局安装”,安装成功之后,就可以直接使用“json”的命令了,而如果是本地模式安装,则没法使用“json”命令。只能手动找到执行文件,然后调用./command-file这样调用。很是不爽!

后来仔细想了下,npm这样设计也是有道理的,因为命令行的模块,通过命令行使用,一般也都会认为是全局的,就像压缩文件,合并文件之类的命令,一般是不会随着应用的发布而发布的,都只是开发过程中的中间工具。所以,npm对这种类型的模块只有当全局安装的时候才会可以直接使用命令。

那么,“npm到底是如何实现全局直接使用,而本地就不能使用的呢?”

通过查看npm的源码,稍作调试就能发现其中的奥妙了:

  • 通过npm的package.json配置文件就能知道npm的命令行入口是“bin/npm.js”
  • npm.js有会去调用“模块根目录的npm.js”,并会调用相关的命令,依据来自如下代码:

    npm = require("../npm");
    npm.load(conf, function (er) {
    if (er) return errorHandler(er)
    npm.commands[npm.command](npm.argv, errorHandler)
    })

    “npm.commands...(npm.argv,errorHandler)”是一行典型的command模式代码,npm.js中的commands对象肯定维护了所有command的列表。依据来自如下代码:

    var cmd = require(__dirname+"/lib/"+a+".js")

    那么install命令就会去调用“lib/install.js”的install方法,install方法会去做一些模块查询,模块依赖关系处理,模块下载,模块安装等工作,之后会去区分本地模式和全局模式,依据来自如下代码:

    var fn = npm.config.get("global") ? installMany : installManyTop

    之后会去调用lib/build.js中的build函数,依据来自于如下代码:

    npm.commands.build([where], false, true, function (er) {
    return cb_(er, d)
    })

    然后,再看看build函数的申明中,其第二个参数正是表示模块是否全局安装,依据来自如下代码:

    function build (args, global, didPre, didRB, cb) {

    最后,global参数被赋予给gtop变量,最后判断是否全局,如果是则注册Path否则直接调用回调函数返回,依据来自如下代码:

    if (er || !gtop) return cb(er)
    var dest = path.resolve(binRoot, b)
    , src = path.resolve(folder, pkg.bin[b])
    , out = npm.config.get("parseable")
    ? dest + "::" + src + ":BINFILE"
    : dest + " -> " + src

    这里很清楚,如果“!gtop”,即本地模式就直接调用cb并返回,否则,就去注册Path,其中“dest->src”会发现很眼熟,通常全局安装好一个命令行模块之后,都会显示这行log。这行代码其实就做了如下这件事情:

  • 将命令执行文件json.js link到node/bin/json命令中
    其中node的bin路径命令已经被加入到PATH中了,这样输入json的时候,系统自动去PATH中查找对应的执行文件,这样就能够找到了!

npm中本地安装命令行类型的模块是不注册Path的的更多相关文章

  1. Vim中常用的命令行

    Vim中常用的命令行... ------------------- 一些真正强大的武器总不是那么容易驾驭的,主角总得付出一些努力才能收获到更加强大的力量,对于 Vim 这种上古神器来说更是如此.由于它 ...

  2. QT中QProcess调用命令行的痛苦经历(调用Winrar,设置工作目录,获得输出,注意引号与括号,等等)

    QT中QProcess调用命令行的痛苦经历   阅读目录 创建压缩包的方法 在QT中调用命令行 在QT中调用C++创建的dll 在QT程序中需要将某些目录和文件压缩为一个rar的压缩包,于是想到了在Q ...

  3. python中处理命令行参数的模块optpars

    optpars是python中用来处理命令行参数的模块,可以自动生成程序的帮助信息,功能强大,易于使用,可以方便的生成标准的,符合Unix/Posix 规范的命令行说明.使用 add_option() ...

  4. Ruby(或cmd中)输入命令行编译sass

    Ruby(或cmd中)输入命令行编译sass步骤如下: 举例: 1.在F盘中新建一个总文件夹,比如test文件夹,其中在该文件夹下面建立html.images.js.sass等文件夹. 2.在sass ...

  5. $命令行参数解析模块argparse的用法

    argparse是python内置的命令行参数解析模块,可以用来为程序配置功能丰富的命令行参数,方便使用,本文总结一下其基本用法. 测试脚本 把以下脚本存在argtest.py文件中: # codin ...

  6. Python命令行参数解析模块getopt使用实例

    Python命令行参数解析模块getopt使用实例 这篇文章主要介绍了Python命令行参数解析模块getopt使用实例,本文讲解了使用语法格式.短选项参数实例.长选项参数实例等内容,需要的朋友可以参 ...

  7. npm install 本地安装与全局安装

    npm的包安装分为本地安装(local).全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已: npm install grunt # 本地安装 npm install -g gr ...

  8. 通过npm写一个cli命令行工具

    前言 如果你想写一个npm插件,如果你想通过命令行来简化自己的操作,如果你也是个懒惰的人,那么这篇文章值得一看. po主的上一篇文章介绍了定制自己的模版,但这样po主还是不满足啊,项目中我们频繁的需要 ...

  9. [转] npm install 本地安装与全局安装的区别

    npm的包安装分为本地安装(local).全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如 npm install grunt # 本地安装 npm install -g  ...

随机推荐

  1. GitHub页面布局乱了,怎么解决??

    GitHub页面布局乱了,怎么解决?? GitHub乱了,怎么解决?? 一年一度的布局又乱了!!! F12一下下面有东西加载不了,,,, Refused to evaluate a string as ...

  2. Java 中equals和==差别

    java中的数据类型,可分为两类:  1.基本数据类型.也称原始数据类型.byte,short,char,int,long,float,double,boolean    他们之间的比較,应用双等号( ...

  3. java数据库编程:JDBC操作及数据库

    掌握JDBC操作步骤, 掌握数据库驱动程序配置 可以使用JDBC进行数据库连接. JDBC本身是一个标准,因此操作步骤是固定的,以后只需要修改很少代码就可以达到不同数据库间连接转换功能. 操作步骤: ...

  4. SpringMVC学习小结

    配置web.xml: <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-cl ...

  5. Grunt快速使用笔记

    本篇文章由:http://xinpure.com/grunt-quick-note/ http://www.gruntjs.net/getting-started Grunt中文网 安装 Grunt ...

  6. django学习笔记【003】创建第一个带有model的app

    [1]python应用程序要连接mysql有多个驱动程序可供选择: 1.MySQLdb 这个只支持python2.x 所以在这里就不说了: 2.mysqlclient 下载地址 https://pyp ...

  7. IIS8.5设置 MVC HTTP 错误 404.0 - Not Found

    0. 确认 设置IIS的“ISAPI和CGI限制”中的“ASP.NET v4.0.0.30319”为允许 1. 解决方案 <system.webServer>    <modules ...

  8. PHP 时间与日期

    PHP提供了大量的内置函数,使开发者在时间的处理上游刃有余,大大提高了工作效率. 介绍一些常见的PHP日期和时间函数以及日期和时间的处理. 经常使用的日期和时间处理函数 函 数 说  明 checkd ...

  9. [k8s]k8s api-server启动systemd参数分析

    默认2个参数就可以启动(必需) kube-apiserver \ --service-cluster-ip-range=10.254.0.0/16 \ --etcd-servers=http://19 ...

  10. Java对象的浅克隆和深克隆

    为什么需要克隆      在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B, 并且此后对B任何改动都不会影响到A中的值 ...