前面的話
Node組織了自身的核心模塊,也使得第三方文件模塊可以有序地編寫和使用。但是在第三方模塊中,模塊與模塊之間仍然是散列在各地的,相互之間不能直接引用。而在模塊之外,包和NPM則是將模塊聯系起來的一種機制。在介紹NPM之前,不得不提起CommonJS的包規范。JavaScript不似Java或者其他語言那樣,具有模塊和包結構。Node對模塊規范的實現,一定程度上解決了變量依賴、依賴關系等代碼組織性問題。包的出現,則是在模塊的基礎上進一步組織JavaScript代碼。CommonJS的包規范的定義其實也十分簡單,它由包結構和包描述文件兩個部分組成,前者用于組織包中的各種文件,后者則用于描述包的相關信息,以供外部讀取分析。本文將詳細介紹nodeJS中的包
包結構
包實際上是一個存檔文件,即一個目錄直接打包為.zip或tar.gz格式的文件,安裝后解壓還原為目錄。完全符合CommonJS規范的包目錄應該包含如下這些文件
1、package.json:包描述文件
2、bin:用于存放可執行二進制文件的目錄
3、lib:用于存放JavaScript代碼的目錄
4、doc:用于存放文檔的目錄
5、test:用于存放單元測試用例的代碼
以功能為使頁面即時刷新的livereload插件的包結構為例

包描述文件
包描述文件用于表達非代碼相關的信息,它是一個JSON格式的文件——package.json,位于包的根目錄下,是包的重要組成部分。而NPM的所有行為都與包描述文件的字段息息相關
package.json
文件,定義了項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數據)。npm install
命令根據這個配置文件,自動下載所需的模塊,也就是配置項目所需的運行和開發環境
有了package.json文件,直接使用npm install命令,就會在當前目錄中安裝所需要的模塊
$ npm install
如果一個模塊不在package.json
文件之中,可以單獨安裝這個模塊,并使用相應的參數,將其寫入package.json
文件之中
$ npm install express --save
$ npm install express --save-dev
上面代碼表示單獨安裝express模塊,--save
參數表示將該模塊寫入dependencies
屬性,--save-dev
表示將該模塊寫入devDependencies
屬性
同樣地,以livereload插件的包描述文件為例

