一文帶你了解前端包管理工具npm、yarn和pnpm
為什么需要包管理工具?
每種主流編程語(yǔ)言都有包管理工具,比如 java 的 Maven、Gradle,Python 的 pip,nodejs 的 npm、yarn、pnpm 等。
包管理工具的主要作用是管理第三方依賴(lài),也可以看成一個(gè)"輪子"工廠(chǎng),每個(gè)人都可以上傳自己造的"輪子"和下載使用別人的"輪子",包管理工具顧名思義就是統(tǒng)一管理這些輪子的軟件或者工具,它以多種方式自動(dòng)處理項(xiàng)目依賴(lài)關(guān)系、提供了命令行工具(CLI)、支持跟蹤依賴(lài)項(xiàng)和版本等功能,
除此之外還可以安裝、卸載、更新和升級(jí)包,配置項(xiàng)目設(shè)置,運(yùn)行腳本等等。
有了包管理工具,我們可以很簡(jiǎn)單地構(gòu)建一個(gè)項(xiàng)目或者引入和管理一個(gè)庫(kù),留給我們的則是愉快地編碼。
npm 不只是包管理工具,它是世界上最大的軟件注冊(cè)表(registry),每星期大約有 30億次 的下載量,包含超過(guò) 600000個(gè)包,開(kāi)發(fā)者使用 npm 互相分享和借鑒。
版本管理規(guī)范
版本管理規(guī)范 - 語(yǔ)義化版本控制規(guī)范 SemVer

在使用 npm 和 yarn 安裝完依賴(lài)時(shí),package.json 會(huì)有類(lèi)似以下的版本號(hào):
"vue": "^2.6.11", "vue-router": "~3.1.3"
2.6.11、3.1.3 這個(gè)版本號(hào)就是遵循了 SemVer 語(yǔ)義化版本控制的規(guī)范。
SemVer規(guī)范規(guī)定,版本的格式為:主版本號(hào).次版本號(hào).修訂號(hào)-預(yù)發(fā)版本(可選),版本號(hào)遞增規(guī)則如下:
- 主版本號(hào):當(dāng)你做了不兼容的 API 修改
- 次版本號(hào):當(dāng)你做了向下兼容的功能性新增
- 修訂號(hào):當(dāng)你做了向下兼容的問(wèn)題修正。
- 預(yù)發(fā)布版本:
- alpha(Alpha 版本,通常用于進(jìn)行中的工作和實(shí)驗(yàn))
- beta(Beta 版本,通常是下一個(gè)計(jì)劃發(fā)布的功能完整的版本,但可能包含已知錯(cuò)誤)
- rc: 候選版本,通常是可能最終(穩(wěn)定)的版本,除非出現(xiàn)重大錯(cuò)誤。
在 nodejs 版本管理中,還允許使用 ~ ^ * 字符來(lái)管理版本的范圍:
- ^: 不允許修改最左邊非0版本 (^2.6.11: 版本 >= 2.6.11 且 < 3.0.0)
- ~: 如果指定了次要版本,則只允許補(bǔ)丁版本更新,如果沒(méi)有,則允許次要版本更新 (~3.1.3: 版本 >= 3.1.3 且 < 3.2.0)
- *: 任何非預(yù)發(fā)版本 (版本 >=0.0.0)
前端主流包管理工具
主流的前端包管理工具有 npm、yarn、pnpm、以及國(guó)內(nèi)的鏡像 cnpm、tyarn 等,這是包管理器都是基于 nodejs。
npm 是 2010 年發(fā)布的 nodejs 依賴(lài)管理工具,在此之前,前端的依賴(lài)管理都是手動(dòng)下載和管理的。
yarn 是 Facebook 于 2016 年 發(fā)布的替代 npm 的包管理工具,還可以作為項(xiàng)目管理工具,定位是快速、可靠、安全的依賴(lài)管理工具。
pnpm 是 2017 年發(fā)布的一款替代 npm 包管理工具,具有速度快、節(jié)省磁盤(pán)空間的特點(diǎn)。

