理解包結構
commonjs包結構規范:http://wiki.commonjs.org/wiki/Packages/1.0
- 一個package.json文件應該存在于包頂級目錄下
- 二進制文件應該包含在bin目錄下。
- JavaScript代碼應該包含在lib目錄下。
- 文檔應該在doc目錄下。
- 單元測試應該在test目錄下。
理解描述文件package.json
輸入 npm init
后會彈出一堆問題,我們可以輸入對應內容,也可以使用默認值。在回答一堆問題后輸入 yes
就會生成圖中所示內容的 package.json
文件。如果嫌回答這一大堆問題麻煩,可以直接輸入 npm init --yes
跳過回答問題步驟,直接生成默認值的 package.json
文件
- name。包名,需要在NPM上是唯一的,不能帶有空格。
- description。包簡介,通常會顯示在一些列表中。
- version。版本號,一個語義化的版本號(http://semver.org/ ),通常為x.y.z。
- keywords。關鍵字數組,用于NPM中的分類搜索。
- maintainers。包維護者的數組,數組元素是一個包含name、email、web三個屬性的JSON對象。
- contributors。包貢獻者的數組。第一個就是包的作者本人。在開源社區,如果提交的patch被merge進master分支的話,就應當加上這個貢獻patch的人。格式包含name和email。
"contributors": [{
"name": "Jackson Tian",
"email": "mail @gmail.com"
}, {
"name": "fengmk2",
"email": "mail2@gmail.com"
}],
bugs。一個可以提交bug的URL地址,可以是郵件地址(mailto:mailxx@domain),也可以是網頁地址(http://url)。
licenses。包所使用的許可證,例如:
"licenses": [{ "type": "GPLv2", "url": "http://www.example.com/licenses/gpl.html", }]
repositories。托管源代碼的地址數組。
dependencies。當前包需要的依賴,這個屬性十分重要,NPM會通過這個屬性,幫你自動加載依賴的包。
理解npm install
我們可以把項目發布到npm中央倉庫,別人拿到我們的項目時,可以執行npm install下載所需要的模塊,這些模塊是依賴package.json中定義的,這些依賴都會被安裝在當前目錄下。
npm的包安裝分為本地安裝(local)、全局安裝(global)兩種。
npm install xxx # 本地安裝
將安裝包放在 ./node_modules 下(運行npm時所在的目錄)
npm install -g xxx # 全局安裝
將安裝包放在/usr/local/lib/node_modules下。
使用 npm install
時增加 --save
或者 --save -dev
表示將這個包名及對應的版本添加到 package.json
的 dependencies
或devDependencies
。
使用模塊
使用require函數用于在當前模塊中加載和使用別的模塊,傳入一個模塊名,返回一個模塊導出對象。
優先從緩存中加載模塊,其次在核心模塊中加載,然后是指定文件路徑的模塊加載,如果以上三個條件均不滿足,則定義為自定義模塊,查找策略為從當前目錄下的node_modules查找,找不到則向父目錄的node_modules查找,直到根目錄或找到為止。
如果在環境變量中設置了HOME目錄和NODE_PATH目錄的話,整個路徑還包含NODE_PATH和HOME目錄下的.node_libraries與.node_modules。
全局模塊
為什么我們使用npm install -g命令安裝的模塊不能即時生效,那是因為npm install -g 會將模塊默認安裝在/usr/local/lib/node_modules中,而require模塊的流程如剛才所說,默認情況下并沒有自動查找到全局路徑中。
可以通過三種方法解決:
- 可以在工程目錄下執行npm link module_name
- 可以設置環境變量NODE_PATH
- 可以軟鏈接一個目錄,在某個父節點路徑中創建node_modules,如下:
設置一個代理全局模塊路徑,這樣npm install -g的模塊都會安裝在此
npm config set prefix "~/npm_global"
建立一個軟鏈接
ln -s ~/npm_global/lib/node_modules ~/node_modules
查看全局安裝模塊的命令:
npm list --depth=0 -global
導出模塊
exports該對象是當前模塊的導出對象,用于導出模塊公有方法和屬性,默認為一個空對象{}。別的模塊通過require()函數使用當前模塊時得到的就是當前模塊的exports對象。以下代碼中導出了一個公有方法:
exports.hello = function() {
console.log("Hello World!");
};
在下面的情況下,你的模塊是一個類:
module.exports = function(name, age) {
this.name = name;
this.age = age;
this.about = function() {
console.log(this.name +' is '+ this.age +' years old');
};
};
然后你應該這樣使用它:
var Rocker = require('./rocker.js');
var r = new Rocker('Ozzy', 62);
r.about(); // Ozzy is 62 years old
在下面的情況下,你的模塊是一個數組:
module.exports = ['Lemmy Kilmister', 'Ozzy Osbourne', 'Ronnie James Dio', 'Steven Tyler', 'Mick Jagger'];
然后你應該這樣使用它:
var rocker = require('./rocker.js');
console.log('Rockin in heaven: ' + rocker[2]); //Rockin in heaven: Ronnie James Dio
exports
只是module.exports
的輔助方法。你的模塊最終返回module.exports
給調用者,而不是exports
。exports
所做的事情是收集屬性,如果module.exports
當前沒有任何屬性的話,exports
會把這些屬性賦予module.exports
。如果module.exports
已經存在一些屬性的話,那么exports
中所用的東西都會被忽略。
簡單理解核心模塊
核心模塊中,有些模塊使用C/C++編寫,有些則由C/C++完成核心部分,由JavaScript實現包裝和向外導出。
內建模塊被統一放在一個node_module_list數組中,通過get_builtin_module方法取出,通過執行register_func()填充exports對象,將exports對象緩存并返回給調用方。