NodeJS的lock file及其使用

什麼是lock file

lock file文件描述了整顆依賴樹,包含了特定版本的傳遞依賴(依賴嵌套)關係。npm中用的是package-lock.json,yarn中用的是yarn.lock。

package-lock.json如下所示:

yarn.lock如下所示:

lockfile包含的關鍵信息包括

  • 安裝每個依賴的實際版本
  • 每個依賴的依賴(即傳遞依賴)
  • 包的校驗和(以驗證包的完整性)

使用lockfile的方法如下:

npm ci # will install exactly what's in the package-lock.json
yarn install --frozen-lock-file # will install exactly what's in yarn.lock without updating it

什麼時候使用lockfile

當我們在構建一個web應用時,建議使用上述的命令,來執行構建和發佈。包括在CI中使用上述命令。這樣我們可以確保每個開發驗證人員、構建系統/CI系統使用完全相同的依賴項。

因此,在yarn和npm的文檔裏都有建議,在提交代碼的時候,把lockfile也提交進GIT倉作爲代碼的一部分。

這也有利於可重複構建。對外交付時,任何時候都可以通過相同的代碼構建出一致的包,客戶也易於理解與驗收。

什麼時候不使用lockfile

當我們代碼的構建結果是一箇中間依賴,即被其他項目依賴時,不建議使用。換言之,lockfile應該進入頂層項目(最終用戶消費的程序)的源碼版本控制。

爲什麼被依賴件的源碼倉不建議使用lock file呢?

主要原因在於npm倉庫上發佈的包本身。即,你發佈到npm的內容並不總是與git倉上的內容相同。

npm使用npm pack命令將需要發佈的文件打成一個tarball,你可以嘗試使用如下命令來查看npm打包了哪些文件

npm pack --dry-run

也可以在 npm的doc 查看打包的完整文件列表,摘錄其打包的內容如下

Certain files are always included, regardless of settings:

  • package.json
  • README
  • CHANGES / CHANGELOG / HISTORY
  • LICENSE / LICENCE
  • NOTICE
  • The file in the "main" field

README, CHANGES, LICENSE & NOTICE can have any case and extension.

Conversely, some files are always ignored:

  • .git
  • CVS
  • .svn
  • .hg
  • .lock-wscript
  • .wafpickle-N
  • .*.swp
  • .DS_Store
  • ._*
  • npm-debug.log
  • .npmrc
  • node_modules
  • config.gypi
  • *.orig

可以看到,npm只打包了package.json,而沒有打包package-lock.json。

這種情況下,當別人的工程依賴你的npm包的時候,無法下載到你的工程的package-lock.json,導致實際依賴的你的包的傳遞依賴(即你所依賴的包)的版本不一定與你發佈時的一致。

所以,作爲一個被別人依賴的模塊,關鍵在於讓自己“靠譜”一些,而這點並不依靠lock文件。建議的“靠譜”方法包括:

  1. 嚴格遵循 semver 語義化版本的原則來進行版本發佈。對不遵循 semver 發佈的模塊敬而遠之。
  1. 選擇依賴時,儘量選擇npm 上有較大的下載量的,當遇到模塊問題時,波及範圍越廣,其修復的速度越快。
  1. 開源模塊在github 上的問題反饋迅速,或者是由一些知名開發者維護。質量有一定的保障
  1. 版本號中,patch 位變更的發佈不多(說明 bug fix 不多)。

有的人會認爲,即使如此,仍然應該把package-lock文件歸檔到git倉,哪怕它實際沒有被使用。畢竟要使用lockfile都是單獨的命令,如果不使用的話,歸檔也沒什麼影響。但是,事實真的如此嗎?

首先,npm包管理是使用的semver 語義化版本的機制來幫助開發者管理依賴,開發者可以在 package.json中通過 ^1.1.0 或者 ~1.0.0 的方式來引入模塊,如果開發者信任他們依賴的模塊,開發者可以通過 ^ 來鎖定一個模塊的大版本,這樣在每次重新安裝依賴或者打包的時候,都能夠享受到這個包所有的新增功能和 bug 修復。而這個模塊如果遵循 semver 原則,也不用擔心它會引入一些不兼容變更導致項目出現一些未知異常。最終開發者需要關心的其實只有直接依賴的這些模塊是否足夠靠譜。 這樣一來,每個模塊對自身的依賴負責,一個項目雖然只直接依賴了十來個模塊,但其最終卻間接的依賴了上千個模塊。真正想要通過package-lock.json去管理好這一份多達上千個模塊的模塊是非常困難的。(一個關於lockfile成爲安全侵入的入口的例子見這裏https://snyk.io/blog/why-npm-lockfiles-can-be-a-security-blindspot-for-injecting-malicious-modules/,例子中,正是由於lockfile動輒幾百上千行的修改,對commit審覈造成了很大的壓力,而通常一個commit也就幾十行的修改。)

其次,在有lockfile文件的情況下,npm install的真正行爲情況如下:

1、npm 5.0.x 版本,不管package.json怎麼變,npm install 時都會根據lock文件下載

2、5.1.0 - 5.4.2版本 npm install 會無視lock文件,去下載符合規則的最新的包。

3、5.4.2版本後,如果改了package.json,且package.json和lock文件不同,那麼執行npm install時npm會根據package.json中的版本號去下載最新的包,並更新lock文件。如果沒有更新package.json,那麼npm install會根據lock文件下載,而不會理會package.json中實際的包的版本是否有更新。

換句話說,當存在lockfile的情況下,即使有新的補丁包存在,都可能不會被使用 。而這點顯然不是我們希望的

最後,重申一遍,lockfile應該進入頂層項目(最終用戶消費的程序)的源碼版本控制,中間模塊不建議使用lockfile。

P.S:有人會認爲開源社區大多用了lock。其實仔細看github上的提交就會發現,lock文件很多是不允許個人提交的,lock文件的更新大多由機器人自動更新,也就是說,這裏的lock文件,是作爲一個CI快照更新上庫的。同樣的,也有不少高星的開源社區,例如ESlint,庫上沒有lock文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章