日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
新一代包管理工具Pnpm

背景

npm 發(fā)展

npm2

在 npm2 發(fā)展階段,安裝依賴是相對(duì)比較直接的,它會(huì)直接按照配置文件 package.json 中的依賴項(xiàng)去下載相關(guān)依賴包,而依賴包的組織形式則是按照樹形結(jié)構(gòu)去排列的。由于不同的包的依賴關(guān)系在版本上差異較大,依賴關(guān)系相對(duì)復(fù)雜,所以 npm2 直接按照配置去下載并組織依賴的方式,是簡(jiǎn)單明晰的做法,保證了各個(gè)依賴的獨(dú)立性,在依賴變更時(shí),相互并不影響,其關(guān)系可以通過(guò)下圖來(lái)描述:

從上圖中,我們可以看到

  • A、B、C 包相互獨(dú)立
  • A、B、C 包可能會(huì)依賴相同的包,比如 D@1.0
  • A、B、C 包可能會(huì)存在較深的依賴層級(jí),比如 C package

其中 2 和 3 這兩點(diǎn)的負(fù)面影響會(huì)隨著項(xiàng)目復(fù)雜度而上升,可能會(huì)導(dǎo)致的幾個(gè)問(wèn)題:

  • 較大的冗余。多次下載的相同的依賴包 D@1.0,無(wú)法實(shí)現(xiàn)共享。
  • 較深層級(jí)的依賴樹。

Too many dependencies break the Windows file system[2]

Maximum Path Length Limitation[3]

Why does the 260 character path length limit exist in Windows?[4]

node_modules 依賴包路徑過(guò)長(zhǎng),超出操作系統(tǒng)最長(zhǎng)路徑限制( windows:260 字符,macos:1024 字符),參見:

太深的層級(jí)導(dǎo)致文件查找復(fù)雜度上升,嚴(yán)重影響性能,增加耗時(shí)。

Note: 通過(guò) npm ls --depth=n 查看項(xiàng)目相關(guān)依賴層級(jí)深度。

npm3

為解決 npm2 中存在的冗余和依賴樹問(wèn)題,npm3 對(duì)依賴項(xiàng)進(jìn)行了依賴扁平化討論和處理[5]。

扁平化具體來(lái)講就是依賴不在按照樹型進(jìn)行安裝,而是安裝將依賴安裝在同級(jí)目錄下,npm install安裝依賴時(shí),會(huì)按照配置文件 package.json 里的依賴順序進(jìn)行解析,遇到新包就把它放在第一層級(jí)的目錄(如 D@1.0、E@1.0、F@1.0),后面如果遇到第一級(jí)目錄已有的包,會(huì)先進(jìn)行依賴版本判斷,如果版本一樣則忽略,否則會(huì)按照 npm2 的方式依次掛在依賴包目錄下,這樣處理的原理遵循了`Nodejs`的依賴解析規(guī)則[6]:當(dāng)前目錄下沒(méi)有找到node_modules,它將遞歸解析父目錄下的node_modules。

使用 npm3 安裝依賴后如下圖:

這種扁平化處理方式一定程度上緩解了冗余和依賴樹問(wèn)題,同時(shí) npm3 還支持動(dòng)態(tài)安裝更新包,如果依賴有更新,可以通過(guò) npm dedupe 命令對(duì)依賴樹進(jìn)行優(yōu)化。

但是 npm3 也存在部分問(wèn)題,比如:

phantom_deps(幻影依賴)[7]。npm3不會(huì)以確定的方式安裝依賴項(xiàng)。舉例來(lái)說(shuō):我們?cè)?NodeJS 中 require() 的函數(shù),不需要考慮配置文件 package.json 中是否有該依賴項(xiàng)。這可能會(huì)導(dǎo)致依賴版本不兼容,并且開發(fā)者不容易發(fā)現(xiàn);另外,由于`Nodejs`的依賴解析規(guī)則[8],這還會(huì)導(dǎo)致幻影 node_modules ,即依賴向上查找,可能會(huì)越過(guò)代碼目錄自身的 node_modules 。如下:

- my-monorepo/
- package.json
- node_modules/
- semver/
- ...
- my-monorepo/my-library/
- package.json
- lib/
- index.js
- node_modules/
- brace-expansion
- minimatch
- ...

