使用 npm shrinkwrap 來管理項(xiàng)目依賴

原文地址:https://tech.meituan.com/npm-shrinkwrap.html

在一次項(xiàng)目開發(fā)中遇到了這個(gè)情況:我從倉庫把項(xiàng)目拉到本地,結(jié)果構(gòu)建出來發(fā)現(xiàn)有問題硼端,但是在同事那里就運(yùn)行正常乾胶。無疑是因?yàn)橐蕾嚢陌姹静煌瑢?dǎo)致的褥影,在Google時(shí)發(fā)現(xiàn)了這篇文章飒筑,下邊是原文渤涌。

使用 npm shrinkwrap 來管理項(xiàng)目依賴
敬威 ·2015-10-23 17:30

管理依賴是一個(gè)復(fù)雜軟件開發(fā)過程中必定會遇到的問題佩谣。
在Node.js項(xiàng)目開發(fā)的時(shí)候,我們也經(jīng)常需要安裝和升級對應(yīng)的依賴实蓬。雖然 npm 以及語意化的版本號 (semantic versioning, semver) 讓開發(fā)過程中依賴的獲取和升級變得非常容易茸俭, 但不嚴(yán)格的版本號限制,也帶來了版本號的不確定性安皱。主要的問題可能有三個(gè):
npm 建議使用 semver 的應(yīng)用程序版本调鬓,但這也完全依賴第三方包遵守這一規(guī)則。如果你依賴于的包不遵循 semver 酌伊,或者依賴的包的新版本有重大更改(而你使用了 ^
的寬泛版本安裝)腾窝,這潛在可能是會導(dǎo)致問題的。

另一個(gè)問題的出現(xiàn)是由于 npm 安裝依賴的機(jī)制。npm 的安裝包是有層次結(jié)構(gòu)的虹脯,手動控制要安裝的軟件包的版本號可以實(shí)現(xiàn)驴娃,但是你只能在 package.json 使用精確的版本號控制你的直接依賴包,但那些多層以上的依賴就沒辦法控制了循集;一個(gè)第三方包不嚴(yán)謹(jǐn)?shù)陌姹疽蕾嚿赡芷茐哪愕囊蕾嚬芾怼?/p>

在開發(fā)階段執(zhí)行得到的版本唇敞,和后續(xù)部署時(shí)得到的可能是不一致的,更不可控的是咒彤,你依賴的第三方包也有這樣的情況會導(dǎo)致潛在的上線風(fēng)險(xiǎn)厚棵。

如果要控制上線的風(fēng)險(xiǎn),我們就必需要解決這個(gè)問題蔼紧,這時(shí)候婆硬,就需要使用 npm shrinkwrap
這個(gè)命令來解決問題。
介紹 shrinkwrap
npm shrinkwrap
可以按照當(dāng)前項(xiàng)目 node_modules 目錄內(nèi)的安裝包情況生成穩(wěn)定的版本號描述奸例。
比方說彬犯,有一個(gè)包 A
{ "name": "A", "version": "0.1.0", "dependencies": { "B": "<0.1.0" } }

還有一個(gè)包 B
{ "name": "B", "version": "0.0.1", "dependencies": { "C": "<0.1.0" } }

以及包 C
{ "name": "C", "version": "0.0.1" }

你的項(xiàng)目只依賴于 A,于是 npm install
會得到這樣的目錄結(jié)構(gòu)
A@0.1.0 -- B@0.0.1-- C@0.0.1

這時(shí)候查吊,B@0.0.2 發(fā)布了谐区,這時(shí)候在一個(gè)新的環(huán)境下執(zhí)行 npm install
將得到
A@0.1.0 -- B@0.0.2-- C@0.0.1

這時(shí)候兩次安裝得到的版本號就不一致了。而通過 shrinkwrap 命令逻卖,我們可以保證在所有環(huán)境下安裝得到穩(wěn)定的結(jié)果宋列。
在項(xiàng)目引入新包的時(shí)候,或者 A 的開發(fā)者執(zhí)行一下 npm shrinkwrap
评也,可以在項(xiàng)目根目錄得到一個(gè) npm-shrinkwrap.json 文件炼杖。
這個(gè)文件內(nèi)容如下
{ "name": "A", "version": "0.1.0", "dependencies": { "B": { "version": "0.0.1", "dependencies": { "C": { "version": "0.0.1" } } } } }

