1. 程式人生 > >nodeJs中npm詳解

nodeJs中npm詳解

commonjs -s license mon sem console 能力 效應 模塊安裝

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 文件和解釋這個文件,這個文件基於 Packages/1.1 規範。在這個文件裏你可以定義你的應用名稱( 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 <[email protected]>",
    "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.4.2

  • 主版本( 0 )
  • 副版本( 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 http://npmjs.org/install.sh | env npm_config_foo=bar sh 設置。

使用配置能給我們帶來很大的靈活性。比如我們使用 npm install 時,對默認的資源庫地址 https://registry.npmjs.org/ 不是很滿意,我們可以使用下面的命令來更改資源庫地址。

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‘) ,比如 Coffee-script 。那麽我們可以使用全局模式安裝,然後使用下一段要講的命令 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 社區一致推薦它為開發者模塊依賴管理工具。

nodeJs中npm詳解