何時咱們不該該使用鎖文件

調試程序時遇到的最多見情景之一多是「在個人電腦上明明是好的」。這一般是因爲對程序帶有bug和本身系統的底層依賴不一樣的結果。 所以,yarn和npm在引入了的「lock files」,能夠跟蹤依賴項的確切版本。可是,當您開發將發佈到npm的包時,應避免使用此類鎖文件。在這篇博文中,咱們將討論爲何要這樣。

快速總結

若是您構建一個相似web服務器的應用程序,那麼鎖定文件很是有用。可是,若是將庫或CLI發佈到npm,則永遠不要發佈鎖文件。若是使用鎖文件,則意味着您的用戶和您可能使用不一樣版本的依賴項。html

什麼是鎖文件?

一個鎖文件描述了整個依賴樹,由於它在建立時被解析,包括與特定版本的嵌套依賴關係。在npm中,這些被稱爲package-lock.json和在yarn中,它們被稱爲yarn.lock。在npm和yarn中,它們都放在package.json旁邊。node

package-lock.json看起來像這樣:git

{
 "name": "lockfile-demo",
 "version": "1.0.0",
 "lockfileVersion": 1,
 "requires": true,
 "dependencies": {
   "ansi-styles": {
     "version": "3.2.1",
     "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
     "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
     "requires": {
       "color-convert": "^1.9.0"
     }
   },
   "chalk": {
     "version": "2.4.2",
     "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
     "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
     "requires": {
       "ansi-styles": "^3.2.1",
       "escape-string-regexp": "^1.0.5",
       "supports-color": "^5.3.0"
     }
   }
 }
}
複製代碼

yarn.lock文件格式不一樣,但包含相似的信息:web

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


ansi-styles@^3.2.1:
  version "3.2.1"
  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
 dependencies:
        color-convert "^1.9.0"

chalk@^2.4.2:
  version "2.4.2"
  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
 dependencies:
        ansi-styles "^3.2.1"
        escape-string-regexp "^1.0.5"
        supports-color "^5.3.0"
複製代碼

這兩份文件都記錄了一些重要的信息:npm

  1. 安裝的每一個依賴項的實際版本
  2. 每一個依賴項的依賴項
  3. 已解析的包,包括一個校驗和,用於驗證包的完整性

所以,若是全部依賴項都列在鎖文件中,爲何還要在package.json中列出它們呢?爲何咱們須要兩個文件?json

package.json vs. Lock File

項目「package.json」文件中的dependencies字段的目的是顯示應該安裝的依賴項,而不是這些依賴項的依賴項。依賴項能夠指定精確的版本或在Semver版本號範圍內。對於使用semver版本號規則的,npm或yarn將選擇最適合安裝的版本。bash

這意味着,若是在發佈新版本期間運行兩次npm install,那麼實際上可能獲得不一樣依賴項的版本。例如,若是您使用npm install twilio安裝一個叫twilio的依賴項。json可能有一個相似的條目:服務器

{
  "dependencies": {
     "twilio": "^3.30.3"
  }
}
複製代碼

若是你在npm頁面上查看semver的文檔,你會發現^實際上意味着任何大於3.30.3和小於4.0.0的版本都是有效的。所以,若是任何新版本發佈,而你沒有一個鎖文件存在,npm或yarn將安裝那個新的版本並不會自動更新package.json。然而,若是存在鎖文件就不會這樣子。併發

若是npm或yarn找到各自的鎖文件,它們將使用這些文件進行模塊安裝。這對於在須要確保測試在可預測環境中運行的平臺上進行持續集成(CI)之類的狀況特別有用。對於這個用例,您可使用特殊的命令或標誌與相應的包管理器:app

npm ci # 將確切地安裝package-lock.json中的內容
yarn install --frozen-lock-file # 將準確地安裝yarn.lock中的內容。不更新鎖定
複製代碼

這在構建web應用程序或服務器之類的應用程序時很是有用,由於在CI環境中,咱們但願模擬用戶的行爲。所以,若是咱們開始在源代碼控制中跟蹤鎖文件(如git),咱們能夠確保每一個開發人員、服務器、構建系統和CI系統使用相同版本的依賴。

