前端工程師應該知道的yarn知識

TonySQ發表於2020-01-10

yarn 是在工作中離不開的工具,但在工作中,很多人基本只會使用 yarn install,而且會手動刪除 node-modules,或刪除 yarn.lock 檔案等不規範操作。本文將從一些基礎的知識點開始介紹,循序漸進的讓你對 Yarn 有一個更深入的瞭解,來保證規範的使用yarn,避免一些隱藏bug的產生。
本文主要介紹以下知識:

  1. 什麼是registry
  2. 依賴的版本含義及寫法
  3. 依賴型別及區別(devDependencesdevDependencespeerDependencesoptionalDependenciesbundledDependencies
  4. 快取介紹
  5. yarn.lock 檔案作用及介紹
  6. yarn install 安裝依賴的過程
  7. 依賴關係樹的模組扁平化
  8. 常用的 yarn 命令介紹

什麼是registry

registry是 模組倉庫提供了一個查詢服務,也就是我們常說的源。以yarn官方映象源為例,它的查詢服務網址是https://registry.yarnpkg.com

這個網址後面跟上模組名,就會得到一個 JSON 物件,裡面是該模組所有版本的資訊。比如,訪問 https://registry.npmjs.org/vue,就會看到 vue 模組所有版本的資訊。

registry 網址的模組名後面,還可以跟上版本號或者標籤,用來查詢某個具體版本的資訊。https://registry.yarnpkg.com/vue/2.6.10

上面返回的 JSON 物件裡面,有一個dist.tarball屬性,是該版本壓縮包的網址。dist.shasum 屬性相當於hash值,在lock和快取時會使用到,下文會提到。

dist: {
  "shasum": "a72b1a42a4d82a721ea438d1b6bf55e66195c637",
  "tarball":"https://registry.npmjs.org/vue/-/vue-2.6.10.tgz"
},
複製程式碼複製程式碼

我們在執行 yarn install 時,就是向 registry 查詢得到上面的壓縮包地址進行下載的。
工作中,我們可能有需要修改映象源的場景,比如修改成淘寶源或者自己公司的私有源。
檢視和設定源,可以通過 yarn config 命令來完成
檢視當前使用的映象源

yarn config get registry
複製程式碼複製程式碼

修改映象源(以修改成淘寶源為例)

yarn config set registry https://registry.npm.taobao.org/
複製程式碼複製程式碼

依賴版本

yarn的包遵守 semver,即語義化版本。 SemVer 是一套語義化版本控制的約定,定義的格式為

X.Y.Z(主版本號.次版本號.修訂號):
X.主版本號:進行不向下相容的修改時,遞增主版本號
Y.次版本號: 做了向下相容的新增功能或修改
Z.修訂號:做了向下相容的問題修復
複製程式碼複製程式碼

yarn 中依賴版本範圍的表示方法有以下幾種:

  1. 通過比較器
表示含義描述
<2.0.0任何小於 2.0.0 的版本
<=3.1.4任何小於或等於 3.1.4 的版本
>0.4.2任何大於 0.4.2 的版本
>=2.7.1任何大於或等於 2.7.1 的版本
=4.6.6任何等於 4.6.6 的版本
>=2.0.0 <3.1.4交集,大於或等於 2.0.0 並小於 3.1.4
<2.0.0 || >3.1.4並集 小於 2.0.0 或者大於 3.1.4

如果沒有指定運算子,預設為 =

  1. 通過連字元
表示含義描述
2.0.0 - 3.1.4>=2.0.0 <=3.1.4
0.4 - 2>=0.4.0 <=2.0.0

版本號中缺少的那些部分會用數字 0 填充。

  1. X範圍
    字元 X、x 或者 * 都可以作為萬用字元,用於填充部分或全部版本號。 被省略的那部分版本號預設為 x 範圍。
表示含義描述
*>=0.0.0 (任意版本)
2.x>=2.0.0 <3.0.0(匹配主要版本)
3.1.x> = 3.1.0 < 3.2.0(匹配主要和次要版本)
``(空字串)* 或 > = 0.0.0
22.x.x 或 > = 2.0.0 < 3.0.0
3.13.1.x 或 > = 3.1.0 < 3.2.0
  1. ~ 字元範圍
    同時使用字元 ~ 和次版本號,表明允許 修訂號 變更。同時使用字元 ~ 和主版本號,表明允許 次版本 號變更。
表示含義描述
~3.1.4>=3.1.4 <3.2.0
~3.13.1.x 或 > = 3.1.0 < 3.2.0
~33.x 或 > = 3.0.0 < 4.0.0
  1. ^ 字元範圍
    字元 ^ 表明不會修改版本號中的第一個非零數字,3.1.4 裡的 3 或者 0.4.2 裡的 4。版本號中缺少的部分將被 0 填充,且在匹配時這些位置允許改變。
表示含義描述
^3.1.4>=3.1.4 <4.0.0
^0.4.2>=0.4.2 <0.5.0
^0.0.2>=0.0.2 <0.0.3

使用 yarn add [package-name] 命令安裝依賴,預設使用的是 ^ 範圍。
需要注意的是,如果一個比較器包含有預釋出標籤的版本,它將只匹配有相同 major.minor.patch 的版本。 例如 >=3.1.4-beta.2,可以匹配 3.1.4-beta.3,但不會匹配 3.1.5-beta.3 版本。

依賴型別

dependences 程式碼執行時所需要的依賴,比如vue,vue-router。

devDependences 開發依賴,就是那些只在開發過程中需要,而執行時不需要的依賴,比如babel,webpack。

peerDependences 同伴依賴,它用來告知宿主環境需要什麼依賴以及依賴的版本範圍。
如果宿主環境沒有對應版本的依賴,在安裝依賴時會報出警告。
比如包 eslint-plugin-import 中有依賴:

 "peerDependencies": {
    "eslint": "2.x - 5.x"
  },
複製程式碼複製程式碼

在install時,如果宿主環境沒有 2.x-5.x 版本的 eslint,cli就會丟擲警告。但不會自動幫我們安裝,仍然需要手動安裝。

optionalDependencies 可選依賴,這種依賴即便安裝失敗,Yarn也會認為整個依賴安裝過程是成功的。
可選依賴適用於那些即便沒有成功安裝可選依賴,也有後備方案的情況。

bundledDependencies 打包依賴,在釋出包時,這個陣列裡的包都會被打包打包到最終的釋出包裡,需要注意 bundledDependencies 中的包必須是在devDependencies或dependencies宣告過的。

快取

yarn 會將安裝過的包快取下來,這樣再次安裝相同包的時候,就不需要再去下載,而是直接從快取檔案中直接copy進來。

可以通過命令 yarn cache dir 檢視yarn的全域性快取目錄。我的快取目錄在 /Library/Caches/Yarn/v1 下。

可以看出,yarn 會將不通版本解壓後的包存放在不同目錄下,目錄以

npm-[package name]-[version]-[shasum]` 
複製程式碼複製程式碼

來命名。shasum 即上文中 registry 獲取的 dist.shasum

我們可以通過命令檢視已經快取過的包。

yarn cache list    列出已快取的每個包

yarn cache list --pattern <pattern>  列出匹配指定模式的已快取的包
複製程式碼複製程式碼

例如執行 yarn cache list --pattern vue

yarn.lock

yarn.lock 中會準確的儲存每個依賴的具體版本資訊,以保證在不同機器安裝可以得到相同的結果。

下面以@babel/code-frame為例,看看yarn.lock 中會記錄哪些資訊。

  1. 第一行 "@babel/code-frame@7.0.0-beta.54" 包的name和語義化版本號,這些都來自package.json中的定義。
  2. version 欄位,記錄的是一個確切的版本。
  3. resolved 欄位記錄的是包的URL地址。其中hash值,即上文的 dist.shasum
  4. dependencies 欄位記錄的是當前包的依賴,即當前包在 package.jsondependencies 欄位中的所有依賴。

Yarn 在安裝期間,只會使用當前專案的 yarn.lock 檔案(即 頂級 yarn.lock 檔案),會忽略任何依賴裡面的 yarn.lock 檔案。在頂級 yarn.lock 中包含需要鎖定的整個依賴樹裡全部包版本的所有資訊。

yarn.lock檔案是在安裝期間,由 Yarn 自動生成的,並且由yarn來管理,不應該手動去更改,更不應該刪除yarn.lock檔案,且要提交到版本控制系統中,以免因為不同機器安裝的包版本不一致引發問題。

Yarn install過程

首次執行 yarn install 安裝,會按照 package.json 中的語義化版本,去向 registry 進行查詢,並獲取到符合版本規則的最新的依賴包進行下載,並構建構建依賴關係樹。 比如在 package.json 中指定 vue 的版本為 ^2.0.0,就會獲取符合 2.x.x 的最高版本的包。然後自動生成 yarn.lock 檔案,並生成快取。

之後再執行 yarn install,會對比 package.json 中依賴版本範圍和 yarn.lock 中版本號是否匹配。

  1. 版本號匹配,會根據 yarn.lock 中的 resolved 欄位去檢視快取, 如果有快取,直接copy,沒有快取則按照 resolved欄位的url去下載包。
  2. 版本號不匹配,根據 package.json 中的版本範圍去 registry 查詢,下載符合版本規則最新的包,並更新至 yarn.lock中。

模組扁平化

上面提到,在安裝依賴時,會解析依賴構建出依賴關係樹。 比如我專案的首層依賴(即當前專案的dependence和devDependences中的依賴,不包括依賴的依賴)中有A,B,C三個包,A 和 B包同時依賴了相同版本範圍的D包。那麼這部分的依賴關係樹是這樣的:

├── A    				
│ └── D    
├── B    				
│ └── D  
├── C 
複製程式碼複製程式碼

如果按照這樣的依賴關係樹直接安裝的話,D模組會在A包和B包的 node_modules中都安裝,這樣會導致模組冗餘。

為了保證依賴關係樹中沒有大量重複模組,yarn在安裝時會做dedupe(去重)操作,它會遍歷所有節點,逐個將模組放在根節點下面,也就是當前專案的 node-modules 中。當發現有相同的模組時,會判斷當前模組指定的 semver 版本範圍是否交集,如果有,則只保留相容版本,如果沒有則在當前的包的 node-modules 下安裝。
所以上面的說的情況,最終安裝完成是下面這樣的,A,B,C,D包都會安裝在第一層 node-modules 下。

├── A    				
├── B    				
├── C 
├── D
複製程式碼複製程式碼

如果A包和B包依賴的是不相容的版本,假設A包依賴的是D@1版本的包,B包依賴的是D@2版本。則最終安裝的結果如下:

├── A    				
├── B    
│ └── D@2 
├── C 
├── D@1
複製程式碼複製程式碼

當程式碼中 requireimport 某個模組時,會從當前 packagenode-modules 裡中開始找,找不到就到當前package的上一層 node-modules 裡找,這樣一直找到全域性的node_modules。 所以上面的安裝的樹結構,可以保證每個 package 都能獲取到所需要版本的包。

常用的yarn命令

  1. yarn install 安裝依賴
yarn install / yarn  在本地 node_modules 目錄安裝 package.json 裡列出的所有依賴
yarn install --force 重新拉取所有包,即使之前已經安裝的(所以以後別在刪除node-modules了...)
yarn install --modules-folder <path> 為 node_modules 目錄指定另一位置,代替預設的 ./node_modules
yarn install --no-lockfile 不讀取或生成 yarn.lock 檔案
yarn install --production[=true|false] / --production / --prod 只安裝 dependence下的包,不安裝 devDependencies 的包

複製程式碼複製程式碼
  1. yarn add
yarn add package-name 會安裝 latest 最新版本。
yarn add <package...>  安裝包到dependencies中
yarn add <package...> [--dev/-D]  用 --dev 或 -D 安裝包到 devDependencies
yarn add <package...> [--peer/-P]  用 --peer 或者 -P 安裝包到 peerDependencies
yarn add <package...> [--optional/-O] 用 --optional 或者 -O 安裝包到 optionalDependencies 
yarn add <package...> [--exact/-E] 用 --exact 或者 -E 會安裝包的精確版本。預設是安裝包的主要版本里的最新版本。 比如說, yarn add foo@1.2.3 會接受 1.9.1 版,但是 yarn add foo@1.2.3 --exact 只會接受 1.2.3 版。
yarn add <package...> [--tilde/-T]  用 --tilde 或者 -T 來安裝包的次要版本里的最新版。 預設是安裝包的主要版本里的最新版本。 比如說,yarn add foo@1.2.3 --tilde 會接受 1.2.9,但不接受 1.3.0。
複製程式碼複製程式碼
  1. yarn config 管理配置檔案
yarn config get <key> 檢視配置key的值
yarn config list 檢視當前的配置
yarn config delete <key> 從配置中刪除配置key
yarn config set <key> <value> [-g|--global] 設定配置項 key 的值為 value
複製程式碼複製程式碼
  1. 其他常用命令
yarn list 查詢當前工作資料夾所有的依賴
yarn info <package> [<field>]  檢視包資訊,可以檢視特定
yarn remove <package...>  從依賴裡移除名包,同時更新你 package.json 和 yarn.lock 檔案。
yarn <script> [<args>] 執行使用者自定義的指令碼
複製程式碼複製程式碼
  1. 詳細日誌模式 執行yarn命令時,增加引數 --verbose,這對排查錯誤時很有幫助
yarn <command> --verbose複製程式碼


相關文章