yarn-lock 你鎖明白了嗎?

前言

你是否遇到過這種場景,項目拉下來後執行yarn install安裝依賴,yarn.lock 卻提示有變更,我明明什麼都沒做呢,這是爲啥?但是基於以往的經驗(出過 case),yarn.lock 不應該有 diff 纔對,一定是哪裏出了問題!但是git diff yarn.lock發現自己也看不明白(我好菜 😭)

舉個 🌰

還原一下我出過的 Case 😭 項目裏原本有個依賴foo

同學 A 是負責foo這個庫的開發,一次發版後,到項目裏升級這個依賴到 1.1.0,但是提交代碼時,只變更了 package.json,沒有更新 yarn.lock

然後大家每次拉新代碼並安裝依賴後,本地總有個煩人的 yarn.lock 文件變更,大家心想應該是有人升級依賴的時候忘記提交 yarn.lock 了於是同學 B 行動了:

然後過了一天,拉羣了 😭

About yarn.lock

yarn.lock 的作用?

鎖定唯一版本!

yarn.lock 長啥樣?

裏面都是一塊一塊的,每一塊大概長下面這樣:

core-js-compat@^3.0.0:
  version "3.14.0"
  resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.14.0.tgz#b574dabf29184681d5b16357bd33d104df3d29a5"
  integrity sha1-tXTavykYRoHVsWNXvTPRBN89KaU=
  dependencies:
    browserslist "^4.16.6"
    semver "7.0.0"

Identifier(s)

第一行的core-js-compat@^3.0.0是依賴的 identifier。和 package.json 裏對應的包名和版本區間,用@連接。這邊的標題裏帶了(s),是因爲多個 Identifier 最終可能都指向同一個版本(具體例子可以看下文### dependencies裏給出的例子)

version

第二行version是實際安裝的版本。通常是滿足版本區間裏的一個版本,比如上一行 identifier 裏版本區間是^3.0.0,這裏實際安裝的是3.14.0,符合要求。但是爲什麼要說是 “通常” 呢,因爲有例外,在後文### resolutions部分會講到。

resolved

第三行resolved的是一個鏈接,是下載這個包的地址。這個 url 裏的域名部分跟_項目裏配置的 .npmrc_ 或_你本地的 npm 配置的 registry_ 有關。

integrity

第四行integrity是對resolved下載下來的文件進行完整性校驗。如果出現 diff,說明同一個下載鏈接對應的文件被修改過。

dependencies

第五行dependencies是這個包自己的依賴。如這裏依賴的browserslist "^4.16.6",你想看下實際安裝的哪個版本,就可以把它拼成 Identifierbrowserslist@^4.16.6",以此爲關鍵字在 yarn.lock 中搜索,就能找到對應的 “塊” 了。

browserslist@4.16.6, browserslist@^4.0.0, browserslist@^4.11.1, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.6, browserslist@^4.3.6, browserslist@^4.6.2, browserslist@^4.6.4, browserslist@^4.7.2, browserslist@^4.9.1:
  version "4.16.6"
  resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
  integrity sha1-15ASd6WojlVO0wWxg+ybDAj2b6I=
  dependencies:
    caniuse-lite "^1.0.30001219"
    colorette "^1.2.2"
    electron-to-chromium "^1.3.723"
    escalade "^3.1.1"
    node-releases "^1.1.71"

上面這個例子第一行有多個 Identifiers,最終都指向第二行的version "4.16.6",可以檢查下4.16.6版本滿足上面所有 Identifiers 裏的版本區間:4.16.6^4.0.0...

yarn.lock 是如何生成的?

yarn.lock 是自動生成的,你不應該去手動的修改

依賴管理

比如我們的常規操作,都會自動更新 package.json 和 yarn.lock

更多可參考 https://classic.yarnpkg.com/en/docs/managing-dependencies

霸道的resolutions

假如你的項目依賴了foo,foo依賴了bar@^1.0.0。假設bar現在有兩個版本1.0.01.1.0。很不幸,bar在發佈1.1.0的時候沒有做好向後兼容。導致foobar@1.1.0不能搭配使用。如果你可以等:

那如果你等不了呢,你已知foobar@1.0.0可以正常工作。如果你能鎖住foobar的依賴就好了,但是這定義在foo的 packge.json 裏,你總不能去改 node_modules/foo/package.json 吧?這不合適。resolutions[1] 可以解決你的問題,只要在你自己項目的 package.json 裏定義:

"resolutions"{
  "foo/bar""1.0.0"
}

這裏的 key"foo/bar"表示foo直接依賴bar,把版本區間重寫成1.0.0。如果foo不是直接依賴的barfoo -> ... -> bar),我還需要把中間的鏈路都捋清楚嗎?不用那麼麻煩!