my-monorepo/my-library/lib/index.js 可能使用的是my-monorepo/node_modules 中的依賴,而非自身目錄 my-monorepo/my-library/node_modules。

npm doppelgangers(npm 分身)[9]。簡(jiǎn)單來(lái)講,npm 分身是指同一個(gè)依賴的不同版本會(huì)出現(xiàn)在 node_modules 中,比如項(xiàng)目中同時(shí)依賴了 A@1.0.0 和 A@2.0.0,無(wú)論是扁平化處理A@1.0.0 或 A@2.0.0,另一個(gè)依賴還是會(huì)被重復(fù),如果這樣的分身較多,就會(huì)導(dǎo)致一些潛在問(wèn)題,比如擴(kuò)展包大小變大、相關(guān)類型校驗(yàn)交叉等。

npm5

npm5 通過(guò)添加 lock 文件來(lái)記錄依賴樹信息,進(jìn)行依賴鎖定,從而唯一確定 node_modules 的結(jié)構(gòu),這樣處理可以保證團(tuán)隊(duì)成員使用同一份node_modules依賴結(jié)構(gòu)。但是,我們前文提到的平鋪式的算法的復(fù)雜性、幻影依賴和分身問(wèn)題仍然沒(méi)有解決。

pnpm 簡(jiǎn)介

前文我們大致梳理了 npm 的發(fā)展和遺留問(wèn)題。而 pnpm 比較巧妙地解決了它們,并且極大地提升了依賴包管理的效率。

pnpm 指 performant npm(高性能的 npm),如 pnpm 官網(wǎng)[10]所言,它是快速的,節(jié)省磁盤空間的包管理工具,同時(shí),它也較好地支持了 workspace 和 monorepos。

pnpm 效果

與 npm、yarn、yarn pnp 工具鏈效果對(duì)比,來(lái)自 pnpm benchmarks[11]

action

cache

lockfile

node_modules

npm

pnpm

Yarn

Yarn PnP

install

1m 9.5s

15.3s

16.6s

23.6s

install

2.4s

1.3s

2.3s

n/a

install

14.8s

4s

6.8s

1.5s

install

21.8s

8.9s

11.2s

6.2s

install

35.4s

13.4s

12s

17.9s

install

3.1s

1.9s

7s

n/a

install

2.4s

1.3s

7.6s

n/a

install

3s

6.1s

11.8s

n/a

update

n/a

n/a

n/a

2.3s

11.8s

15.5s

28.3s

從上表數(shù)據(jù)我們可以看出,pnpm 的各項(xiàng)性能均比其它包管理工具有優(yōu)勢(shì),那你可能會(huì)想,為什么 pnpm 有如此優(yōu)越的表現(xiàn),接下來(lái)我們聊聊 pnpm 的主要原理

pnpm 的原理

pnpm 主要有兩個(gè)不同與其包管理工具的特性:

基于硬鏈接的 node_modules

pnpm 創(chuàng)建從全局存儲(chǔ)到項(xiàng)目中 node_modules 文件夾的硬鏈接[12],而硬鏈接指向磁盤上原始文件所在的同一位置,具體來(lái)說(shuō)就是 node_modules 中每個(gè)包的每個(gè)文件都是來(lái)自內(nèi)容可尋址存儲(chǔ)[13]的硬鏈接,簡(jiǎn)言之,就是特定版本和名稱的包全局只有一份。舉例來(lái)看:

node_modules
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> /bar
│ ├── index.js
│ └── package.json
└── foo@1.0.0
└── node_modules
└── foo -> /foo
├── index.js
└── package.json

node_modules 下面的唯一文件夾叫做 .pnpm, .pnpm 下面是一個(gè) 文件夾,而在其下面 的文件夾是一個(gè)基于內(nèi)容可尋址存儲(chǔ)的硬鏈接。同時(shí),我們也可以通過(guò) pnpm root 命令來(lái)打印當(dāng)前項(xiàng)目中存放模塊(modules)的有效目錄。

基于依賴解析的軟鏈接 symlinks

觀察以下依賴包結(jié)構(gòu):

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> /bar
└── foo@1.0.0
└── node_modules
├── foo -> /foo
└── bar -> ../../bar@1.0.0/node_modules/bar

我們可以看到在 foo@1.0.0/node_modules/bar 內(nèi)引用了 bar 的軟鏈接 ../../bar@1.0.0/node_modules/bar,而在項(xiàng)目里引用 foo 的軟鏈接 ./.pnpm/foo@1.0.0/node_modules/foo,如果項(xiàng)目?jī)?nèi)新增一個(gè)依賴包 qar@2.0.0,則其引用結(jié)構(gòu)如下:

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ ├── bar -> /bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
├── foo@1.0.0
│ └── node_modules
│ ├── foo -> /foo
│ ├── bar -> ../../bar@1.0.0/node_modules/bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
└── qar@2.0.0
└── node_modules
└── qar -> /qar

根據(jù)前文我們介紹到的`Nodejs`的依賴解析規(guī)則[14],foo@1.0.0/node_modules/foo/index.js 中所需的依賴包 bar,實(shí)際上使用的是bar@1.0.0/node_modules/bar中的內(nèi)容,因此,只有真正在依賴項(xiàng)中的包才能被訪問(wèn)到。而對(duì)于不同的 peer dependencies 的依賴解析原理,可以參考這里 How peers are resolved[15]

通過(guò)基于硬鏈接的node_modules和基于依賴解析的軟鏈接原理,我們了解到,當(dāng)我們?cè)谙嗤僮飨到y(tǒng)下第二次安裝同一個(gè)依賴包時(shí),我們需要做的僅僅是創(chuàng)建一個(gè)該依賴包對(duì)應(yīng)的硬鏈接,對(duì)于同一個(gè)依賴包的不同版本,也只有不同的部分會(huì)被重新保存起來(lái),而具體有沒(méi)有 pnpm 是在哪里判斷的呢?全局的 pnpm 索引文件在 ~/.pnpm-store/v3/files。基于此,使用硬鏈接讓依賴包的安裝速度非??欤瑫r(shí)也去除了冗余,節(jié)省較大磁盤空間。

symlinks 符號(hào)連接[16]

pnpm 使用

pnpm 的具體使用這里我們不展開介紹了,可以查看官網(wǎng)使用方法[17]和CLI 命令[18]即可。這里只提幾個(gè)有意思的點(diǎn)

CI 集成

在 GitHub Actions 上,你可以像這樣使用 pnpm 安裝和緩存依賴項(xiàng),配置文件目錄: .github/workflows/NAME.yml。

name: pnpm Example Workflow
on:
push:
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [15]
steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.0.1
with:
version: 6.20.3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- name: Install dependencies
run: pnpm install

pnpm 除了在開發(fā)體驗(yàn)方面的優(yōu)越表現(xiàn),在項(xiàng)目集成方面也毫不遜色,對(duì)于較大型項(xiàng)目從 npm 或 yarn到pnpm遷移過(guò)程后,也得到了極大的優(yōu)化,結(jié)果如下:

Without cache

With cache

yarn 2 (without dedupe)

6min 31s

1min 11s

yarn 3 (without dedupe)

4min 50s

57s

yarn 3

4min 1s

50s

yarn 3 (optimized)

1min 10

45s

pnpm

58s

24s

通過(guò)以上數(shù)據(jù),我們可以 pnpm 在 CI 應(yīng)用中的良好表現(xiàn)。

具體可以參考這篇最佳實(shí)踐 A story of how we migrated to pnpm[19]

pnpm 前置

項(xiàng)目中使用 pnpm 時(shí),如果你不希望項(xiàng)目?jī)?nèi)其他人使用 npm i 或 yarn這類包管理器,可以在 package.json 配置文件中添加預(yù)安裝 preinstall 配置項(xiàng),從而規(guī)范使用統(tǒng)一的包管理器。

{
"scripts": {
"preinstall": "npx only-allow pnpm"
}
}

管理 NodeJS 版本

在以前,如果你同時(shí)支撐了多個(gè)項(xiàng)目,而且需要在其中切換,你可能需要切換不同的 NodeJS 版本,也許你會(huì)用到像 nvm 或 Volta[20] 這樣的 NodeJS 版本管理器,而 pnpm 從 v6.12.0 版本后支持了 pnpm env[21] 命令,你可以使用它來(lái)安裝并指定使用哪個(gè)版本的 NodeJS ,是不是方便了很多。

monorepo 支持

