package-lock.json 需要寫進 .gitignore 嗎?
眾所周知,npm 借鑒 yarn 在 v5 推出 package-lock.json 文件。
筆者經過了解發現:
在 jquery 項目中,package-lock.json 明確被寫進 .gitignore。參考:jquery 項目中的 .gitignore。而在另一個知名項目 vue 中,package-lock.json 則沒有被寫進 .gitignore。
那麼 package-lock.json 到底需不需要寫進 .gitignore 呢?
相關 Stack Overflow 問題:Should package-lock.json also be published?
先給出回答:
package-lock.json 不應寫進 .gitignore。這點無論你是否使用 lock 都是一樣的。
具體來說:
如果你使用 lock 機制,則應該將 package-lock.json 提交到 repo 中。比如 Vue 採取了該策略。
如果你不使用 lock 機制,則應該加入 .npmrc 文件,內容為 package-lock=false
,並提交到 repo 中。比如 ESLint 採取了該策略。
例外是,如果你使用 yarn 並且不打算使用 npm,則可以把 package-lock.json 列入 .gitignore(比如 Babel);反之如果你使用 npm 並且不打算使用 yarn,則可以把 yarn.lock 列入 .gitignore (比如 TypeScript)。
如果你不按照上述方式做,請確定你清楚自己在幹什麼。比如 jQuery 為什麼把 package-lock.json 寫入 .gitignore 可以看其 commit message:Build: Remove package-lock.json, add it to .gitignore · jquery/jquery@7037fac 。簡單說就是 optional 依賴包會導致不同平台上的 package-lock.json 發生變更。jQuery 的人認為這有問題,所以暫時性 ignore 了它。先不管是不是有更好的方式或者其他 workaround,最新的 npm 5.6.0 其實已經解決了這個問題。(想混個 jQuery contributor 的同學可以趕緊去提交 PR 了,成功之後可以給我發個紅包當謝禮。)
有一些不使用 lock 機制的庫,已經使用了 .npmrc ,但也把 package-lock.json 列入了 .gitignore,這是沒有必要的。
至於到底要不要 lock,是另一個話題了。儘管題主也許想問的實際上就是要不要 lock,不過我還是按照題面作答。如果想討論要不要 lock,建議移步已有的 透過 js-beautify@1.7.0 的 Bug 來看,npm 默認的 lock 機制是否重要? 問題。
這是要看社區環境的,如果社區保守,你也可以保守。如果社區激進,你可能不得不也激進。
像 Rails 和 Java 這樣穩重(保守)的社區,第三方一般都會嚴格測試後才發布新版本,而且發布頻率遠沒有 Node 社區的高,並且如果版本有重大 bug 會發布公告的。在這種社區里,大家一般都會加 lock。
而 Node 社區,left padding 之前,想刪依賴就刪依賴,這樣的話加不加 lock 其實都是個死 。left padding 事件之後好像不能刪除已經發布的包了。 不過由於這個社區發版本太頻繁,所以你不知道當前版本質量如何,也不知道下個版本質量如何,大部分都是靠 star 來評判質量,這樣的話其實 lock 不 lock 依然還是差不多,保守一點就 lock ,激進一點就不 lock。
當年 node 想保守一點停在 0.12 不動,結果呢,社區直接 fork 出一個 io.js 來表達不滿。node 想保持地位不得不妥協也激進起來,直接升級到 Node 3。node 自己想把自己 lock 起來都做不到呢。
然後保守派又不幹了。
你看 npm 3 一開始默認不 lock,被 yarn 教育了幾下之後還不是乖乖加默認 lock。默認選項本來就應該偏向於保守才對,有人想激進就自己加參數吧。當前版本如果有隱藏漏洞怎麼辦?
做安全測試和異常監控啊,密切關注你依賴的包的新聞呀,難道有什麼一勞永逸的辦法嗎?死馬老師的文章第一條就說了,一定要選擇靠譜的開源包。但這個前提我覺得實在是太難保證了,npm install 之後幾百個包我怎麼去一個一個篩查呢,靠譜的項目可能會變得不靠譜,不靠譜的項目也可能會變得靠譜,我無法預知未來。我還是保守點更新吧。
不過 lock 帶來的問題就是,你一覺醒來,發現有 10% 的依賴已經 outdated 了。誰讓第三方發包發那麼勤快(草率)呢?所以我也能理解那些主張不 lock 的人的想法,不想被落下太遠。
最終我還是選擇
1 加 lock,加測試2 定期刪除 lock 做升級(Node 應用如果不做這一條,遲早要完)3 配以其他安全措施。其實問題的癥結是
1 你希望你的代碼被第三方主動更新
2 還是願意你的代碼只有自己能主動更新相信第三方就選 1,相信自己就選 2
或者說得不好聽一點想把鍋摔給第三方就選 1,想把鍋扛在自己身上就選 2 (我好像突然領悟了什麼(??? ·? ???) )
然而程序員都知道一個真理:只要是人類,那就是不能 100% 相信的,因為人類絕對會出錯(墨菲定律)。
所以這道題,無解……
沒有一勞永逸的辦法,程序員就是勞碌命啊!
不過還有另外一條定律,大部分非小白程序員覺得自己的水平是高於平均水平的,所以應該更偏向於相信自己才對啊。
我就是這種自戀的程序員,所以我加 lock ? ?(?ˉ???ˉ???)?」哇哈哈~我來說說不一樣的點。
npm 5.x 發布以來到現在的5.6.0 lock的作用變更過好多次,現在網上很多小白文都是停留在以前的文檔翻譯。
從npm3.x更新到了npm5,但是發現執行 `npm i ` 時的現象跟網路上的科普文不太一致。
有提到不管怎麼修改package.json文件,重複執行npm i,npm都會根據lock文件描述的版本信息進行下載。
也有提到重複npm i時,npm會不顧lock的信息,根據package.json中的包Semantic versioning 版本信息下載更新模塊(lock貌似沒啥用了)。
**查閱資料得知,自npm 5.0版本發布以來,npm i的規則發生了三次變化。**
1、npm 5.0.x 版本,不管package.json怎麼變,npm i 時都會根據lock文件下載
package-lock.json file not updated after package.json file is changed · Issue #16866 · npm/npm
這個 issue 控訴了這個問題,明明手動改了package.json,為啥不給我升級包!然後就導致了5.1.0的問題...
2、5.1.0版本後 npm install 會無視lock文件 去下載最新的npm
然後有人提了這個issue why is package-lock being ignored? · Issue #17979 · npm/npm
控訴這個問題,最後演變成5.4.2版本後的規則。
3、5.4.2版本後 why is package-lock being ignored? · Issue #17979 · npm/npm
大致意思是,如果改了package.json,且package.json和lock文件不同,那麼執行`npm i`時npm會根據package中的版本號以及語義含義去下載最新的包,並更新至lock。
如果兩者是同一狀態,那麼執行`npm i `都會根據lock下載,不會理會package實際包的版本是否有新。贊同賀老回答,某些回答看來我又要開懟了,你們提醒我,陪玩兒子就開始懟,欺我node社區無人乎?
一個偶然的機會我讀了死馬老師的文章 為什麼我不使用 shrinkwrap(lock)
# 官方推薦的方式
This file is intended to be committed into source repositories, and serves various purposes:
......
檢索一番,大致提及:package-lock.json ①要提交到源代碼倉庫中②不建議發布到 npm 。
而 ① 的必要條件就是該文件不能寫入 .gitignore。所以,官方的傾向是『package-lock.json 不要寫入 .gitignore 中』
參考:package-lock.json 官方文檔
# 寫入與否,各有利弊
回到我們的問題,只能說這件事情有利有弊。
實際上 package-lock.json 機制,只能保證模塊維護者踩過的坑都解決了,但是不排除存在未被發現的地雷!!!若不寫入 .gitignore,則極大程度上降低各個依賴的升級版本中新產生的 bug 對原有功能的影響,但是原依賴中潛在的雷可能永遠藏起來,直到不確定的某一天突然爆炸。若寫入 .gitignore,則保證模塊一直與時俱進,有問題能夠及時反饋發現。
# 個人觀點
說說個人想法。如果一個模塊是很活躍的,維護者也很有時間,那就寫入 .gitignore。如果一個模塊已經 deprecated 了,維護者很忙,那就不要寫入 .gitignore 。因為依賴越多,依賴升級之後可能帶來的新 bug 的幾率就相應越大,所以掛出免戰牌,開啟勿擾模式是個不錯的選擇。假設確實碰到了發現新問題,需要更新依賴版本,那就向維護者提 issue 和 pr 提示對方升級依賴包。
# 吐槽
最煩的就是維護者太忙以至於沒空搭理非常重要的 pull request 的情況了。
Update gift dependency by tekd · Pull Request #117 · shinnn/gulp-gh-pages
正好寫了一篇文章。直接貼近來了:
## package.json 的困境
package.json 不能夠保證每次安裝的依賴的唯一性。 舉例來說:
A 模塊:
```
{
"name": "A",
"version": "0.1.0",
"dependencies": {
"B": "&<0.1.0"
}
}
```
依賴版本號小於 0.1.0 的 B 模塊。
```
{
"name": "B",
"version": "0.0.1",
"dependencies": {
"C": "&<0.1.0"
}
}
```
我們在開發的時候 B 模塊時 0.0.1。下一次執行 npm install 的 B 模塊發布了 0.0.2 版本。此時安裝到的版本時 B 的 0.02 版。出現了不一致情況。
npm 推薦 [sermer](Semantic Versioning 2.0.0) 的規則來管理自己的版本發布:
```
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
```
sermer 的目的是讓代碼升級到最新的 bug fix。但是,通常一個項目依賴成百上千個模塊,你並不能確定哪一個模塊會出問題。
**[一定要選擇靠譜的開源模塊](為什麼我不使用 shrinkwrap(lock))** 並不能解決你的憂慮。
相信別人,還是相信自己?從可控性角度來說,當然是相信自己。**我們需要的是一個 single of truth 的依賴樹。**
## yarn.lock
npm 的 對待此問題的行動遲緩 (君不見 nodejs、io-js), facebook 開發出了 yarn 來解決npm 的 lock 和 cache 等問題。
![image](https://user-images.githubusercontent.com/3912408/34292451-f25806a2-e73b-11e7-96f2-1192e96e7398.png)
版本鎖定 與 install 等操作同步,保證了 node_modules 的一致性。實現了我們想要的 single of truth 的依賴樹。
## package-lock.json
有競爭就有改進的動力。 npm 5 發布,默認支持 package-lock.json。
```
package-lock.json is automatically generated for any operations where npm modifies either the node_modules tree, or package.json. It describes the exact tree that was generated, such that subsequent installs are able to generate identical trees, regardless of intermediate dependency updates.
```
一個簡單的例子:
```
{
"name": "mobi-pandaren-front-web",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"align-text": {
"version": "0.1.4",
"resolved": "http://npm.pandatv.com/align-text/-/align-text-0.1.4.tgz",
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
"requires": {
"kind-of": "3.2.2",
"longest": "1.0.1",
"repeat-string": "1.6.1"
}
},
"amdefine": {
"version": "1.0.1",
"resolved": "http://npm.pandatv.com/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
},
"asap": {
"version": "2.0.6",
"resolved": "http://npm.pandatv.com/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
...
```
package-lock 描述了所有相關依賴的具體版本,並且會隨著 npm install 變化而變化。彌補了 package.json 的不足。
## npm-shrinkwrap.json
npm-shrinkwrap.json 和 package-lock.json 內容是相同的。不同之處在於:
1. npm-shrinkwrap.json 優先順序較高。install 時會優先採用。
2. 可發布到 registry。使用場景僅在:模塊通常以 daemon 形式後台運行,或者依賴在dev中。其他請用package-lock.json。
## 結論
要使得避免「我這裡是好的」這種情況。npm 5 是不錯的選擇。低版本推薦用 yarn 替代。
我建議不要把package-lock.json給ignore掉。在npm默認支持lock之前,遇到過1次生產環境錯誤無法在開放環境復現的情況。排查到source code發現是因為package.json寫了~做匹配,新版本引入了一個bug。
之後有一段時間寫死版本號,而後yarn、 npm lock。但是npm剛剛出現package-lock.json邏輯也有些問題。當package.json更新版本時,npm仍然會跟著package-lock.json來選擇版本後來改成package.json優先了(https://github.com/npm/npm/issues/16866)。就目前看,共用package-lock.json和不用比沒有明顯的壞處。固然不做lock會有可能fix一些沒有遇到dwbug。也有可能引入新的bug。我更傾向於lock受版本控制而使模塊變得更可控。鎖定版本不才是正常的嗎,想更新庫版本直接更新就是了,lock文件又不會限制你更新。
推薦閱讀:
※深JS(2015 JS中國開發者大會)有哪些女生參加?
※如何評價fibjs?
※Promise then中回調為什麼是非同步執行?
※既然 Node.js 是單線程,又是怎麼做到支持非同步函數調用的?
※vuejs怎麼在伺服器部署?