2010:npm 發(fā)布,支持 Node.js。
2016:yarn 發(fā)布,生成 yarn.lock 文件用于確定 repos 的精確版本,并且比 npm 性能更好。
2017:npm 5 發(fā)布,提供類(lèi)似 yarn.lock 的 package-lock.json 文件。
2017:pnpm 發(fā)布,pnpm 具有 yarn 相對(duì)于 npm 的所有附加功能,并解決了 yarn 沒(méi)有解決的磁盤(pán)空間問(wèn)題。
2018:npm 6 發(fā)布,在 npm 在安裝依賴(lài)項(xiàng)之前檢查安全漏洞,提高了安全性。
2020:yarn 2 和 npm 7 發(fā)布,這兩個(gè)軟件包都具有出色的新功能。
2021:yarn 3 發(fā)布并進(jìn)行了各種改進(jìn)。
yarn vs npm vs pnpm
包管理工具安裝和版本切換
因?yàn)?node 預(yù)裝了 npm ,所以安裝 node 后,不需要手動(dòng)安裝 npm。
相反地,yarn 需要手動(dòng)安裝。建議全局安裝 yarn:
npm install yarn -g
然后,我們?cè)陧?xiàng)目的根目錄設(shè)置需要的 yarn 版本:
# yarn set version latest # 最新版 # yarn set version canary # 最新的經(jīng)典版 # yarn set version classic # 最新的經(jīng)典版 # yarn set version 3.x yarn set version <version>
使用 Yarn,在每個(gè)項(xiàng)目我們可以使用不同的版本,而在 npm 中,要安裝 nvm 才能完成版本切換。
同樣的,pnpm 也需要全局安裝,才能使用
npm install pnpm -g
pnpm 其他使用命令 和 npm 使用方法一致。
安裝項(xiàng)目依賴(lài)
在執(zhí)行 npm install 安裝項(xiàng)目依賴(lài)時(shí),依賴(lài)項(xiàng)是順序安裝,并且終端會(huì)輸出很多的警告日志,導(dǎo)致覆蓋報(bào)錯(cuò)的日志,從而難以排查問(wèn)題。
使用 yarn 安裝依賴(lài)時(shí),運(yùn)行 yarn 命令即可,yarn 是并行安裝依賴(lài)項(xiàng),這是它比 npm 快的原因之一,yarn 1 中的日志比較簡(jiǎn)介干凈,是以樹(shù)形的形式顯示,但是在 yarn 2 和 yarn 3 中日志發(fā)生了變化,并不像以前直觀(guān)。
并且,yarn 還支持離線(xiàn)安裝,只要以前裝過(guò)的包,可以在沒(méi)有網(wǎng)絡(luò)鏈接的情況下進(jìn)行。yarn 具有重試機(jī)制,單個(gè)包安裝失敗不會(huì)導(dǎo)致整個(gè)安裝失敗。
在 yarn 安裝不同版本的依賴(lài)時(shí),會(huì)將多個(gè)版本歸結(jié)為單個(gè)版本,避免創(chuàng)建多個(gè)副本。
npm 、yarn 和 pnpm 常用命令
- npm init| yarn init| pnpm init: 初始化命令
- npm run| yarn run/yarn | pnpm: 運(yùn)行腳本
- npm publish| yarn publish: 發(fā)布包
- npm cache clean| yarn cache clean:清除緩存
- npm install| yarn | pnpm install/i: 安裝所有依賴(lài)
- npm install [package]| yarn add [package]| pnpm add [package]: 安裝某個(gè)依賴(lài)項(xiàng)
- npm install --save-dev/-D [package]| yarn add --dev/-D [package]| | pnpm add --dev/-D [package]: 安裝開(kāi)發(fā)依賴(lài)
- npm uninstall [package]| yarn remove [package]| pnpm remove/rm [package]: 卸載依賴(lài)
- npm update| yarn upgrade| pnpm update/up: 更新全部依賴(lài)
- npm update [package]| yarn upgrade [package]| pnpm update/up [package]|: 更新某個(gè)依賴(lài)
安全性
npm 最不好的缺點(diǎn)之一就是安全性,曾經(jīng)的版本發(fā)生過(guò)幾個(gè)嚴(yán)重的安全漏洞, npm 6 開(kāi)始則是在安裝之前會(huì)檢查安全漏洞,并且支持使用 npm audit 手動(dòng)檢查安裝包的安全性,如果發(fā)現(xiàn)安全問(wèn)題,可以運(yùn)行 npm audit fix 修復(fù)漏洞。
因?yàn)?npm/yarn 是扁平化依賴(lài)結(jié)構(gòu),有個(gè)非常嚴(yán)重的問(wèn)題就是可以非法訪(fǎng)問(wèn)未聲明的包,而 pnpm 是將依賴(lài)通過(guò) link 的形式避免了非法訪(fǎng)問(wèn)依賴(lài)的問(wèn)題,如果沒(méi)在 package.json 聲明的話(huà),是無(wú)法訪(fǎng)問(wèn)的。
yarn 和 pnpm 同樣也支持 yarn/pnpm audit 手動(dòng)檢查安裝包的安全性。
yarn 和 npm 都是使用 hash加密算法 確保包的完整性。
lock 文件
在 package.json 跟蹤的依賴(lài)項(xiàng)和版本總是不準(zhǔn)確的,因?yàn)?~ ^ * 等前綴表示依賴(lài)更新時(shí)對(duì)應(yīng)的版本范圍。
范圍版本可以在更新依賴(lài)時(shí)自動(dòng)升級(jí)依賴(lài)到兼容性的次要版本或者補(bǔ)丁版本,讓軟件包支持最新的功能或者修復(fù)最近的錯(cuò)誤。
所以,為了避免不同設(shè)備安裝依賴(lài)時(shí)的版本不匹配的問(wèn)題,在 lock 文件中定義了精確的安裝版本。在每次新裝(更新)依賴(lài)時(shí),npm 和 yarn 會(huì)分別
創(chuàng)建(更新) package-lock.json 和 yarn.lock 文件。這樣就能保證其他設(shè)備安裝完全相同的包。
在 pnpm 中,則是使用 pnpm-lock.yaml 文件定義依賴(lài)包的精確版本。
性能對(duì)比
npm/pnpm/yarn/yarnPnp install 性能對(duì)比
測(cè)試 package.json 位置
| action | cache | lockfile | node_modules | npm | pnpm | Yarn | Yarn PnP |
|---|---|---|---|---|---|---|---|
| install | 51s | 14.4s | 39.1s | 29.1s | |||
| install | ? | ? | ? | 5.4s | 1.3s | 707ms | n/a |
| install | ? | ? | 10.9s | 3.9s | 11s | 1.8s | |
| install | ? | 33.4s | 6.5s | 26.5s | 17.2s | ||
| install | ? | 28.3s | 11.8s | 23.3s | 14.2s | ||
| install | ? | ? | 4.6s | 1.7s | 22.1s | n/a | |
| install | ? | ? | 6.5s | 1.3s | 713ms | n/a | |
| install | ? | 6.1s | 5.4s | 41.1s | n/a | ||
| update | n/a | n/a | n/a | 5.1s | 10.7s | 35.4s | 28.3s |

