使用pnpm包管理器替代npm及yarn的命令示例
前言
今天給大家介紹一種新的包管理器:pnpm,pnpm 由 zkochan 開發(fā),最初也是在用 npm 或者 yarn 遇到了一些不爽的地方,于是自己做了一個開源的包管理器,也為優(yōu)化包管理提供了一種不同的新思路,接下來我們就看一下為何要使用 pnpm,以及他能做什么
值得一提的是,zkochan 也是一名烏克蘭的開發(fā)者,他也在主頁呼吁大家援助一下烏克蘭,我也希望當(dāng)前的國際局勢能更快的穩(wěn)定下來,不要損失這么優(yōu)秀的開發(fā)者
為什么會有 pnpm
一句話概括就是:節(jié)約磁盤空間并提升安裝速度
設(shè)想一下,假如公司的每個項目都用了 vue 全家桶,那么每個項目都需要安裝 vue、vue-router、vuex、axios 等幾乎相同的庫,如果有 100 個項目,那就要重復(fù)安裝 100 遍??!,要知道,現(xiàn)如今,硬盤雖然便宜,但也沒那么多插槽啊,更別說筆記本電腦這寸土寸金的資源空間。
因此,pnpm 的核心就是將所有的包都存放在一個資源倉庫中,而每個項目的 node_modules 通過軟鏈接的形式將包鏈接到資源倉庫中,這樣不僅節(jié)省了空間,同時也加快了安裝速度
不止于此
pnpm 的另一個優(yōu)點,在保留了非扁平化的 node_modules 文件夾,同時節(jié)省了空間
什么是扁平化的 node_modules
我們簡單回顧一下 npm 的發(fā)展歷史
1.最初,npm 只是簡單的通過依賴去遞歸的安裝包,所有的依賴放在相應(yīng)的包文件夾下面,假如 A 依賴了 foo,B 也依賴了 foo,那么就會有兩份 foo 安裝在 node_modules
node_modules ├── A │ └── node_modules │ └── foo └── B └── node_modules └── foo
2.經(jīng)過一次優(yōu)化, npm 為了節(jié)省空間,采用了扁平化的 node_modules,這樣,假如 A 和 B 都依賴了 foo,那么 foo 會提升至頂層,也就是說 node_modules 文件夾里的包會變成 A、B、foo
node_modules ├── A ├── B └── foo
這樣的好處是,同一個包 foo 只會有一份,節(jié)省了空間,但是引入了一個新的問題,引用混亂??!。
試想一下,我們的項目依賴本來只有 A 和 B,假如你想 import foo,肯定是找不到的,但是扁平化的結(jié)果,將 A 和 B 的依賴層級提升到了頂級,這樣,我們直接引用 foo,其實也不會報錯,但實際上我們并沒有指定依賴 foo,導(dǎo)致了使用上的混亂,假如有一天,A 和 B 都不依賴于 foo 了,那我們的項目或者說我提供的包就會報錯
這個不良的行為其實已經(jīng)默默的融入我們的開發(fā)中,當(dāng)我們使用 ant-design 時,我們可以直接使用 moment,當(dāng)我們使用 axios 時,我們可以直接使用 qs,當(dāng)我們使用 webpack 時,我們可以直接使用 lodash,而無需額外的安裝包
pnpm 的 node_modules
假設(shè)我們的項目依賴 foo 包,而 foo 又依賴 bar 包,那么 pnpm 安裝后的實際 node_modules 結(jié)果如下
node_modules ├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo └── .pnpm ├── bar@1.0.0 │ └── node_modules │ └── bar -> <store>/bar └── foo@1.0.0 └── node_modules ├── foo -> <store>/foo └── bar -> ../../bar@1.0.0/node_modules/bar
我們分析一下這個目錄結(jié)構(gòu)
- 包都是從 store 軟鏈接而來
- 項目直接使用的包只有一個 foo,保證了只有依賴項中的包才能訪問
- 有個隱藏的文件夾 .pnpm,這里將所有的依賴進(jìn)行扁平化,這樣避免了循環(huán)符號鏈接,同時 foo 還能引用自己
如果添加 qar@2.0.0 作為 bar 和 foo 的依賴項,那么結(jié)果會變成
node_modules ├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo └── .pnpm ├── bar@1.0.0 │ └── node_modules │ ├── bar -> <store>/bar │ └── qar -> ../../qar@2.0.0/node_modules/qar ├── foo@1.0.0 │ └── node_modules │ ├── foo -> <store>/foo │ ├── bar -> ../../bar@1.0.0/node_modules/bar │ └── qar -> ../../qar@2.0.0/node_modules/qar └── qar@2.0.0 └── node_modules └── qar -> <store>/qar
如何使用 pnpm
安裝
直接安裝
curl -fsSL https://get.pnpm.io/install.sh | PNPM_VERSION=7.0.0-rc.2 sh -
或者
wget -qO- https://get.pnpm.io/install.sh | PNPM_VERSION=7.0.0-rc.2 sh -
通過 npm 安裝
npm install -g pnpm@next-7
通過 HomeBrew 安裝( 一種 MacOS 包管理器)
brew install pnpm
升級
簡單的通過 pnpm 自己的命令升級即可
pnpm add -g pnpm
使用
配置
大部分配置可以直接使用 npm 的配置,與之區(qū)別的是有些配置可能是 pnpm 專有的,例如:
# 配置倉庫路徑 pnpm config set store-dir /path/to/.pnpm-store
命令
安裝依賴
pnpm install # 其他一些參數(shù) --offline 僅從 store 中離線下載 --dev, -D 只下載 devDependencies 依賴 --frozen-lockfile 不會生成 lockfile --shamefully-hoist 創(chuàng)建扁平結(jié)構(gòu),類似于 npm ,不推薦
2. 增加依賴
pnpm add <pkg>
這里 pnpm 有多種增加方式
- 直接通過配置的源安裝
在 workspace 中,會先檢查 workspace 是否有相應(yīng)包,至于 workspace 是什么,在下面會詳細(xì)說道
從本地安裝: 例如你想調(diào)試開發(fā)的包時
pnpm add ./package.tar.gz pnpm add ./some-directory
從遠(yuǎn)端安裝 Tar 包
pnpm add https://github.com/indexzero/forever/tarball/v0.5.6
從 git 安裝
pnpm add <git remote url>
# 其他一些參數(shù) --save-dev, -D 安裝為 devDependencies,也就是開發(fā)環(huán)境使用的包 --save-peer 安裝為 peerDependencies ,同時安裝到 devDependencies, peerDependencies 通常是和該包一起使用的其他包,需要使用者同時下載 --global, -g 安裝為全局依賴
發(fā)布依賴
pnpm [-r] publish [<tarball|folder>] [--tag <tag>] [--access <public|restricted>] [options] --no-git-checks 不檢查當(dāng)前分支是否是可發(fā)布分支,是否有沒有提交的代碼,直接發(fā)布 --dry-run 執(zhí)行發(fā)布包的所有流程,但唯獨不會真正把包發(fā)布到源上,這個在測試發(fā)布的時候非常有用 -r 遞歸的執(zhí)行發(fā)布命令,通常在 workspace 中使用
這里只列出常用的一些,更多的命令可以參考官網(wǎng)
和其他包管理器比較
npm 命令 | pnpm 等效 |
---|---|
npm install | pnpm install |
npm i | [pnpm add ] |
npm run | [pnpm ] |
功能 | pnpm | Yarn | npm |
---|---|---|---|
工作空間支持(monorepo) | ?? | ?? | ?? |
隔離的 node_modules | ?? - 默認(rèn) | ?? | ? |
提升的 node_modules | ?? | ?? | ?? - 默認(rèn) |
Plug'n'Play | ?? | ?? - 默認(rèn) | ? |
零安裝 | ? | ?? | ? |
修補(bǔ)依賴項 | ? | ?? | ? |
管理 Node.js 版本 | ?? | ? | ? |
有鎖文件 | ?? - pnpm-lock.yaml | ?? - yarn.lock | ?? - package-lock.json |
支持覆蓋 | ?? | ?? - 通過 resolutions | ?? |
內(nèi)容可尋址存儲 | ?? | ? | ? |
動態(tài)包執(zhí)行 | ?? - 通過 pnpm dlx | ?? - 通過 yarn dlx | ?? - 通過 npx |
Monorepo 及 工作空間(Workspace)
什么是 Monorepo
Monorepo 由兩個單詞組成,Mono 指的是單個(single),repo 指的是項目存儲(Repository),合起來意思就是說,大量的項目存儲在單一的庫中,用人話講就是,不同的項目都寫在一個 git 庫里,第一次聽到這個概念的時候大家肯定覺得這人指定有什么大病,這么多項目放一起,大家在里面各種修改,一個人項目修改了,另一個不相干的項目肯定還得更新代碼,這不是技術(shù)倒退么,這個其實還真就是 Monorepo 的缺點,但是靜下心來考慮,他的優(yōu)點也還是很多的,例如:
- 不同項目之間,如果需要復(fù)用相同的組件或者方法,現(xiàn)在就可以很方便的引用了,同時,這些公用方法一旦修改了,其他項目的相應(yīng)邏輯交互也都更新了,不同在擔(dān)心忘了安裝或者更新,同時也比單純的 復(fù)制黏貼 要更科學(xué)
這里插一句,很多公司的項目說是獨立的,其實都是從已有的項目中各種復(fù)制來的,連帶著以前的 bug 也都有了,還不如放一起呢
- 也不是所有的項目都適合放在一起,只有項目之間重合度高的,才應(yīng)該放一起,例如:管理系統(tǒng),基本表單操作之類的復(fù)用度很高,如果是不相關(guān)的項目,彼此沒有交集,那就別折騰了
- 不同項目之間,如果拆分的力度比較細(xì),互相之間有調(diào)用,那就適合放在一起,最常見的是 npm 庫,不同的庫之間可能有依賴,同時每個庫還需要單獨發(fā)布
- 它倡導(dǎo)了一種開放,透明,共享的組織文化,所有的開發(fā)者都可以瀏覽學(xué)習(xí)其他人的代碼
說完了 Monorepo ,離真正應(yīng)用還是有點差距,多個項目之間需要保證自己的獨立性,還需要能方便的根據(jù)其他項目的變動做出相應(yīng)的改變,目前市面上也有很多其他的方便管理 Monorepo 的工具,例如:lernajs,幸運(yùn)的是,pnpm 也對 Monorepo 有著良好的支持,pnpm 稱他為 workspace
值得一提的是,vite 也對 Monorepo 做了支持,這使得當(dāng)引用的其他庫發(fā)生變化時,正在使用 vite dev 開發(fā)的項目也會熱更新,詳細(xì)可見Monorepo 和鏈接依賴
Workspace
pnpm 可以創(chuàng)建一個 workspace 將多個項目合并到一個中,一個 workspace 的根目錄下必須有 pnpm-workspace.yaml 文件,常見的 pnpm-workspace.yaml 類似于下面這種配置,可以定義哪些文件或者文件夾應(yīng)該包含于 workspace 中
packages: # all packages in subdirs of packages/ and components/ - 'packages/**' - 'components/**' # exclude packages that are inside test directories - '!**/test/**'
在 workspace 根目錄使用 pnpm install 命令時,會自動將 workspace 中的所有項目執(zhí)行 pnpm install
workspace: 協(xié)議
pnpm 支持協(xié)議 workspace:,當(dāng)使用這個協(xié)議時,pnpm 只會解析本地 workspace 中的包,workspace: 協(xié)議的使用方法和 package.json 引用包的方法一致
"foo": "workspace:*" "foo": "workspace:../foo" "foo": "workspace:~", "foo": "workspace:^", "zoo": "workspace:^1.5.0"
當(dāng)需要發(fā)布包時,例如使用 pnpm pack 或者 pnpm publish 命令時,將動態(tài)的把 workspace: 協(xié)議替換為真正的版本號
結(jié)語
pnpm 目前被越來越多的人使用,其中也包括 vue 這樣的一線開源框架,具體可以參見 使用示例
在諸如 pnpm 或者 yarn 這樣的開源項目影響下,npm 也在反思自己,也及時的做出了更新,例如:支持 workspace 等功能,希望這樣的良性循環(huán)也讓 js 社區(qū)越來越好,或許有一天我還會重投 npm 的懷抱也說不定
以上就是使用pnpm包管理器替代npm及yarn的命令示例的詳細(xì)內(nèi)容,更多關(guān)于pnpm包管理器替代npm及yarn命令的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript?與?TypeScript之間的聯(lián)系
這篇文章主要介紹了?JavaScript?與?TypeScript之間的聯(lián)系,JavaScript,也稱為?JS,是一種符合?ECMAScript?規(guī)范的編程語言。這是一個高級別的、通常是即時編譯的、多范式的。TypeScript?是一種強(qiáng)類型、面向?qū)ο蟮木幾g語言,更多消息內(nèi)容,需要的朋友可以參考一下下面文章內(nèi)容2021-11-11在微信小程序中渲染HTML內(nèi)容3種解決方案及分析與問題解決
在開發(fā)微信小程序時我們會在小程序內(nèi)加入純HTML代碼,且HTML中包括圖片,視頻,甚至是事件,微信小程序為我們提供了3種解決方法,但它們的功能與實現(xiàn)方式與最終效果并不理想2020-01-01關(guān)于JavaScript?中?if包含逗號表達(dá)式
這篇文章主要介紹了?關(guān)于JavaScript?中?if包含逗號表達(dá)式,有時會看到JavaScript中if判斷里包含英文逗號?“,”,這個是其實是逗號表達(dá)式。在if條件里,只有最后一個表達(dá)式起判斷作用。下面來看看文章的具體介紹吧2021-11-11