<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么 vue 源碼以及生態(tài)倉(cāng)庫(kù)要遷移 pnpm?

          共 8613字,需瀏覽 18分鐘

           ·

          2022-01-23 20:07

          大廠技術(shù)  高級(jí)前端  Node進(jìn)階

          點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)

          回復(fù)1,加入高級(jí)Node交流群

          前言

          隨著前段時(shí)間尤大在 vue3 以及 vite 倉(cāng)庫(kù)中切換包管理為 pnpm 的 pr 成功 merge,以及 vue 生態(tài)中的一些項(xiàng)目例如 VueUse 也切換使用 pnpm,宣告著 vue 生態(tài)中項(xiàng)目倉(cāng)庫(kù)完成了從原有的 yarn workspace monorepo 到 pnpm workspace monorepo 的遷移。

          可以看到 vite 核心貢獻(xiàn)者以及 vue 團(tuán)隊(duì)成員之一的 patak (https://github.com/patak-js) 在 twitter 上對(duì)這次項(xiàng)目遷移的生動(dòng)描述:“項(xiàng)目如同多米諾骨牌一樣倒向了 pnpm”。

          具體關(guān)于 pnpm 相關(guān)介紹可以參考筆者之前寫的一篇文章: pnpm: 最先進(jìn)的包管理工具 ,本文中不會(huì)對(duì)此做更多的介紹。

          vue 遷移項(xiàng)目

          其中關(guān)于 vue 生態(tài)中項(xiàng)目遷移的具體過(guò)程可以參考這些的一些 pr:

          • https://github.com/vuejs/vue-next/pull/4766

          • https://github.com/vitejs/vite/pull/5060

          • https://github.com/vueuse/vueuse/commit/826351ba1d9c514e34426c85f3d69fb9875c7dd9

          其中包括目前 vue3.0 項(xiàng)目源碼倉(cāng)庫(kù):

          以及目前社區(qū)里面火熱的 bundleless 工具 vite 源碼倉(cāng)庫(kù):

          可以看到這兩個(gè)的遷移 pr 都是由尤大親手完成改造,同時(shí) pnpm 作者的本人 zkochan(github: https://github.com/zkochan) 也親自幫 vite 遷移的 pr 做了 code review

          以上幾個(gè)項(xiàng)目都是基于 monorepo 來(lái)做的倉(cāng)庫(kù)管理,pnpm 的 workspace 在 monorepo 場(chǎng)景下是有著極好的支持,當(dāng)然也有非 monorepo 項(xiàng)目的遷移,例如由筆者遷移的 naive-ui 倉(cāng)庫(kù)的項(xiàng)目中包管理工具為 pnpm 用于提升 CI 下依賴安裝速度的提升(參考pr: https://github.com/TuSimple/naive-ui/pull/1425 )。

          下面來(lái)介紹一些這次的遷移動(dòng)機(jī)以及引發(fā)問(wèn)題的源頭,注意以下的內(nèi)容都是根據(jù)一些社區(qū)討論進(jìn)行推斷的,可能并不完整或者準(zhǔn)確,但是對(duì)于具體的細(xì)節(jié)我會(huì)盡量還原到位,同時(shí)也不會(huì)對(duì)此過(guò)度解讀,希望讀者自行甄別。如果錯(cuò)誤,歡迎指正。

          遷移原因

          在尤大9月份的一條 twitter 中,發(fā)起了一條關(guān)于包管理器的投票,當(dāng)時(shí)筆者正混跡 pnpm 社區(qū),對(duì)此也有所耳聞,具體的投票結(jié)果可以參考:

          pnpm 作者本人 zkochan 對(duì)此結(jié)果還是很滿意的,因?yàn)橹敖y(tǒng)計(jì)社區(qū)的一些趨勢(shì),pnpm 并沒(méi)有達(dá)到過(guò)如此高的使用率。

          隨著該條 twitter 之后,尤大又更新了一條 twitter (這里直接貼原文的內(nèi)容):

          esbuild 0.13 now uses optionalDependencies to install platform-specific binaries. Yarn 1/2 will download all binaries before picking the right one. Other (update to date) package managers only downloads the matching one.

          This may be the thing that pushes me away from Yarn 1 :/

          翻譯過(guò)來(lái)的內(nèi)容大概是 esbuild 在 v0.13 之后使用了optionalDependencies 來(lái)安裝某些不同平臺(tái)的依賴(相關(guān) pr 可以參考: https://github.com/evanw/esbuild/pull/1621)。但  yarn 1/2 并不會(huì)根據(jù)對(duì)應(yīng)的 optional 規(guī)則去下載對(duì)應(yīng)平臺(tái)的包而是會(huì)去選擇下載所有的包。

          那么為什么 esbuild 的一個(gè)調(diào)整會(huì)對(duì)尤大產(chǎn)生這樣的念頭呢,因?yàn)?vite 目前會(huì)在一些場(chǎng)景下使用到 esbuild 這個(gè)庫(kù):例如目前開(kāi)發(fā)階段 vite 會(huì)使用 esbuild 進(jìn)行依賴預(yù)打包,來(lái)將第三方依賴轉(zhuǎn)成 ESM 格式的 bundle 產(chǎn)物。

          這樣的關(guān)系使得 esbuild 作為了 vite 的一個(gè)底層依賴,前面也提到過(guò) vite 本身倉(cāng)庫(kù)是基于 yarn workspace monorepo 搭建的,因此每次在開(kāi)發(fā) vite 時(shí)使用 yarn 安裝依賴的過(guò)程中,都會(huì)去安裝 esbuild 以及相關(guān)的包。

          下面筆者會(huì)詳細(xì)介紹一下 esbuild 的這個(gè)改動(dòng)的原理以及為什么這個(gè)改動(dòng)會(huì)使得 vite 將原有的 monorepo 架子直接做了遷移。

          依賴分發(fā)機(jī)制

          在上一節(jié)中提到了 esbuild 使用 optionalDependenceis 來(lái)作為目前的依賴安裝策略,這節(jié)來(lái)介紹一下像這樣這些跨平臺(tái)的包依賴分發(fā)的過(guò)程。

          其實(shí)關(guān)于這部分,具體可以參考社區(qū)中這篇: 用 Rust 和 N-API 開(kāi)發(fā)高性能 Node.js 擴(kuò)展(文章地址: https://zhuanlan.zhihu.com/p/234914336) 文章最開(kāi)頭的一部分內(nèi)容。

          這里筆者以 nodejs 原生拓展(native addon)的代碼分發(fā)方式為例子做個(gè)介紹:

          關(guān)于 nodejs 拓展開(kāi)發(fā)可以參考筆者之前寫過(guò)的一篇文章: Nodejs 的 C++ 拓展開(kāi)發(fā)

          其中主流的分發(fā)方式大概有這樣兩種:

          分發(fā) JS 代碼,postinstall 去下載對(duì)應(yīng)產(chǎn)物

          一般使用其他語(yǔ)言開(kāi)發(fā)的 addon 之類的會(huì)把產(chǎn)物打包成一個(gè)可執(zhí)行的二進(jìn)制文件(例如 C++ 拓展一般是 .node 結(jié)尾的文件)。

          postinstall 腳本安裝的方式其實(shí)在社區(qū)中也是比較常見(jiàn)的,例如安裝 node-sass 就會(huì)按照這樣的模式進(jìn)行:

          node-sass 會(huì)把 native addon(C++ 開(kāi)發(fā)) 的預(yù)編譯產(chǎn)物放在一個(gè) CDN 地址里面,然后用戶在使用 npm install 安裝 node-sass 的時(shí)候,會(huì)通過(guò) postinstall 腳本將 addon 產(chǎn)物文件從 CDN 上下載下來(lái)。

          包括 v0.13 版本之前的 esbuild 其實(shí)也是采用這種方式來(lái)進(jìn)行分發(fā)。

          這種方式其實(shí)有個(gè)缺點(diǎn),可以看到圖中下載的二進(jìn)制文件地址是個(gè) Github release 地址,這種情況下常常會(huì)因?yàn)闊o(wú)法兼顧國(guó)內(nèi)/海外用戶。不過(guò)一般可以通過(guò)在國(guó)內(nèi)搭建一個(gè)相關(guān)的下載鏡像來(lái)解決這個(gè)問(wèn)題,但鏡像不同步的問(wèn)題也是時(shí)常會(huì)發(fā)生的。

          不同平臺(tái)的 native addon 通過(guò)不同的 npm 包去分發(fā)

          目前市面上很火的兩個(gè)構(gòu)建工具,swc 和 esbuild 就采用的這種方式。每一個(gè) native addon 對(duì)應(yīng)一個(gè) npm 包。然后將所有的 native addon 對(duì)應(yīng)的 npm package 作為 optionalDependencies, 并在這些 npm package 的 package.json 中的 os 以及 cpu 字段,讓對(duì)應(yīng)的包管理工具在安裝的時(shí)候?qū)Σ煌脚_(tái)的包自動(dòng)選擇去安裝哪個(gè) native package,例如 esbuild 目前的 npm 包結(jié)構(gòu):

          {
          "name": "esbuild",
          "version": "0.14.1",
          "optionalDependencies": {
          "esbuild-android-arm64": "0.14.1",
          "esbuild-darwin-64": "0.14.1",
          "esbuild-darwin-arm64": "0.14.1",
          "esbuild-freebsd-64": "0.14.1",
          "esbuild-freebsd-arm64": "0.14.1",
          "esbuild-linux-32": "0.14.1",
          "esbuild-linux-64": "0.14.1",
          "esbuild-linux-arm": "0.14.1",
          "esbuild-linux-arm64": "0.14.1",
          "esbuild-linux-mips64le": "0.14.1",
          "esbuild-linux-ppc64le": "0.14.1",
          "esbuild-netbsd-64": "0.14.1",
          "esbuild-openbsd-64": "0.14.1",
          "esbuild-sunos-64": "0.14.1",
          "esbuild-windows-32": "0.14.1",
          "esbuild-windows-64": "0.14.1",
          "esbuild-windows-arm64": "0.14.1"
          }
          }

          例如其中對(duì)應(yīng)的 esbuild-android-arm64 一個(gè)安卓平臺(tái)的包,以及 arm64 架構(gòu)的包的 package.json 內(nèi)容為:

          {
          "name": "esbuild-android-arm64",
          "version": "0.14.1",
          "os": ["android"],
          "cpu": ["arm64"]
          }

          這種方式可以認(rèn)為是目前對(duì)使用 native addon 用戶影響最小的分發(fā)方式,包括這里提到的 esbuildswc 以及 napi-rs 都是采用的這種方式。

          這種方式存在的缺點(diǎn)可能就是對(duì)開(kāi)發(fā)者的負(fù)擔(dān)會(huì)比較大:因?yàn)樾枰瑫r(shí)維護(hù)多個(gè)系統(tǒng)以及 CPU 架構(gòu)的包。同時(shí)開(kāi)發(fā)/調(diào)試也需要消耗很大的工作量。

          前面提到的 vite 底層的依賴項(xiàng) esbuild 在 v0.13 之后由 postinstall script 安裝的方式遷移到了這種 optionalDependencies 的方式:

          包管理器支持

          在上一節(jié)中我們介紹到了 native addon 的一些常見(jiàn)的依賴分發(fā)機(jī)制,同時(shí)也介紹到了 esbuild 目前在 v0.13 之后采用了 optionalDependencies 機(jī)制。前面也有提到因?yàn)?nbsp;yarn1 的依賴安裝機(jī)制問(wèn)題導(dǎo)致在 vite 進(jìn)行開(kāi)發(fā)時(shí),每次都會(huì)下載 esbuild 中所有的跨平臺(tái)包(例如在 android 平臺(tái)上也會(huì)下載 ios 的包),對(duì)此會(huì)導(dǎo)致每次給 vite 倉(cāng)庫(kù)進(jìn)行依賴安裝的時(shí)候,耗費(fèi)很久的時(shí)間。參考 yarn 下面的 issue(https://github.com/yarnpkg/berry/issues/3317)。

          舉個(gè)例子來(lái)說(shuō)(該例子來(lái)自于 esbuild 作者 evanw 解釋):

          以目前 pnpm v6.14 的行為來(lái)說(shuō),對(duì)于 esbuild 下的 optionalDep 進(jìn)行依賴安裝的時(shí)候,下面有各種跨平臺(tái)以及 cpu 架構(gòu)的包,但實(shí)際上只會(huì)對(duì)符合當(dāng)前平臺(tái)架構(gòu)的包進(jìn)行實(shí)際的依賴安裝,其他非這一類的包只是會(huì)生成一個(gè) meta data 的數(shù)據(jù)在 lock 文件上。

          實(shí)際上包的體積時(shí)遠(yuǎn)遠(yuǎn)大于這份數(shù)據(jù)的大小(例如數(shù)據(jù)約 0.5MB,一個(gè)包大約 8MB),那么假設(shè) optionalDep 下面存在 13 個(gè) package,那么 pnpm 大概會(huì)安裝約 0.5mb * 13 + 8mb = 14.5mb 體積的包,而 yarnv1 則會(huì)安裝約 0.5mb * 12 + 8mb * 12 = 102mb 的包,這樣會(huì)使得因?yàn)榘芾砉ぞ卟煌那闆r下,yarn 安裝的東西比 pnpm 遠(yuǎn)多,從而導(dǎo)致依賴安裝的時(shí)間會(huì)很慢。

          關(guān)于上面提到的依賴安裝問(wèn)題可以參考下表中的 Downloads extra data 這一欄,可以看到目前 yarn 只有 yarnv3.1.0 這個(gè)版本修復(fù)了該問(wèn)題,pnpmnpm v7 以及 [email protected] 都解決了這個(gè)該問(wèn)題。

          vue 生態(tài)項(xiàng)目完成遷移

          尤大在社區(qū)里面參考了一些開(kāi)發(fā)者的意見(jiàn)以及發(fā)起了一個(gè)關(guān)于包管理器的投票,twitter 下 90% 左右的回復(fù)都推薦了 pnpm,包括目前 vue core team 的 antfu(https://github.com/antfu) 也已經(jīng)在自己的開(kāi)源項(xiàng)目 slidev(https://github.com/slidevjs/slidev) 中實(shí)踐使用了 pnpm,同時(shí)也對(duì) pnpm 的一些功能贊不絕口。

          于是 vite 直接在幾天之后開(kāi)始了由 yarn workspace 到 pnpm workspace 的遷移:

          在遷移過(guò)程中雖然遇到了一些問(wèn)題,但基本上隨著 pnpm 作者以及社區(qū)的幫助努力下,最后也都成功完成了,實(shí)際上的遷移成本也沒(méi)有特別的大,可以參考前面的 pr。

          在 vite 完成遷移之后,其他的 vue 生態(tài)項(xiàng)目也緊隨其后,雖然這些其他的項(xiàng)目底層可能沒(méi)有像 vite 遇到的 esbuild 的問(wèn)題那樣,但 pnpm 的一些其他優(yōu)勢(shì)(例如對(duì)依賴的嚴(yán)格管理,快速的依賴安裝,天然的 monoreo workspace 支持等)也吸引著 vue 生態(tài)遷移了包管理工具。因?yàn)橛辛?nbsp;vite 遷移的經(jīng)驗(yàn),其他項(xiàng)目的遷移也都很快完成了,基本上 vue3 的一個(gè)遷移相關(guān)的 mr 在一天的時(shí)間內(nèi)就完成了合并,慢慢地幾乎 vue 生態(tài)里面大部分項(xiàng)目都完成了遷移。

          遷移 pnpm 的實(shí)踐

          如果想了解如何從一個(gè)完整的 yarn workspace 項(xiàng)目遷移到 pnpm workspace,其實(shí)也不用去專門研究 vite 或者 vue3 的 pr 是怎么遷移的,在 pnpm 官網(wǎng)上有一篇來(lái)自于社區(qū)的文章: Replacing Lerna + Yarn with PNPM Workspaces (地址: https://www.raulmelo.dev/blog/replacing-lerna-and-yarn-with-pnpm-workspaces)。

          作者算是比較詳細(xì)的介紹了如果從yarn workspace(項(xiàng)目基于 lerna,但區(qū)別其實(shí)不大),遷移到 pnpm workspace 需要做的文件改動(dòng)以及項(xiàng)目變更。大概是這樣的一個(gè)流程:

          • 替換掉腳本命令,與 yarn 相關(guān)的命令替換為: pnpm <command> 或者 pnpm run <command>

          • 刪除掉頂部 package.json 中的 yarn workspace 配置

          • 替換掉的 workspace 配置用 pnpm-workspace.yaml 文件替代

          • 調(diào)整 pipeline、以及 Dockfile 或者其他 CI/CD 配置文件里面的依賴安裝命令

          • 刪除掉 yarn.lock 文件(這里也可以使用筆者開(kāi)發(fā)完善的 pnpm import 命令來(lái)完成 yarn.lock 文件轉(zhuǎn)換 /笑 )

          • 調(diào)整構(gòu)建相關(guān)的腳本(如果有 lerna 相關(guān)的 build 腳本)

          • 添加一個(gè) .npmrc 文件用于自定義一些 pnpm 的 CLI 行為表現(xiàn)(也可以不用)

          感興趣的同學(xué)可以去參考一下,或者直接和筆者進(jìn)行交流也可以(筆者在字節(jié)也遷移過(guò)比較多這一類型的項(xiàng)目,對(duì)此也有一些經(jīng)驗(yàn),這里就不做過(guò)多的介紹了)。

          總結(jié)

          其實(shí)之前在尤大發(fā)起關(guān)于包管理工具的投票時(shí),筆者就已經(jīng)注意到了,同時(shí)也關(guān)注到了 vue 開(kāi)始了 pnpm 的遷移,但當(dāng)時(shí)并沒(méi)有去仔細(xì)關(guān)注底層的原因。

          之前 yarn 的作者發(fā)布了 yarnv3.1(文檔見(jiàn): https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak),  里面最吸引人注意的 feature  可能是: yarn 在這個(gè)版本下支持了 pnpm 模式的依賴安裝方式(即 content-addressable store),但 yarn 的作者表示這次版本發(fā)布中實(shí)現(xiàn)的最復(fù)雜的 feature 是支持了本文中提到的按需安裝不同平臺(tái)以及 cpu 架構(gòu)的依賴包:

          筆者在最近學(xué)習(xí) swc 的時(shí)候,注意到了這一點(diǎn),抱著刨根問(wèn)底的心態(tài),去研究了一下這一系列遷移問(wèn)題背后的原因(原因令人暖心)。

          最后寫了這樣一篇干貨性不是很強(qiáng)的文章,可以作為一個(gè)記錄如果之后有相關(guān)的需求進(jìn)行開(kāi)發(fā)(例如使用其他語(yǔ)言開(kāi)發(fā) native addon 的時(shí)候)的話。同時(shí)也希望 pnpm 未來(lái)能成為一個(gè)社區(qū)中流行的包管理工具吧~

          Node 社群


          我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。


             “分享、點(diǎn)贊在看” 支持一波??

          瀏覽 14
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  豆花视频一区二区三区在线观看 | 亲子乱伦视频 | 日韩小视频 | 91成人电影免费 | 香蕉人妻AV久久久久天天 |