根據(jù)上面的測(cè)試結(jié)果我們可以看出,首次執(zhí)行 npm install 安裝依賴(lài)時(shí) pnpm 比 npm 和 yarn 大約快了 3 倍左右,在有緩存和已安裝過(guò)依賴(lài)的情況,比 npm 也快了不少,yarn 則是更快,其他場(chǎng)景 pnpm 也是占了很大優(yōu)勢(shì)。
pnpm 的優(yōu)勢(shì)
速度很快、節(jié)約空間
pnpm 的所有依賴(lài)包統(tǒng)一存儲(chǔ)在 store,不會(huì)出現(xiàn)像 npm 或 yarn 每個(gè)項(xiàng)目會(huì)下載獨(dú)立的依賴(lài),yarn 是從緩存下載文件,而 pnpm 是從 store 中鏈接依賴(lài),pnpm 更節(jié)約空間,當(dāng)安裝某個(gè)依賴(lài)時(shí),新項(xiàng)目會(huì)使用硬鏈接到 store 的這個(gè)依賴(lài),多個(gè)項(xiàng)目不會(huì)出現(xiàn)多次安裝依賴(lài)的情況,磁盤(pán)只有一次寫(xiě)入。
對(duì)于依賴(lài)的不同版本,在 pnpm 中,則只會(huì)保存增量文件。比如:某個(gè)包有100個(gè)文件,如果更新版本只會(huì)修改其中的一個(gè)文件,不會(huì)因?yàn)樾掳姹镜拇嬖诙4嫠械囊蕾?lài)文件。
因?yàn)?pnpm 的依賴(lài)包存儲(chǔ)在 store 同樣也支持離線(xiàn)安裝的功能。
沒(méi)有扁平化 node_modules 結(jié)構(gòu)
pnpm 不會(huì)扁平化依賴(lài)數(shù),它的 node_modules 布局使用符號(hào)鏈接來(lái)創(chuàng)建依賴(lài)關(guān)系的嵌套結(jié)構(gòu)。
pnpm 所有包都有自己的依賴(lài)項(xiàng)組合在一起,內(nèi)部每個(gè)包使用符號(hào)鏈接將它們組合在一起。
一個(gè) vue3 項(xiàng)目 的 pnpm node_modules 結(jié)構(gòu)

