所謂的NodeJS模塊其實就是指NodeJS package,即nodejs包。
在使用NodeJS進行開發(fā)的時候,往往需要用到各種各樣的第三方包。當然,很多時候我們在實際開發(fā)的時候自己也會按照功能或者需求來封裝一個本地的包。
那么問題來了,NodeJS模塊究竟是什么?
在說這個問題之前,我們有必要先提出一個概念,即模塊規(guī)范。關于模塊規(guī)范可以參與之前的這篇文章從CommonJS到Sea.js。
所以,現(xiàn)階段Javascript領域大體上有三種比較流行的模塊規(guī)范,一種是AMD規(guī)范,一種是CMD規(guī)范,還有一種就是CommonJS規(guī)范。NodeJS采用的規(guī)范就是CommonJS規(guī)范。這三種規(guī)范中,前兩者專注于客戶端,即瀏覽器端的規(guī)范標準,而后者而其實是服務器端的規(guī)范。
CommonJS規(guī)范說,一個單獨的文件其實就是一個模塊。在NodeJS中,一個模塊可以是一個單獨的文件,也可以是一個包含多個文件(子模塊)的目錄。與此同時,CommonJS規(guī)范還要求模塊都采用統(tǒng)一的格式exports
或者module.exports
導出模塊接口。
上面我們已經知道了模塊的概念,那么包其實就是包含多個模塊目錄。同時,還要附加一個重要的package.json
文件。那么這個package.json
文件是個什么情況呢?如下圖,
這個json文件可以配置的很簡略,也可以配置的很復雜。關于各個字段的具體含義可以參閱官方文檔或者漢化文檔。
其實package.json
就是用來聲明NodeJS包的,包括包名字,版本,作者,包入口信息,依賴等信息。
其中有兩個字段這里稍微提一下,dependencies
和devDependencies
字段。前者表明包在生產環(huán)境需要的第三方依賴,而后者表明包在開發(fā)階段所需要的第三方依賴(比如構建、測試等第三方包等)。
NPM是NodeJS包管理器,可以看成類似Java中的Maven或者Ruby中gem。
現(xiàn)在的npm是在最初的版本上改版而來的,界面更好看了,對包信息的展示更加人性化了。而且目前除了用于面向普通開發(fā)者提供服務之外,還提供私有包倉庫和企業(yè)級包倉庫。聽說馬上再一次改版的npm3.0也要到來了,提供了眾多的優(yōu)化和新特性,詳情請參閱這篇文章。
前面我們說package.json
是NodeJS包的標識或者說配置文件。所以,任何一個NodeJS包都是從新建package.json
文件開始的。
這里我們一般不會傻傻的手動去新建一個package.json
文件,而是通過npm工具來生成。
$ cd YOUR_PROJECT_DIR
$ npm init
在命令行中鍵入npm init
后,CLI將會出現(xiàn)一些互動的提示來引導你完成package.json
的生成。如下圖,
當然CLI只會詢問你一些package.json
文件必須的字段,而且它會智能的給出一些默認值(括號中的內容),最后它會向你確認是否可行。
package.json
中有一個字段為main
,此字段為意為包的入口。如果留空的話,NodeJS會默認將包目錄下的index.js
作為入口文件。
NodeJS模塊使用的是CommonJS規(guī)范,使用exports
或者module.exports
導出模塊準備暴露的接口。比如,
exports.sayHello = function() {
// your code
};
exports.sayGoodbye = function() {
// your code
};
或者,
module.exports = function People() {
// your code
};
那么,exports
和module.exports
這兩種方式到底有什么區(qū)別呢?
其實在NodeJS內部,模塊真正返回的是module.exports
對象,而exports
只是module.exports
的引用而已。如下,
exports = module.exports = {};
如果你直接賦值一個函數(shù)(function
)或者一個對象({}
)給exports
,這樣的話就破壞了exports
和module.exports
的引用關系了,而模塊將會返回空對象。所以當我們需要暴露一個函數(shù)或者一個對象時,應該直接賦值給module.exports
而不是exports
。
本博客前面有一篇文章如何導出NodeJS模塊就是闡述NodeJS如何返回接口的。
好了,在我們完成模塊的編寫之后。我們希望將自己的包發(fā)布到NPM上,成就自己的同時又方便他人。該怎么做呢?
其實很簡單。npm同樣提供了相應的接口,npm adduser和npm publish。
$ npm adduser
npm會向你索要npmjs.com用戶名,密碼以及Email。如果沒有問題,接下來就可以執(zhí)行npm publish
了。
這里提一下執(zhí)行npm publish
時經常會遇到的兩個問題。
第一,提示你沒有權限發(fā)布。這種情況往往是你的包名已經在npm倉庫中被占用了。所以這種情況你需要給你的包換個名字。
第二,提示你必須更新版本。這種情況一般是你是在本地更新了包,然后想更新npm倉庫時卻出現(xiàn)了這種錯誤。造成這個錯誤的原因其實很簡單,因為已經發(fā)布在npm倉庫中的包不允許不改變版本號的情況下就改變包代碼。所以這種情況你需要改動package.json
中的version
字段。
我們說整個NodeJS社區(qū)都是一片欣欣向榮的景象,npm倉庫的包數(shù)量很多,社區(qū)也很活躍。這些都是好現(xiàn)象,而且我個人也非??春肗odeJS在未來的發(fā)展。
但是,就我個人使用NodeJS的經驗,遇到兩個可能存在一些隱患的地方。
第一,npm倉庫上的第三方包質量參差不齊,有的包基本就是垃圾,給使用者可能會造成一些損失。
第二,有些第三方包本身升級了,但是其周邊插件包的更新卻跟不上,有時候你為了向插件包妥協(xié),不得不放棄新版本而使用低版本。
第三,因為第三方包是可以直接在服務器端運行的,有時候可能需要考慮一些安全因素。
通過npm install -g xxx
命令安裝的部分第三方包后,就可以直接在命令行上運行相關命令了。比如下圖,
這種效果是如何做的呢?
bin
字段我們可以在package.json
文件中添加一個叫做bin
的字段。比如,npm cli中就是這樣的,
{
"bin": {
"npm" : "./cli.js"
}
}
然后你在命令行中輸入npm
,NodeJS就會去執(zhí)行對應的NodeJS模塊。
如果你只有一個可執(zhí)行命令,并且還和包名一致,那么package.json
中你可以這么寫,
{
"name": "my-package",
"version": "1.2.5",
"bin": "./bin/my-package"
}
然后,你需要在bin/my-package
文件的第一行添加如下代碼,
#!/usr/bin/env node
我們通過命令行使用部分第三方包時,有時候包會提供各種命令和參數(shù),如下圖,
從圖中可以看出,這個harp提供四個命令以及兩個參數(shù),并且簡略的展示了Usage。
那么這種比較完備的命令行包是如何做的呢?
這里我們一般會有兩個方案去做成這件事,第一就是使用原生的progress.argv
來解析,另一種方案就是使用commander.js。后面我會專門寫篇文章來闡述commander.js
的用法。
bullhead是作者隨便寫的一個小玩意兒,主要目的是用來聯(lián)系npm包創(chuàng)建及發(fā)布等操作。有興趣可以參考。
更多建議: