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)

我總結一下自己學習到的東西:之所以作者不使用 shrinkwrap, 是因為這個機制會鎖死各個依賴的版本號,而某個指定依賴可能存在潛在 bug 隱患。如果鎖死,則 bug 隱患會一直存在,像地雷一樣,直到有人觸發了才會被發現。而如果不鎖死,則可能隨著依賴包的升級,bug 就默默被解決了。

# 官方推薦的方式

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怎麼在伺服器部署?

TAG:Git | 軟體配置管理 | Nodejs | npm |