vite 包的 pnpm 結(jié)構(gòu)

參考鏈接
總結(jié)
到此這篇關(guān)于前端包管理工具npm、yarn和pnpm的文章就介紹到這了,更多相關(guān)前端包管理工具npm yarn pnpm內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
nodejs(officegen)+vue(axios)在客戶(hù)端導(dǎo)出word文檔的方法
這篇文章主要介紹了nodejs(officegen)+vue(axios)在客戶(hù)端導(dǎo)出word文檔的方法,需要的朋友可以參考下2018-07-07
node連接MongoDB數(shù)據(jù)庫(kù)錯(cuò)誤:MongoServerSelectionError:?connect?ECON
使用node連接MongoDB數(shù)據(jù)庫(kù)時(shí)發(fā)生報(bào)錯(cuò),MongoServerSelectionError:?connect?ECONNREFUSED?::1:27017,本文給大家分享原因分析及解決方案,感興趣的朋友跟隨小編一起看看吧2023-04-04
詳解基于node的前端項(xiàng)目編譯時(shí)內(nèi)存溢出問(wèn)題
本篇文章主要介紹了基于node的前端項(xiàng)目編譯時(shí)內(nèi)存溢出問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08
nodejs服務(wù)內(nèi)存泄露排查過(guò)程和優(yōu)化方法
在開(kāi)發(fā)和部署Node.js應(yīng)用程序時(shí),內(nèi)存泄露是一個(gè)常見(jiàn)的挑戰(zhàn),本文將探討如何對(duì)于一個(gè)陌生項(xiàng)目進(jìn)行內(nèi)存排查和優(yōu)化的方法,文章通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-11-11
node.js使用 http-proxy 創(chuàng)建代理服務(wù)器操作示例
這篇文章主要介紹了node.js使用 http-proxy 創(chuàng)建代理服務(wù)器,結(jié)合實(shí)例形式分析了node.js使用 http-proxy 創(chuàng)建代理服務(wù)器原理、具體步驟與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-02-02
nodejs異步編程基礎(chǔ)之回調(diào)函數(shù)用法分析
這篇文章主要介紹了nodejs異步編程基礎(chǔ)之回調(diào)函數(shù)用法,結(jié)合具體實(shí)例形式分析了阻塞與非阻塞形式下回調(diào)函數(shù)具體功能、使用技巧,需要的朋友可以參考下2018-12-12