shrinkwrap 命令根據(jù)目前安裝在node_modules的文件情況鎖定依賴版本。在項(xiàng)目中執(zhí)行 npm install
的時(shí)候盗迟,npm 會檢查在根目錄下有沒有 npm-shrinkwrap.json 文件坤邪,如果 shrinkwrap 文件存在的話,npm 會使用它(而不是 package.json)來確定安裝的各個(gè)包的版本號信息罚缕。
這樣一來艇纺,在安裝時(shí)候確定的所有版本信息會穩(wěn)定的固化在 shrinkwrap 里。無論是A邮弹,B 和 C中的版本如何變化黔衡,或者它們的 package.json 文件如何修改,你始終能保證腌乡,在你項(xiàng)目中執(zhí)行 npm install
的到的版本號時(shí)穩(wěn)定的盟劫。
在開發(fā)中使用 shrinkwrap
在開發(fā)過程中,引入一個(gè)新包的流程如下
npm install PACKAGE_NAME@VERSION --save
獲取特定版本的包
測試功能
測試功能正常后导饲,執(zhí)行 npm shrinkwrap
把依賴寫入 shrinkwrap 文件
在代碼倉庫中提交 shrinkwrap / package.json 描述

升級一個(gè)包的流程應(yīng)該是這樣
npm outdated
獲取項(xiàng)目所有依賴的更新信息
npm install PACKAGE_NAME@VERSION --save
獲取特定版本的包
測試功能
測試功能正常后捞高,執(zhí)行 npm shrinkwrap
把依賴寫入 shrinkwrap 文件
在代碼倉庫中提交 shrinkwrap / package.json 描述

刪除一個(gè)包的流程如下
npm uninstall PACKAGE_NAME --save
刪除這個(gè)包
測試功能
測試功能正常后,執(zhí)行 npm shrinkwrap
把更新的依賴寫入 shrinkwrap 文件
在代碼倉庫中提交 shrinkwrap / package.json 描述

比一般的安裝多了一步手工生成 shrinkwrap 文件渣锦。在實(shí)際工作中硝岗,有時(shí)候我們會忘記這一步,導(dǎo)致上線時(shí)候沒有獲取到依賴包的特定版本袋毙。
介紹 npm-shrinkwrap-install
去年我引入 shrinkwrap 工作流的時(shí)候型檀,npm 官方的 shrinkwrap 命令還有很多問題,比如
在生成版本描述的時(shí)候不會忽略 devDependencies 和 optionalDependencies
不會檢查 package.json 和 shrinkwrap 文件的差異
不會刪除 from 字段(這個(gè)字段沒有用)听盖,導(dǎo)致在 diff 時(shí)候會出現(xiàn)多余的信息

所以我寫了一個(gè) bin/shrinkwrap 腳本胀溺。這個(gè)腳本會自動對比 package.json 和 npm-shrinkwrap.json 文件的區(qū)別,獲取需要更新的版本皆看,然后對相關(guān)信息進(jìn)行更新仓坞。(更新:現(xiàn)在的 npm shrinkwrap 已經(jīng)修復(fù)了很多的問題,但 from 字段有時(shí)候仍然有些小問題腰吟。)
當(dāng)時(shí)為了忽略 devDependencies 和 optionalDependencies无埃,我會執(zhí)行 npm prune
刪除額外的包之后才生成版本描述,然后再把其它的包裝回來毛雇,導(dǎo)致腳本執(zhí)行時(shí)間有點(diǎn)長嫉称。
后面 uber 發(fā)布了 npm-shrinkwrap 工具,可以更高效的生成版本描述灵疮≈模可惜這個(gè)包不支持 scoped package。我花了一點(diǎn)時(shí)間 patch 了這個(gè)工具震捣,因?yàn)樗鼈兊陌l(fā)版太慢荔棉,所以我發(fā)布了一份 @th507/npm-shrinkwrap,可以支持 scoped package蒿赢。
在上面這個(gè)包的基礎(chǔ)上江耀,我還寫了另外一個(gè)小工具,叫做 npm-shrinkwrap-install诉植,它可以無縫替換 npm install
的執(zhí)行過程祥国,讓 shrinkwrap 文件的生成變得更自動。
安裝
$ npm install npm-shrinkwrap-install

安裝完成之后晾腔,有如下命令可以使用
安裝依賴的命令npm-installnpm-i
刪除依賴的命令npm-unisntallnpm-unnpm-removenpm-rmnpm-r
手工生成 shrinkwrap 描述npm-shrinkwrap
在開發(fā)中使用 npm-install
引入新依賴包
npm-install PACKAGE_NAME@VERSION --save
獲取特定版本的包
測試功能
在代碼倉庫中提交 shrinkwrap / package.json 描述