那麼,當咱們編寫庫或其餘打算髮布到npm倉庫的東西時,爲何不但願作一樣的事情呢?爲了回答這個問題,咱們首先要談談發包是如何運做的。

如何發佈模塊

與一些人通常認知不一樣,發佈到npm的內容並不老是與GitHub上的內容相同,也不老是與項目中的整體內容相同。模塊發佈的方式是,npm將經過檢查package.json文件中的files配置和.npmignore文件來肯定應該發佈的文件。若是沒有.npmignore文件則使用.gitignore文件。還有一些文件老是包含在其中,而另外一些文件老是被排除在外。您能夠在npm頁面上找到這些文件的完整列表。例如,.git文件夾老是會被忽略。

以後,npm將獲取文件列表,並使用npm pack將它們打包成一個tarball。若是你想查看哪些文件被打包,你能夠運行npm pack --dry-run命令,它將輸出與全部文件:

而後,該tarball將被上傳到npm包倉庫。運行此命令時,您可能注意到了,package-lock.json並無被打入包中。這是由於package-lock.json老是會被忽略,正如npm文檔中的列表所指定的那樣。

這意味着若是其餘開發人員安裝了你發佈的包,他們將永遠不會下載你的package-lock.json。所以,在安裝期間將徹底不受鎖文件影響。

這可能會意外地致使「在個人機器明明是好的」的效果,由於您的CI和開發人員環境可能會得到不一樣版本的依賴關係。那麼咱們應該作些什麼呢?

禁用鎖定文件和Shrinkwrapping文件

首先,咱們應該確保中止跟蹤鎖定文件。若是您正在使用git,請將如下內容添加到項目中的.gitignore文件中:

yarn.lock
package-lock.json
複製代碼

yarn官方文檔說即便是你寫的庫,也應該登記一份yarn.lock文件。可是,若是你想確保擁有與用戶相同的體驗,我建議將yarn.lock添加到.gitignore

您能夠關閉package-lock.json文件的生成。經過在項目中建立或將如下內容添加到.npmrc文件

package-lock = false
複製代碼

對於yarn,您可使用yarn install --no-lockfile命令不生成鎖定文件。

然而,不是說由於咱們不使用package-lock.json文件就沒有辦法鎖定依賴項和子依賴項。咱們還可使用另外一個名爲npm-shrinkwrap.json的文件。

它基本上與package-lock.json相同。由npm shrinkwrap命令生成,並實際打包併發布到npm倉庫。

所以,經過將npm shrinkwrap做爲預打包腳本甚至git提交鉤子添加到npm腳本中,您能夠確保在開發環境、用戶和CI中使用相同版本的依賴關係。

有一點很重要,必定要當心使用。經過使用shrinkwrap文件安裝依賴包,你能夠鎖定準確的版本,這可能很棒,但它也能夠阻止人們得到關鍵補丁。npm強烈反對對庫使用shrinkwrap,並建議只在CLIs或相似的場景使用shrinkwrap

怎樣才能獲得更多信息

雖然在npm文檔中有不少關於這方面的資料,但有時很難找到。若是您想更好地瞭解要安裝或打包的內容,一個常見的命令就是--dry-run。運行該命令不影響應用。例如npm install --dry-run實際上不會將依賴項安裝到項目目錄,npm publish --dry-run實際上不會發布包。

下面是一些你可能想要查看的命令:

npm ci --dry-run # 基於package-lock.json 或者 npm-shrinkwrap.json文件模擬安裝
npm pack --dry-run # 列出了全部要打包的文件以及元信息
npm install <dep> --verbose --dry-run # 將以verbose模式運行包的安裝,而無需實際將其安裝到文件系統
複製代碼

有關該主題的一些有用的文檔連接以下:

這在很大程度上取決於npm如何處理打包、發佈和安裝依賴項,並且隨着不斷變化的環境,這一點可能會在某一時刻發生變化。我但願這篇文章能讓你對這個複雜的話題有更多的瞭解。

原文:When Not to Use Lock Files with Node.js

相關文章
相關標籤/搜索