require('http') 內置模塊
require('./server') 「./」表示當前路徑,後面跟的是相對路徑
require("../lib/server") ../表示上一級目錄,後面跟的也是相對路徑
server.js
[javascript]
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
[javascript]
//路徑根據本身的實際狀況而定
var server = require("./learnNode/server");
server.start();
下面介紹require的只是來自於連接:http://www.nodecn.org/modules.html#file_Modules
模塊
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
緩存
javascript
模塊在首次被加載後會緩存起來。這意味着每次調用 require('foo') 將獲得徹底相同的對象,若是它被解析爲同一個文件的話。html
在 Node 中,require.paths 是一個字符串數組,表示模塊不以 '/' './' 或 '..' 打頭的搜索路徑。例如,若是 require.paths 設置爲:java
[ '/home/micheil/.node_modules',
'/usr/local/lib/node_modules' ]
則調用 require('bar/baz.js') 會搜索如下位置:node
1: '/home/micheil/.node_modules/bar/baz.js'
2: '/usr/local/lib/node_modules/bar/baz.js'
能夠在運行時修改 require.paths 數組來改變這種行爲。算法
它的值最初從 NODE_PATH 環境變量而來,那是一個冒號分隔的絕對路徑列表。在前面的例子中,NODE_PATH 環境變量可能被設置爲:npm
/home/micheil/.node_modules:/usr/local/lib/node_modules
只有使用上面的 node_modules 算法找不到模塊時纔會嘗試 require.paths。全局模塊的優先級低於捆綁依賴。json
**注意** 請不要修改 `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() 時基於文件的真實路徑,所以軟件包自己能夠放在任何位置。