因?yàn)閜npm 對(duì) monorepos 的大力支持,像 Vue、Vite 這些開源項(xiàng)目也轉(zhuǎn)而使用了它。使用pnpm run 結(jié)合 --filter 、 --recursive 和 --parallel 選項(xiàng),可以指定特定包,并高速執(zhí)行相關(guān)命令。這樣做的好處是之前要另外安裝 lerna 這種 monorepo 管理工具的場(chǎng)景,現(xiàn)在 pnpm 可以包攬了。詳細(xì)文章可以參考這里 pnpm vs Lerna: filtering in a multi-package repository[22]。

總結(jié)

本文從 pnpm 的出現(xiàn)背景開始,簡(jiǎn)要介紹了 npm 的發(fā)展過(guò)程及存在的問(wèn)題,繼而對(duì) pnpm 及其效果進(jìn)行了簡(jiǎn)介,重點(diǎn)講述了 pnpm 的實(shí)現(xiàn)原理,并從應(yīng)用側(cè)選擇了四個(gè)點(diǎn)展開。

pnpm 作為新一代包管理器,自身有不少優(yōu)越的表現(xiàn),它通過(guò)硬鏈接和軟鏈接的方式,解決了 npm幻影依賴和分身問(wèn)題,并且較好地解決了依賴包復(fù)用問(wèn)題,從而實(shí)現(xiàn)了依賴包高效快速的安裝。需要特別注意的是 pnpm 嚴(yán)格遵循了 Nodejs 依賴解析規(guī)則,規(guī)避了之前任意依賴包的訪問(wèn)修改問(wèn)題。

當(dāng)然,pnpm 使用過(guò)程中也存在一些問(wèn)題,包括 Vue 官方在遷移過(guò)程中,也處理過(guò)部分問(wèn)題。另外,一些包也存在兼容性問(wèn)題,由于包自己實(shí)現(xiàn)了模塊解析,并沒(méi)有遵循相關(guān)規(guī)范。但 pnpm 也提供了相關(guān)解決方法。具體參考 pnpm FAQ[23]。

參考資料:

[1]歷史: https://github.com/npm/cli/blob/latest/changelogs/CHANGELOG-1.md

[2]Too many dependencies break the Windows file system: https://github.com/npm/npm/issues/3697

[3]Maximum Path Length Limitation: https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd

[4]Why does the 260 character path length limit exist in Windows?: https://stackoverflow.com/questions/1880321/why-does-the-260-character-path-length-limit-exist-in-windows

[5]依賴扁平化討論和處理: https://github.com/npm/cli/blob/latest/changelogs/CHANGELOG-3.md

[6]Nodejs的依賴解析規(guī)則: https://nodejs.org/api/modules.html#all-together

[7]phantom_deps(幻影依賴): https://rushjs.io/pages/advanced/phantom_deps/

[8]npm doppelgangers(npm 分身): https://rushjs.io/pages/advanced/npm_doppelgangers/

[9]pnpm 官網(wǎng): https://pnpm.io/

[10]pnpm benchmarks: https://pnpm.io/zh/benchmarks

[11]硬鏈接: https://zh.wikipedia.org/wiki/%E7%A1%AC%E9%93%BE%E6%8E%A5

[12]內(nèi)容可尋址存儲(chǔ): https://en.wikipedia.org/wiki/Content-addressable_storage

[13]How peers are resolved: https://pnpm.io/zh/how-peers-are-resolved

[14]symlinks 符號(hào)連接: https://zh.wikipedia.org/wiki/%E7%AC%A6%E5%8F%B7%E9%93%BE%E6%8E%A5

[15]使用方法: https://pnpm.io/zh/pnpm-cli

[16]CLI 命令: https://pnpm.io/zh/cli/add

[17]A story of how we migrated to pnpm: https://divriots.com/blog/switching-to-pnpm

[18]Volta: https://volta.sh/

[19]pnpm env: https://pnpm.io/zh/cli/env

[20]pnpm vs Lerna: filtering in a multi-package repository: https://medium.com/pnpm/pnpm-vs-lerna-filtering-in-a-multi-package-repository-1f68bc644d6a

[23]pnpm FAQ: https://pnpm.io/faq#pnpm-does-not-work-with-your-project-here


當(dāng)前名稱:新一代包管理工具Pnpm
文章出自:http://www.dlmjj.cn/article/cdichhj.html