模塊路徑解析規則
我們已經知道,require函數支持斜杠(/)或盤符(C:)開頭的絕對路徑,也支持./開頭的相對路徑。但這兩種路徑在模塊之間建立了強耦合關系,一旦某個模塊文件的存放位置需要變更,使用該模塊的其它模塊的代碼也需要跟着調整,變得牽一發動全身。因此,require函數支持第三種形式的路徑,寫法類似於foo/bar,並依次按照以下規則解析路徑,直到找到模塊位置。
-
內置模塊
如果傳遞給require函數的是NodeJS內置模塊名稱,不做路徑解析,直接返回內部模塊的導出對象,例如require('fs')
-
node_modules目錄
NodeJS定義了一個特殊的node_modules目錄用於存放模塊。例如某個模塊的絕對路徑是/home/user/hello.js,在該模塊中使用require('foo/bar')方式加載模塊時,則NodeJS依次嘗試使用以下路徑。
/home/user/node_modules/foo/bar
/home/node_modules/foo/bar
/node_modules/foo/bar
可以看出module path的生成規則為:從當前文件目錄開始查找node_modules目錄;然后依次進入父目錄,查找父目錄下的node_modules目錄;依次迭代,直到根目錄下的node_modules目錄。
- NODE_PATH環境變量
與PATH環境變量類似,NodeJS允許通過NODE_PATH環境變量來指定額外的模塊搜索路徑。NODE_PATH環境變量中包含一到多個目錄路徑,路徑之間在Linux下使用:分隔,在Windows下使用;分隔。例如定義了以下NODE_PATH環境變量:
NODE_PATH=/home/user/lib:/home/lib
當使用require('foo/bar')的方式加載模塊時,則NodeJS依次嘗試以下路徑
/home/user/lib/foo/bar
/home/lib/foo/bar
包(package)
把多個子模塊組成的大模塊稱為包
在組成一個包的所有子模塊中,需要有一個入口模塊,入口模塊的導出對象被作為包的導出對象
在其它模塊里使用包的時候,需要加載包的入口模塊
如果想自定義入口模塊的文件名和存放位置,就需要在包目錄下包含一個package.json文件,並在其中指定入口模塊的路徑
首先搜索當前目錄下的package.json文件,查找里面的mian屬性,如果存在,則加載該屬性所指定的的文件。 如果不存在package.json或者該文件里面沒有main字段,nodejs將試圖加載 index.js,都不存在那么就只有說一聲Cannot find module了。
工程目錄
了解了以上知識后,現在我們可以來完整地規划一個工程目錄了。以編寫一個命令行程序為例,一般我們會同時提供命令行模式和API模式兩種使用方式,並且我們會借助三方包來編寫代碼。除了代碼外,一個完整的程序也應該有自己的文檔和測試用例。因此,一個標准的工程目錄都看起來像下邊這樣。
- /home/user/workspace/node-echo/ # 工程目錄
- bin/ # 存放命令行相關代碼
node-echo
+ doc/ # 存放文檔
- lib/ # 存放API相關代碼
echo.js
- node_modules/ # 存放三方包
+ argv/
+ tests/ # 存放測試用例
package.json # 元數據文件
README.md # 說明文件
其中部分文件內容如下:
/* bin/node-echo */
var argv = require('argv'),
echo = require('../lib/echo');
console.log(echo(argv.join(' ')));
/* lib/echo.js */
module.exports = function (message) {
return message;
};
/* package.json */
{
"name": "node-echo",
"main": "./lib/echo.js"
}
NPM
NPM是隨同NodeJS一起安裝的包管理工具,能解決NodeJS代碼部署上的很多問題,常見的使用場景有以下幾種:
-
允許用戶從NPM服務器下載別人編寫的三方包到本地使用。
-
允許用戶從NPM服務器下載並安裝別人編寫的命令行程序到本地使用。
-
允許用戶將自己編寫的包或命令行程序上傳到NPM服務器供別人使用。