require最常用的方法
require('http') 內置模塊
require('./server') “./”表示當前路徑,後面跟的是相對路徑
require("../lib/server") ../表示上一級目錄,後面跟的也是相對路徑
server.js
var http = require('http');
function start(){
server = http.createServer(function (req, res) {
res.writeHeader(200, {"Content-Type": "text/plain"});
res.end("Hello oschina\n");
})
server.listen(8000);
console.log("httpd start @8000");
}
exports.start = start;
index.js
//路徑根據自己的實際情況而定
var server = require("./learnNode/server");
server.start();
下面介紹require
模塊
Node 使用 CommonJS 模塊系統。
Node 有一個簡單的模塊加載系統。在 Node 中,文件和模塊一一對應。比如,在 foo.js 加載同一目錄中的 circle.js 模塊。
foo.js 的內容:
var circle = require('./circle.js');
console.log( 'The area of a circle of radius 4 is '
+ circle.area(4));circle.js 的內容:
var PI = Math.PI;
exports.area = function (r) {
return PI * r * r;
};
exports.circumference = function (r) {
return 2 * PI * r;
};模塊 circle.js 導出了 area() 函數和 circumference() 函數,這樣它們就能從模塊外部訪問了。要導出對象,將其添加到特殊的 exports 對象就行。
模塊的局部變量是私有的。在本例中,變量 PI 是 circle.js 私有的。
核心模塊
Node 有一些已編譯成二進制的模塊,這些模塊將在本文檔的其他地方詳細介紹。
核心模塊在 Node 源代碼的 lib/ 文件夾中定義。
使用 require() 時,核心模塊總是優先加載。例如,require('http') 總是返回內置的 HTTP 模塊,即使該名稱的文件存在。
文件模塊
如果沒有找到確切的文件,Node 將嘗試給所需的文件名添加 .js 後綴再加載,然後再嘗試 .node。
.js 文件被視爲 JavaScript 文本文件,而 .node 文件被視爲已編譯的插件模塊,用 dlopen 加載。
模塊以 '/' 開頭表示使用文件的絕對路徑。例如,require('/home/marco/foo.js') 將加載 /home/marco/foo.js 文件。
模塊以 './' 開頭表示調用 require() 時使用相對路徑。也就是說,爲了保證 require('./circle') 能找到,circle.js 必須和 foo.js 在同一目錄。
如果不以 '/' 或'./' 開頭,該模塊可以是一個“核心模塊”,也可是一個從 node_modules 文件夾中加載的模塊。
從 `node_modules` 文件夾中加載
如果傳遞給 require() 有模塊標識符是不是原生模塊,而且不以 '/'、'../' 或'./' 開頭,那麼 Node 從當前模塊的父目錄+/node_modules 這個位置嘗試加載。
如果還是沒有找到,那麼它跳到上層目錄並依此類推,直到找到模塊,或者達到根目錄爲止。
例如,如果在文件 '/home/ry/projects/foo.js' 中調用 require('bar.js'),那麼 Node 將在下列位置查找,順序如下:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
這就允許程序將依賴關係本地化,防止它們衝突。
優化 `node_modules` 查找過程
當嵌套依賴關係的層次很深時,這個文件查找列表可能會變得很長。因此,在查找時進行如下優化:
首先,/node_modules 不會附加到一個以 /node_modules 結尾的文件夾後面。
其次,如果調用 require() 的文件已經在一個 node_modules 層級裏,那麼最頂層的 node_modules 文件夾將被視爲搜索樹的根。
例如,如果在文件 '/home/ry/projects/foo/node_modules/bar/node_modules/baz/quux.js' 中調用 require('asdf.js'),那麼 Node 將搜索下列位置:
/home/ry/projects/foo/node_modules/bar/node_modules/baz/node_modules/asdf.js
/home/ry/projects/foo/node_modules/bar/node_modules/asdf.js
/home/ry/projects/foo/node_modules/asdf.js
以文件夾作爲模塊
Node 允許用戶在獨立的目錄中方便地組織程序,然後提供單一入口指向該庫。有三種方式可以將文件夾作爲 require() 的參數。
第一種方式是在該文件夾中創建 package.json 文件,指定一個 main 模塊。一個典型的 package.json 文件可能看起來像這樣:
{ "name" : "some-library",
"main" : "./lib/some-library.js" }如果此文件位於 ./some-library 文件夾,則 require('./some-library') 會嘗試加載 ./some-library/lib/some-library.js。
這是 Node 能找到 package.json 文件的情況。
如果在該目錄中沒有 package.json 文件,那麼 Node 將嘗試加載該目錄中的 index.js 或 index.node 文件。例如,如果上面的例子找不到 package.json,那麼 require('./some-library') 將試圖加載:
./some-library/index.js
./some-library/index.node
緩存
模塊在首次被加載後會緩存起來。這意味着每次調用 require('foo') 將得到完全相同的對象,如果它被解析爲同一個文件的話。
總結……
爲了得到調用 require() 時被載入的確切的文件名,使用 require.resolve() 函數。
綜上所述,這是 require.resolve 的僞碼描述:
require(X)
1. If X is a core module,
a. return the core module
b. STOP
2. If X begins with `./` or `/`,
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
3. LOAD_NODE_MODULES(X, dirname(Y))
4. THROW "not found"
LOAD_AS_FILE(X)
1. If X is a file, load X as JavaScript text. STOP
2. If X.js is a file, load X.js as JavaScript text. STOP
3. If X.node is a file, load X.node as binary addon. STOP
LOAD_AS_DIRECTORY(X)
1. If X/package.json is a file,
a. Parse X/package.json, and look for "main" field.
b. let M = X + (json main field)
c. LOAD_AS_FILE(M)
2. LOAD_AS_FILE(X/index)
LOAD_NODE_MODULES(X, START)
1. let DIRS=NODE_MODULES_PATHS(START)
2. for each DIR in DIRS:
a. LOAD_AS_FILE(DIR/X)
b. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. let PARTS = path split(START)
2. let ROOT = index of first instance of "node_modules" in PARTS, or 0
3. let I = count of PARTS - 1
4. let DIRS = []
5. while I > ROOT,
a. if PARTS[I] = "node_modules" CONTINUE
c. DIR = path join(PARTS[0 .. I] + "node_modules")
b. DIRS = DIRS + DIR
6. return DIRS從 `require.paths` 加載
在 Node 中,require.paths 是一個字符串數組,表示模塊不以 '/' './' 或 '..' 打頭的搜索路徑。例如,如果 require.paths 設置爲:
[ '/home/micheil/.node_modules',
'/usr/local/lib/node_modules' ]則調用 require('bar/baz.js') 會搜索以下位置:
1: '/home/micheil/.node_modules/bar/baz.js'
2: '/usr/local/lib/node_modules/bar/baz.js'
可以在運行時修改 require.paths 數組來改變這種行爲。
它的值最初從 NODE_PATH 環境變量而來,那是一個冒號分隔的絕對路徑列表。在前面的例子中,NODE_PATH 環境變量可能被設置爲:
/home/micheil/.node_modules:/usr/local/lib/node_modules只有使用上面的 node_modules 算法找不到模塊時纔會嘗試 require.paths。全局模塊的優先級低於捆綁依賴。
**注意** 請不要修改 `require.paths`
出於兼容性的考慮,require.paths 仍然是模塊查找過程的首選策略。儘管如此,它可能會在將來的版本中廢棄。
雖然它看起來似乎是個好主意,但在實踐中一個可變的 require.paths 列表往往是麻煩和混亂的根源。
修改 `require.paths` 毫無用處
這行代碼並不會像期望的那樣:
require.paths = [ '/usr/lib/node' ];它的結果就是丟棄了 Node 實際的模塊查找路徑引用,並創建了一個毫無用處的指向別處的新的引用。
在 `require.paths` 中加入相對路徑……不是個好主意
如果你這樣做:
require.paths.push('./lib');它不會添加 ./lib 在文件系統上已解析的完整路徑。相反,它實際增加的是 './lib',這意味着如果你在 /a/b/x.js 中 require('y.js'),那麼它會查找 /a/b/lib/y.js。如果你之後又在 /l/m/n/o/p.js 中 require('y.js'),那麼它就會查找 /l/m/n/o/lib/y.js。
在實踐中,人們往往將它作爲捆綁依賴的臨時解決辦法,這個技巧是不太穩妥的。
零隔離
有一種糟糕的設計:所有模塊共用一個 require.paths 數組。
結果,如果一個 Node 程序依賴於這種行爲,它可能會永久而微妙地改變同一進程中其它 Node 程序的行爲。當應用程序的複雜度增加時,我們傾向於封裝功能,這些行爲很難預料的部分會成爲開發者的惡夢。
增編:軟件包管理小貼示
在 Node 中,require() 函數的語義被設計成通用性足以支持大量合理的目錄結構。因此 dpkg、rpm 和 npm 之類的包管理器可以從 Node 模塊構建原生包而不作更改。
下面我們給出一個可以工作的建議的目錄結構:
比方說,我們希望 /usr/lib/node/<some-package>/<some-version> 文件夾中包含某個包的特定版本的內容。
一個軟件包可以依賴別的包。爲了安裝 foo 包,你可能需要安裝 bar 包的特定版本 。可能該 bar 包本身有依賴關係,在某些情況下,這些依賴關係甚至可能發生衝突或者形成迴路。
由於 Node 在加載任何模塊時都會查找它的真實路徑(即:會解析符號鏈接),然後在 node_modules 文件夾用上文描述的方式查找依賴。使用以下架構可以很簡單地解決:
/usr/lib/node/foo/1.2.3/ -foo包的內容,版本1.2.3。
/usr/lib/node/bar/4.3.2/ -bar 包的內容,foo依賴這個包。
/usr/lib/node/foo/1.2.3/node_modules/bar -到 /usr/lib/node/bar/4.3.2/的符號鏈接。
/usr/lib/node/bar/4.3.2/node_modules/* -到 bar 所依賴的包的符號鏈接。
因此,即使遇到一個迴路,或者有依賴衝突,每個模塊都能夠得到它依賴的可用版本。
當 foo 包中有代碼 require('bar') 時,它會得到符號鏈接至 /usr/lib/node/foo/1.2.3/node_modules/bar 的版本。然後,當 bar 包調用 require('quux') 時,它會得到符號鏈接至 /usr/lib/node/bar/4.3.2/node_modules/quux 的版本。
此外,爲了使模塊查找過程更加優化,而不是直接把包放到 /usr/lib/node 中,我們可以它們放到 /usr/lib/node_modules/<name>/<version> 裏。這樣,Node 就不用在 /usr/node_modules 或 /node_modules 中查找了。
爲了使 REPL 能夠正常引用模塊,可以將 /usr/lib/node_modules 添加至 $NODE_PATH環境變量。因爲使用 node_modules 文件夾查找模塊時的路徑都是相對的,而且調用 require() 時基於文件的真實路徑,因此軟件包本身可以放在任何位置。
本篇文章來源於 Linux公社網站(www.linuxidc.com) 原文鏈接:http://www.linuxidc.com/Linux/2012-10/72627p2.htm