npm做為Javascript項目的包管理工具,由于其與Node.js的緊密配合(npm和Node.js出自一人之手),目前已經(jīng)基本沒有競爭對手。
包管理工具要解決的主要問題就是依賴包的安裝,在Javascript項目中,包的依賴關系是由package.json給出的,這篇文件將介紹package.json中描述的依賴信息。
依賴管理
在package.json中,有如下幾項涉及到依賴包的描述:
dependencies
項目中使用到的包,但不包括測試所使用的包-
devDependencies
主要是在測試時使用的包,也包括一些代碼編譯的包,比如將coffee-script編譯為javascript。也就是說在僅僅使用該項目的時候(而不進行測試等環(huán)節(jié)),不需要安裝的包可以放在devDependencies中
-
peerDependencies
如果改項目需要指明一些有協(xié)作關系的包的版本時,使用peerDependencies。這里使用了協(xié)作,而不是依賴,是我個人的理解。peerDependencies并不是必須安裝的包,但如果一旦要安裝,就要符合要求。比如react-dom的package.json中有如下的描述:
"peerDependencies": { "react": "^15.6.1" },peerDependencies至少打消了一些顧慮,比如react生態(tài)中用到的一些包在升級的時候會不會不匹配?
-
optionalDependencies
如果有一些依賴包即使安裝失敗,項目仍然能夠運行或者希望npm繼續(xù)運行,就可以使用optionalDependencies。另外optionalDependencies會覆蓋dependencies中的同名依賴包,所以不要在兩個地方都寫。
-
bundledDependencies/bundleDependencies
如果在打包發(fā)布的使用希望一些依賴包也出現(xiàn)在最終的包里,那么可以將包的名字放在bundledDependencies,bundledDependencies的值是一個字符串數(shù)組,如:
"name": "awesome-web-framework", "version": "1.0.0", "bundledDependencies": [ 'renderized', 'super-streams' ]npm pack會將renderized和super-streams放入生成的包awesome-web-framework-1.0.0.tgz中,并且在npm install awesome-web-framework-1.0.0.tgz時,renderized和super-streams也會被一同安裝。
這些項的內容形式都是一樣的(除了bundledDependencies),只是作用不同,如:
"dependencies": {
"base62": "~0.1.1",
"commoner": "~0.7.0",
"esprima": "https://github.com/facebook/esprima/tarball/ca28795124d45968e62a7b4b336d23a053ac3a84",
"recast": "~0.4.8",
"source-map": "~0.1.22"
}
key就是項目的名詞,而value可以有多種形式
- version,遵循semver
- 一個tarball的url
- 一個git url
- 本地路徑
關于semver會在另一篇文章中介紹(先挖個坑)。
依賴樹
不同于很多語言的依賴管理,npm使用的是依賴樹。也就是說每個依賴包會有一套自己指定的(在package.json中說明的)依賴包,而不會和其他包共享。
例如,mod-a依賴mod-b@1.0.0,mod-c依賴mod-b@2.0.0,而現(xiàn)在有一個項目依賴mod-a和mod-c,那么最終安裝的依賴包如下:
├─┬ node_modules
│ ├─┬ mod-a
│ │ ├── mod-b@1.0.0
│ ├─┬ mod-c
│ │ ├── mod-b@2.0.0
而Node.js在加載依賴包的時候會處理這個問題。之所以文章最開始說npm和Node.js的緊密合作也是這個原因。
使用依賴樹來管理包帶來了一個明顯的好處,不用處理依賴沖突的問題。這個問題在早期的Java項目中比較常見,而在使用了Maven和Gradle之后,情況有所緩解,但只能減輕同一個包多個版本被放入發(fā)布的包中這種情況,仍然無法解決依賴沖突這個根本問題。
依賴樹也有一些缺點:
- 代碼量增加。由于不能共享相同的包(在npm v3中,嘗試著共享相同版本的庫,但還是比較弱),導致最終打包的時候有同一個庫的多個版本的代碼出現(xiàn)在最終包中。
- 潛在的運行時沖突。以上面的例子為例,可能有些時候,mod-b的兩個版本無法同時運行,而這只有在運行或者測試的時候才能被發(fā)現(xiàn)。
希望以上的介紹能夠幫助你更好的理解npm的依賴管理。