"resolutions"{
  "foo/**/bar""1.0.0"
}

如果你的項目裏有很多依賴直接 / 間接的依賴了bar,每個定義的版本區間可能有差別,你知道某個版本可以讓他們都能正常工作,而不用安裝多個版本。也可以不用聲明前綴部分,只寫包名bar。這樣不管是哪裏依賴到了bar都會指向你聲明的哪個版本。

"resolutions"{
  "bar""1.0.0"
}

執行yarn install後,在 yarn.lock 裏搜索bar@

bar@^1.0.0 bar@1.1.0 bar@^2.0.0:
  version "1.0.0"
  ...

可以看到,resolutions可以違背版本區間的限制,比如上例中 Identifiers 裏的bar@1.1.0``bar@^2.0.0

如何避免出現問題?

yarn.lock 與 package.json 不 match

場景

只改動 package.json,忘記提交 yarn.lock

問題

執行yarn install後,yarn.lock 有變更

如何解決

可以看到出現問題再解決還是很棘手的,而且有一定賭的成分,所以我們最好預防。

如何預防

即使現在項目是好的,我們是不是也應該防患於未然!

把 lock file 刪掉,整個重裝

場景

當你更新了某個依賴後,發現項目跑不起來了,推測可能是依賴的問題。有沒有嘗試過把 yarn.lock + node_modules 都刪了重新安裝,幸運的話可能 “問題就解決了”(解決了,但是好像沒完全解決,反正項目跑起來了)

問題

把 yarn.lock 刪掉後,原本鎖住的版本都放開了,執行yarn install的時候會根據 package.json 裏定義的版本區間去找最新版。所以,可能會造成你預期外的依賴也被更新了,不幸的話可能會引入 bug。

解決思路

可以單獨搞一個依賴empty-lock-lock

在項目中安裝依賴yarn add empty-lock-lock@1.0.0 --dev,yarn.lock 裏會鎖定版本爲1.0.0。然後準備一個陷阱:

修改後提交,可以再執行yarn install驗證下,yarn.lock 沒有 diff,證明我們手動修改後的 package.json 和 yarn.lock 仍然是 match 的。等小白鼠上鉤,如果把 yarn.lock 整個刪掉了,再執行yarn install,安裝到empty-lock-lock的時候,會根據 package.json 裏定義的^1.0.0版本區間裏找最新的,這時候會找到1.0.1版本,下載後觸發postinstall就報錯啦!

THE END

==========

希望通過本文,可以瞄到 yarn.lock 神祕的面紗下的一角,當下次再看到 yarn.lock 產生 diff 時不會那麼迷茫和焦慮。如果各位大大在閱讀過程中發現了問題,請務必按頭改正!感恩 ❤️ 感謝團隊內的小夥伴們一起探討問題 && 提供小妙 (筍) 招。感恩 Plus ❤️❤️❤️

參考資料

擴展閱讀

參考資料

[1]

resolutions: https://classic.yarnpkg.com/en/docs/selective-version-resolutions/#toc-how-to-use-it

[2]

npm ci: https://docs.npmjs.com/cli/v7/commands/npm-ci

[3]

yarn install --frozen-lockfile: https://stackoverflow.com/questions/58482655/what-is-the-closest-to-npm-ci-in-yarn

[4]

--exit-code: https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---exit-code

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/25UnynJa6Ej8NjyGYpgUUg