npm-install 在運(yùn)行時(shí)會對 package.json 中的依賴做校驗(yàn)舌稀,如果你直接修改 package.json 文件,或者是指定了一個(gè)非嚴(yán)格的版本號灼擂,在運(yùn)行的時(shí)候都會做更新檢查壁查,防止遺漏。
值得注意的是剔应,因?yàn)?npm-install 會進(jìn)行依賴對比和校驗(yàn)睡腿,在安裝新包的時(shí)候需要帶上 --save 參數(shù)语御。否則,在自動更新 shrinkwrap 描述之前席怪,腳本會自動移除多余的依賴包应闯,導(dǎo)致你新安裝的包被刪除。
升級依賴包
npm outdated
獲取項(xiàng)目所有依賴的更新信息
npm-install PACKAGE_NAME@VERSION --save
獲取特定版本的包
測試功能
在代碼倉庫中提交 shrinkwrap / package.json 描述

package.json 文件中指定了一個(gè)非嚴(yán)格的版本號的依賴在運(yùn)行 npm-install 的時(shí)候會做自動更新檢查挂捻,無需指定版本號碉纺,如果你不希望進(jìn)行自動更新,請?jiān)?package.json 中使用嚴(yán)格版本號刻撒。
刪除依賴包
npm-uninstall PACKAGE_NAME --save
刪除這個(gè)包
測試功能
在代碼倉庫中提交 shrinkwrap / package.json 描述

可以看到骨田,在實(shí)際使用中沒有引入額外的流程,對開發(fā)者基本沒有學(xué)習(xí)的負(fù)擔(dān)声怔。但仍然注意态贤,不建議開發(fā)者執(zhí)行 npm update
命令更新所有的依賴。
小結(jié)
通過引入 shrinkwrap 文件醋火,我們可以較好的管理項(xiàng)目的依賴關(guān)系抵卫,讓上線變得更輕松。需要注意的是胎撇,盡管相關(guān)工具可以幫助你減化工作流程介粘、可靠的分發(fā)依賴描述,但工具不能取代功能測試晚树;每次升級依賴版本之后姻采,我們?nèi)匀粦?yīng)該進(jìn)行相關(guān)測試來確保項(xiàng)目能可靠的運(yùn)行在該環(huán)境中。
如果使用 @th507/npm-shrinkwrap 或者 npm-shrinkwrap-install 有任何問題歡迎給我提 issue爵憎。
本文沒有涉及如何優(yōu)化上線前的安裝過程慨亲,縮短依賴構(gòu)建時(shí)間,這個(gè)問題留給專門的文介紹宝鼓。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刑棵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子愚铡,更是在濱河造成了極大的恐慌蛉签,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沥寥,死亡現(xiàn)場離奇詭異碍舍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)邑雅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門片橡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人淮野,你說我怎么就攤上這事捧书〈蹬荩” “怎么了?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵经瓷,是天一觀的道長爆哑。 經(jīng)常有香客問我,道長了嚎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任廊营,我火速辦了婚禮歪泳,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘露筒。我一直安慰自己呐伞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布慎式。 她就那樣靜靜地躺著伶氢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪瘪吏。 梳的紋絲不亂的頭發(fā)上癣防,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機(jī)與錄音掌眠,去河邊找鬼蕾盯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蓝丙,可吹牛的內(nèi)容都是我干的级遭。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼渺尘,長吁一口氣:“原來是場噩夢啊……” “哼挫鸽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鸥跟,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤丢郊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后医咨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚂夕,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年腋逆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婿牍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,742評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惩歉,死狀恐怖等脂,靈堂內(nèi)的尸體忽然破棺而出俏蛮,到底是詐尸還是另有隱情,我是刑警寧澤上遥,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布搏屑,位于F島的核電站,受9級特大地震影響粉楚,放射性物質(zhì)發(fā)生泄漏辣恋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一模软、第九天 我趴在偏房一處隱蔽的房頂上張望伟骨。 院中可真熱鬧,春花似錦燃异、人聲如沸携狭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逛腿。三九已至,卻和暖如春仅颇,著一層夾襖步出監(jiān)牢的瞬間单默,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工忘瓦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留雕凹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓政冻,卻偏偏與公主長得像枚抵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子明场,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容