前端工程師應該知道的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

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

上面返回的 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
2 2.x.x 或 > = 2.0.0 < 3.0.0
3.1 3.1.x 或 > = 3.1.0 < 3.2.0
  1. ~ 字元範圍
    同時使用字元 ~ 和次版本號,表明允許 修訂號 變更。同時使用字元 ~ 和主版本號,表明允許 次版本 號變更。
表示 含義描述
~3.1.4 >=3.1.4 <3.2.0
~3.1 3.1.x 或 > = 3.1.0 < 3.2.0
~3 3.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就會丟擲警告。但不會自動幫我們安裝,仍然需要手動安裝。

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

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

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

快取

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

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

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

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

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

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

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

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

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

例如執行 yarn cache list --pattern vue

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

yarn.lock

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

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

下面以@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
複製程式碼

可以列印出執行的詳細資訊(建立目錄、複製檔案或 HTTP 請求等)

歡迎關注我的公眾號「前端小苑」,我會定期在上面更新原創文章。

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

相關文章