基本字段
package.json文件可以手工編寫,也可以使用npm init
命令自動生成
$ npm init
這個命令采用互動方式,要求用戶回答一些問題,然后在當前目錄生成一個基本的package.json文件。所有問題之中,只有項目名稱(name)和項目版本(version)是必填的,其他都是選填的
因此,最簡單的package.json文件,只定義兩項元數據:項目名稱和項目版本
{ "name" : "xxx", "version" : "0.0.0", }
1、name——包名。規范定義它需要由小寫的字母和數字組成,可以包含.、_和-,但不允許出現空格。包名必須是唯一的,以免對外公布時產生重名沖突的誤解。除此之外,NPM還建議不要在包名中附帶上node或js來重復標識它是JavaScript或Node模塊
"name": "livereload"
2、version——版本號。一個語義化的版本號,這在http://semver.org/上有詳細定義,通常為major.minor.revision格式。該版本號十分重要,常常用于一些版本控制的場合
"version": "0.6.0"
[注意]對于nodejs來說,版本號的小數位代表為這個版本的穩定性,偶數位為穩定版本(0.6.x、0.8.x……),奇數位為非穩定版本(0.7.x、0.9.x……)。一般地,開發時要使用最新的穩定版本
必需字段
CommonJS為package.json文件定義了包括name和version在內的10個必需的字段。但由于CommonJS包規范尚處于草案階段,NPM在實踐中做了一定的取舍
1、description——包簡介。方便別人了解該模塊作用,搜索的時候也有用
"description": "LiveReload server"
2、keywords——關鍵詞數組,NPM中主要用來做分類搜索。一個好的關鍵詞數組有利于用戶快速找到該包
[注意]livereload插件并沒有設置keywords屬性
3、maintainers——包維護者列表。每個維護者由name、email和web這3個屬性組成
[注意]livereload插件并沒有設置maintainers中的web屬性
"maintainers": [ { "name": "bphogan", "email": "brianhogan@napcs.com" } ]
4、contributors——貢獻者列表。在開源社區中,為開源項目提供代碼是經常出現的事情,如果名字能出現在知名項目的contributors列表中,是一件比較有榮譽感的事。列表中的第一個貢獻應當是包的作者本人。它的格式與維護者列表相同
"contributors": [ { "name": "Brian P. Hogan", "email": "brianhogan@napcs.com" } ]
5、bugs——一個可以反饋bug的網頁地址或郵件地址
"bugs": { "url": "https://github.com/napcs/node-livereload/issues" }
6、licenses——當前包所使用的許可證列表,表示這個包可以在哪些許可證下使用
"licenses": [ { "type": "MIT", "url": "https://github.com/napcs/node-livereload/blob/master/LICENSE" } ]
7、repositories——托管源代碼的位置列表,表明可以通過哪些方式和地址訪問包的源代碼
"repository": { "type": "git", "url": "git+ssh://git@github.com/napcs/node-livereload.git" }
8、dependencies——使用當前包所需要依賴的包列表。這個屬性十分重要,NPM會通過這個屬性幫助自動加載依賴的包
對應的版本可以加上各種限定,主要有以下幾種:
- 指定版本:比如1.2.2,遵循“大版本.次要版本.小版本”的格式規定,安裝時只安裝指定版本
- 大于小于號(>或<)+指定版本:比如>=1.2.2,表示安裝大于等于1.2.2的最新版本
- 波浪號(tilde)+指定版本:比如~1.2.2,表示安裝1.2.x的最新版本(不低于1.2.2),但是不安裝1.3.x,也就是說安裝時不改變大版本號和次要版本號。
- 插入號(caret)+指定版本:比如ˆ1.2.2,表示安裝1.x.x的最新版本(不低于1.2.2),但是不安裝2.x.x,也就是說安裝時不改變大版本號。需要注意的是,如果大版本號為0,則插入號的行為與波浪號相同,這是因為此時處于開發階段,即使是次要版本號變動,也可能帶來程序的不兼容
- latest:安裝最新版本
"devDependencies": { "coffee-script": ">= 1.8.0", "mocha": ">= 1.0.3", "request": ">= 2.9.203", "should": ">= 0.6.3", "sinon": "^1.17.4" }
可選字段
除了必選字段外,規范還定義了一部分可選字段,具體如下所示
1、homepage——當前包的網站地址
"homepage": "https://github.com/napcs/node-livereload#readme",
2、os——操作系統支持列表。這些操作系統的取值包括aix、freebsd、linux、macos、solaris、vxworks、windows。如果設置了列表為空,則不對操作系統做任何假設
[注意]livereload插件并沒有設置os屬性
3、cpu——CPU架構的支持列表,有效的架構名稱有arm、mips、ppc、sparc、x86和x86_64。同os一樣,如果列表為空,則不對CPU架構做任何假設
[注意]livereload插件并沒有設置cpu屬性
4、engine——支持的JavaScript引擎列表,有效的引擎取值包括ejs、flusspferd、gpsee、jsc、spidermonkey、narwhal、node和v8
"engines": { "node": ">=0.4.0" }
5、builtin——標志當前包是否是內建在底層系統的標準組件
[注意]livereload插件并沒有設置builein屬性
6、directories——包目錄說明
"directories": {}
7、implements——實現規范的列表。標志當前包實現了CommonJS的哪些規范
[注意]livereload插件并沒有設置implements屬性
8、scripts——腳本說明對象。它主要被包管理器用來安裝、編譯、測試和卸載包。scripts
指定了運行腳本命令的npm命令行縮寫,比如start指定了運行npm run start
時,所要執行的命令
"scripts": { "test": "mocha" },
其他字段
在包描述文件的規范中,NPM實際需要的字段主要有name、version、description、keywords、repositories、author、bin、main、scripts、engines、dependencies、devDependencies。與包規范的區別在于多了author、bin、main和devDependencies這4個字段
1、author——包作者
[注意]livereload插件并沒有設置author屬性
2、bin——指定各個內部命令對應的可執行文件的位置。一些包作者希望包可以作為命令行工具使用。配置好bin字段后,通過npm install package_name -g命令可以將腳本添加到執行路徑中,之后可以在命令行中直接執行。通過-g命令安裝的模塊包稱為全局模式
下面代碼指定,livereaload命令對應的可執行文件為 bin 子目錄下的 livereload.js。Npm會尋找這個文件,在node_modules/.bin/
目錄下建立符號鏈接。在上面的例子中,livereaload會建立符號鏈接npm_modules/.bin/someTool
。由于node_modules/.bin/
目錄會在運行時加入系統的PATH變量,因此在運行npm時,就可以不帶路徑,直接通過命令來調用這些腳本
"bin": { "livereload": "./bin/livereload.js" }
因此,像下面這樣的寫法可以采用簡寫
scripts: { start: './node_modules/livereload.js build' } // 簡寫為 scripts: { start: 'livereload build' }
所有node_modules/.bin/
目錄下的命令,都可以用npm run [命令]
的格式運行。在命令行下,鍵入npm run
,然后按tab鍵,就會顯示所有可以使用的命令
3、main——加載的入口文件。模塊引入方法require()在引入包時,會優先檢查這個字段,并將其作為包中其余模塊的入口。如果不存在這個字段,require()方法會查找包目錄下的index.js、index.node、index.json文件作為默認入口
"main": "./lib/livereload.js"
4、devDependencies——項目開發所需要的模塊。一些模塊只在開發時需要依賴。配置這個屬性,可以提示包的后續開發者安裝依賴包。類比于dependencies字段
"devDependencies": { "coffee-script": ">= 1.8.0", "mocha": ">= 1.0.3", "request": ">= 2.9.203", "should": ">= 0.6.3", "sinon": "^1.17.4" }
文章列表