codecamp

NodeJS模块全面指南

大纲
  1. 1. NodeJS模块
    1. 1.1. 什么是NodeJS模块?
    2. 1.2. NodeJS包和模块
  2. 2. npm包管理器
    1. 2.1. 创建包
    2. 2.2. 导出包接口
    3. 2.3. 发布包
    4. 2.4. 额外的问题
  3. 3. 创建命令行工具包
    1. 3.1. 添加bin字段
    2. 3.2. 命令行参数的解析
  4. 4. 参考示例
  5. 5. 参考列表

NodeJS模块

所谓的NodeJS模块其实就是指NodeJS package,即nodejs包。

在使用NodeJS进行开发的时候,往往需要用到各种各样的第三方包。当然,很多时候我们在实际开发的时候自己也会按照功能或者需求来封装一个本地的包。

那么问题来了,NodeJS模块究竟是什么?

什么是NodeJS模块?

在说这个问题之前,我们有必要先提出一个概念,即模块规范。关于模块规范可以参与之前的这篇文章从CommonJS到Sea.js

所以,现阶段Javascript领域大体上有三种比较流行的模块规范,一种是AMD规范,一种是CMD规范,还有一种就是CommonJS规范。NodeJS采用的规范就是CommonJS规范。这三种规范中,前两者专注于客户端,即浏览器端的规范标准,而后者而其实是服务器端的规范。

CommonJS规范说,一个单独的文件其实就是一个模块。在NodeJS中,一个模块可以是一个单独的文件,也可以是一个包含多个文件(子模块)的目录。与此同时,CommonJS规范还要求模块都采用统一的格式exports或者module.exports导出模块接口。

NodeJS包和模块

上面我们已经知道了模块的概念,那么包其实就是包含多个模块目录。同时,还要附加一个重要的package.json文件。那么这个package.json文件是个什么情况呢?如下图,

这个json文件可以配置的很简略,也可以配置的很复杂。关于各个字段的具体含义可以参阅官方文档或者汉化文档

其实package.json就是用来声明NodeJS包的,包括包名字,版本,作者,包入口信息,依赖等信息。

其中有两个字段这里稍微提一下,dependenciesdevDependencies字段。前者表明包在生产环境需要的第三方依赖,而后者表明包在开发阶段所需要的第三方依赖(比如构建、测试等第三方包等)。

npm包管理器

NPM是NodeJS包管理器,可以看成类似Java中的Maven或者Ruby中gem。

现在的npm是在最初的版本上改版而来的,界面更好看了,对包信息的展示更加人性化了。而且目前除了用于面向普通开发者提供服务之外,还提供私有包仓库和企业级包仓库。听说马上再一次改版的npm3.0也要到来了,提供了众多的优化和新特性,详情请参阅这篇文章

创建包

前面我们说package.json是NodeJS包的标识或者说配置文件。所以,任何一个NodeJS包都是从新建package.json文件开始的。

这里我们一般不会傻傻的手动去新建一个package.json文件,而是通过npm工具来生成。


$ cd YOUR_PROJECT_DIR
$ npm init

在命令行中键入npm init后,CLI将会出现一些互动的提示来引导你完成package.json的生成。如下图,

当然CLI只会询问你一些package.json文件必须的字段,而且它会智能的给出一些默认值(括号中的内容),最后它会向你确认是否可行。

package.json中有一个字段为main,此字段为意为包的入口。如果留空的话,NodeJS会默认将包目录下的index.js作为入口文件。

导出包接口

NodeJS模块使用的是CommonJS规范,使用exports或者module.exports导出模块准备暴露的接口。比如,


exports.sayHello = function() {
    // your code
};
exports.sayGoodbye = function() {
    // your code
};

或者,


module.exports = function People() {
    // your code
};

那么,exportsmodule.exports这两种方式到底有什么区别呢?

其实在NodeJS内部,模块真正返回的是module.exports对象,而exports只是module.exports的引用而已。如下,


exports = module.exports = {};

如果你直接赋值一个函数(function)或者一个对象({})给exports,这样的话就破坏了exportsmodule.exports的引用关系了,而模块将会返回空对象。所以当我们需要暴露一个函数或者一个对象时,应该直接赋值给module.exports而不是exports

本博客前面有一篇文章如何导出NodeJS模块就是阐述NodeJS如何返回接口的。

发布包

好了,在我们完成模块的编写之后。我们希望将自己的包发布到NPM上,成就自己的同时又方便他人。该怎么做呢?

其实很简单。npm同样提供了相应的接口,npm addusernpm publish


$ npm adduser

npm会向你索要npmjs.com用户名,密码以及Email。如果没有问题,接下来就可以执行npm publish了。

这里提一下执行npm publish时经常会遇到的两个问题。

第一,提示你没有权限发布。这种情况往往是你的包名已经在npm仓库中被占用了。所以这种情况你需要给你的包换个名字。
第二,提示你必须更新版本。这种情况一般是你是在本地更新了包,然后想更新npm仓库时却出现了这种错误。造成这个错误的原因其实很简单,因为已经发布在npm仓库中的包不允许不改变版本号的情况下就改变包代码。所以这种情况你需要改动package.json中的version字段。

额外的问题

我们说整个NodeJS社区都是一片欣欣向荣的景象,npm仓库的包数量很多,社区也很活跃。这些都是好现象,而且我个人也非常看好NodeJS在未来的发展。

但是,就我个人使用NodeJS的经验,遇到两个可能存在一些隐患的地方。

第一,npm仓库上的第三方包质量参差不齐,有的包基本就是垃圾,给使用者可能会造成一些损失。
第二,有些第三方包本身升级了,但是其周边插件包的更新却跟不上,有时候你为了向插件包妥协,不得不放弃新版本而使用低版本。
第三,因为第三方包是可以直接在服务器端运行的,有时候可能需要考虑一些安全因素。

创建命令行工具包

通过npm install -g xxx命令安装的部分第三方包后,就可以直接在命令行上运行相关命令了。比如下图,

这种效果是如何做的呢?

添加bin字段

我们可以在package.json文件中添加一个叫做bin的字段。比如,npm cli中就是这样的,


{
    "bin": {
        "npm" : "./cli.js"
    }
}

然后你在命令行中输入npm,NodeJS就会去执行对应的NodeJS模块。

如果你只有一个可执行命令,并且还和包名一致,那么package.json中你可以这么写,


{
    "name": "my-package",
    "version": "1.2.5",
    "bin": "./bin/my-package"
}

然后,你需要在bin/my-package文件的第一行添加如下代码,


#!/usr/bin/env node

命令行参数的解析

我们通过命令行使用部分第三方包时,有时候包会提供各种命令和参数,如下图,

从图中可以看出,这个harp提供四个命令以及两个参数,并且简略的展示了Usage。

那么这种比较完备的命令行包是如何做的呢?

这里我们一般会有两个方案去做成这件事,第一就是使用原生的progress.argv来解析,另一种方案就是使用commander.js。后面我会专门写篇文章来阐述commander.js的用法。

参考示例

bullhead是作者随便写的一个小玩意儿,主要目的是用来联系npm包创建及发布等操作。有兴趣可以参考。

参考列表



gulp vs. grunt
Express4入门指南
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }