1. 程式人生 > >使用NPM來管理你的Node.js依賴

使用NPM來管理你的Node.js依賴

轉載自  http://www.infoq.com/cn/articles/msh-using-npm-manage-node.js-dependence

npm 是 Node.js 的模組依賴管理工具。作為開發者使用的工具,主要解決開發 Node.js 時會遇到的問題。如同 RubyGems 對於 Ruby 開發者和 Maven 對於 Java 開發者的重要性,npm 對與 Node.js 的開發者和社群的重要性不言而喻。本文包括五點:package.json 、npm 的配置、npm install 命令、npm link 命令和其它 npm 命令。

package.json

npm命令執行時會讀取當前目錄的 package.json 檔案和解釋這個檔案,這個檔案基於 規範。在這個檔案裡你可以定義你的應用名稱( name )、應用描述( description )、關鍵字( keywords )、版本號( version )、應用的配置項( config )、主頁( homepage )、作者( author )、資源倉庫地址( repository )、bug的提交地址( bugs ),授權方式( licenses )、目錄( directories )、應用入口檔案( main )、命令列檔案( bin )、應用依賴模組( dependencies )、開發環境依賴模組( devDependencies )、執行引擎( engines )和指令碼( scripts )等。

對於開發者而言,開發和釋出模組都依賴於他對這個檔案 package.json 所包含的意義的正確理解。我們下面用一個本文共用的例子來說明:

{
    "name": "test",
    "version": "0.1.0",
    "description": "A testing package",
    "author": "A messed author <>",
    "dependencies": {
        "express": "1.x.x",
        "ejs": "0.4.2",
        "redis": ">= 0.6.7"
    },
    "devDependencies": {
        "vows": "0.5.x"
    },
    "main": "index",
    "bin": {
        "test": "./bin/test.js"
    },
    "scripts": {
        "start": "node server.js",
        "test": "vows test/*.js",
        "preinstall": "./configure",
        "install": "make && make install"
    },
    "engines": {
        "node": "0.4.x"
    }
}

這個例子裡我們定義了應用的入口檔案( main )為 index ,當其他應用引用了我們的模組 require('test') 時,這個 main 的值 index.js 檔案被呼叫。指令碼( scripts )使用hash 表定義了幾個不同的命令。script.start 裡的定義的 node server.js 會在 npm start 時被呼叫,同樣的 npm test 呼叫時對應的 scripts.test 裡定義的命令被呼叫。在有些 native 模組需要編譯的話,我們可以定義預編譯和編譯的命令。本例中還定義了應用依賴模組( dependencies )和開發環境依賴模組( devDependencies )。應用依賴模組會在安裝時安裝到當前模組的 node_modules 目錄下。開發環境依賴模組主要時在開發環境中用到的依賴模組,用命令 npm 的命令 install 或 link 加上引數 —dev 安裝到當前模組的 node_modules 目錄下。

大家也注意到 package.json 裡的版本號有些是 >= 0.6.7 有些是 1.x.x,這有什麼區別?npm 使用於來進行版本管理。並不是所有的模組都會提供向後相容性,有時候某些模組因為某些原因導致不向後相容。所以我們需要定義一些規則來保證模組能夠在某些特定的版本中可用,並且保證能用最新的版本,因為那些版本總是修改了一些 bug 或提升了效能等。我們來看一下版本定義的欄位:

主版本( 0 )0.4.2

  • 副版本( 4 )
  • 補丁版本( 2 )

在上面 package.json 的定義裡我們確信模組在所有的 Nodejs 0.4及以上和0.5以下版本里都能執行。依賴模組 redis 在所有大於或等於0.6.7的版本上都能執行,依賴模組 ejs 只能確保執行在0.4.2版本里,依賴模組 express 確保能夠相容大於或等於1.0.0並且小於2.0.0。

npm 的配置

npm 擁有很多預設配置。你可以使用這些預設的配置,也可以修改這些預設的配置,甚至可以在環境變數或命令列下修改這些配置。配置的權重是如下順序定義的:

  1. 命令列,使用—為字首的引數。比如 —foo bar,設定變數 foo 的值為" bar “。—foo 後不帶值的引數,設定 foo 的值為 true 。
  2. 環境變數,所有 npm_config_ 為字首的環境變數。比如 npm_config_foo = bar ,設定變數 foo 為 “ bar "。
  3. 使用者定義。所有的變數儲存在 $HOME/.npmrc 檔案裡的變數。
  4. 全域性。所有 $PREFIX/etc/npmrc 檔案裡的變數。$PREFIX 變數可通過 npm prefix -g 獲取,一般預設是 /usr/local。
  5. 內建的配置。通過安裝時執行 ./configure 所定義的變數。可通過命令curl | env npm_config_foo=bar sh 設定。

使用配置能給我們帶來很大的靈活性。比如我們使用 npm install 時,對預設的資源庫地址 不是很滿意,我們可以使用下面的命令來更改資源庫地址。

npm --registry "an other registry" install express
# 或者下面的命令
env npm_config_registry="an other registry" npm install express 

或是對 npm 預設的 vi 編輯器不滿意,直接命令 npm set editor mate 。npm 的配置可通過命令 npm config ls 獲取。這個命令是獲取修改後的配置,要獲取包括預設配置的全部配置加上 -l 引數。值得注意的是,開發者通過 npm config set registry "an other registry" 的方式修改 registry 這個屬性值,一定要明白這個修改這個值所帶來的負面效應。一旦設定了 registry 這個值,當你要 publish 一個模組,會把模組釋出到修改後的資源庫裡,而不是原始預設的資源庫。其他的資源庫是原始預設的資源庫的一個複製品,定時從預設的資源庫取資源。一般來說,沒有把其新家的模組同步到預設的資源庫的能力。這樣會導致發生你的模組在修改後的資源庫裡能夠找到,而在其它的資源庫裡找不到的事情。

npm install命令

安裝模組只需要 npm install express connect 命令給我們帶來了很大的方便。安裝模組的路徑分兩種:

  • 全域性路徑,也就是帶上引數 -g 的安裝模式。這個命令會把模組安裝在 $PREFIX/lib/node_modules 下,可通過命令 npm root -g 檢視全域性模組的安裝目錄。 package.json 裡定義的bin會安裝到 $PREFIX/bin 目錄下,如果模組帶有 man page 會安裝到 $PREFIX/share/man 目錄下。
  • 本地路徑,不帶 -g 引數的。從當前目錄一直查詢到根目錄/下有沒有 node_modules 目錄,有模組安裝到這個目錄下的 node_modules 目錄裡,如果沒有找到則把模組安裝到當前目錄 node_modules 目錄下。package.josn 定義的 bin 會安裝到 node_modules/.bin 目錄下,man page 則不會安裝。

我們需要選擇什麼樣的安裝方式呢?全域性模式可以讓你不用擔心找不到模組,如果不需要還是儘量避免全域性模式。

  • 如果我們只是 require('pkg') 一個模組,我們不需要使用全域性模式。
  • 如果我們需要在命令列中呼叫,我們需要使用全域性模式。因為這個安裝把 package.josn裡 bin 下的定義安裝到 $PATH 目錄下。

有些模組我們既需要在命令列中呼叫又想 require('pkg') ,比如  。那麼我們可以使用全域性模式安裝,然後使用下一段要講的命令 npm link 把它連結到本地的 node_modules 目錄下。

不要擔心 package.josn 裡 script 中定義的命令會不會因為不是全域性安裝而不能執行。比如在例子裡定義的 devDependencies 的 vows 。在呼叫 npm test 時 npm 會把 node_modules/.bin 目錄放到環境變數 $PATH 的最前面。

npm link命令

對開發者而言,這算是最有價值的命令。假設我們開發了一個模組叫 test ,然後我們在 test-example 裡引用這個模組 ,每次 test 模組的變動我們都需要反映到 test-example 模組裡。不要擔心,有了 npm link 命令一切變的非常容易。

首先我們需要把 test 連結到全域性模式下:

cd ~/work/node/test # 進入test模組目錄
npm link # 建立連結到$PREFIX/lib/node_modules

那麼 test 的模組將被連結到 $PREFIX/lib/node_modules 下,就像我的機器上 $PREFIX 指到 /usr/local ,那麼 /usr/local/lib/node_modules/test 將會連結到 ~/work/node/test 下。執行指令碼 bin/test.js 被連結到 /usr/local/bin/test 上。

接下來我們需要把 test 引用到 test-example 專案中來:

cd ~/work/node/test-example # 進入test-example模組目錄
npm link test # 把全域性模式的模組連結到本地

npm link test 命令會去 $PREFIX/lib/node_modules 目錄下查詢名叫 test 的模組,找到這個模組後把 $PREFIX/lib/node_modules/test 的目錄連結到 ~/work/node/test-example/node_modules/test 這個目錄上來。

現在任何 test 模組上的改動都會直接對映到 test-example 上來。再比如假設我們開發很多應用,每個應用都用到 Coffee-script :

npm install coffee-script -g # 全域性模式下安裝coffee-script
cd ~/work/node/test # 進入開發目錄
npm link coffee-script # 把全域性模式的coffee-script模組連結到本地的node_modules下
cd ../test-example # 進入另外的一個開發目錄
npm link coffee-script # 把全域性模式的coffee-script模組連結到本地
npm update coffee-script -g # 更新全域性模式的coffee-script,所有link過去的專案同時更新了。

就像你看到,npm link 對於開發時一個模組被多個模組引用時非常有用。windows 的使用者會想,我這兒沒有 UNIX 下的 link 工具怎麼辦?別擔心只要你的 Node.js 支援 fs.symlink 就可用到這個特性。

其它 npm 命令

npm 命令裡還有很多有用的命令。npm explore . -- git pull origin master ,更新當前的 git 資源庫。npm edit . ,編輯當前模組的所有依賴模組。npm docs coffee-script ,開啟 coffee-script 模組的文件。npm outdated coffee-script ,檢視 coffee-script 是否有新版本。npm submodule . ,你可以要求你的依賴模組是從 git 資源庫安裝的,而不是從 registry 安裝。因為作者的 git 資源庫總是最新的版本,registry 上的是模組作者釋出上去的穩定版本。甚至你可以用 npm 來程式設計。

var npm = require('npm');
npm.load({}, function (err) {
    if (err) return commandFailed(err);
    npm.on("log", function (message) {
        if (arg) console.log(message)
    })
    var requirements = JSON.parse(fs.readFileSync('config/requirements.json'));
    npm.commands.install(requirements, function (err, data) {
        if (err) return commandFailed(err);
    });
});

做為 Node.js 的開發者工具,npm 已經為我們想到很多的應用場景。這也是 Node.js 社群一致推薦它為開發者模組依賴管理工具