facebook yarn -- 一個(gè)可能取代npm的新型包管理器

原文鏈接 : Yarn: A new package manager for JavaScript
原文作者 : SEBASTIAN MCKENZIECHRISTOPH POJER氨淌,JAMES KYLE
譯文出自 : 掘金翻譯計(jì)劃
譯者 : 達(dá)仔
校對(duì)者: 根號(hào)三

JavaScript 包管理方式在 Facebook 的演變
在包管理工具出現(xiàn)之前志笼,JavaScript 工程師們通常依賴(lài)的項(xiàng)目并不多撬讽,因此會(huì)把依賴(lài)直接存儲(chǔ)在工程目錄或上傳到 CDN 上懊缺。在 Node.js 出現(xiàn)后不久袱巨,第一個(gè)主流的 JavaScript 包管理工具 npm
被引入進(jìn)來(lái),并很快成為了最受歡迎的包管理工具之一往核。從此,新的開(kāi)源項(xiàng)目不斷涌現(xiàn)嚷节,工程師們比起以前更加樂(lè)于分享代碼了聂儒。
在 Facebook 中,我們有很多項(xiàng)目都要依賴(lài) npm
倉(cāng)庫(kù)上的代碼丹喻,比如 React薄货。但隨著內(nèi)部規(guī)模的擴(kuò)大,我們面臨著以下挑戰(zhàn):在跨平臺(tái)與跨用戶之間安裝依賴(lài)時(shí)的代碼一致性問(wèn)題碍论、在安裝依賴(lài)時(shí)花費(fèi)太長(zhǎng)時(shí)間谅猾、以及 npm
客戶端自動(dòng)執(zhí)行某些依賴(lài)庫(kù)的代碼所導(dǎo)致的安全性問(wèn)題。我們嘗試過(guò)尋找這些問(wèn)題的解決方案,但在這個(gè)過(guò)程中通常又會(huì)引起一些新的問(wèn)題税娜。
嘗試修改 npm 客戶端
在開(kāi)始階段坐搔,我們遵循了最佳實(shí)踐,在代碼倉(cāng)庫(kù)中只跟蹤了 package.json
文件的變化敬矩,并要求工程師手動(dòng)運(yùn)行 npm install
命令安裝依賴(lài)概行。這種模式在開(kāi)發(fā)人員的電腦上沒(méi)有問(wèn)題,但在持續(xù)集成環(huán)境中遇到了困難弧岳,因?yàn)槌鲇诎踩c可靠性的考慮凳忙,持續(xù)集成環(huán)境需要進(jìn)行沙箱隔離,不能進(jìn)行聯(lián)網(wǎng)禽炬,因此也無(wú)法安裝依賴(lài)涧卵。
接下來(lái),我們嘗試在代碼倉(cāng)庫(kù)中跟蹤整個(gè) node_modules
目錄的文件變化腹尖。雖然這種方式有效柳恐,卻使得一些簡(jiǎn)單操作變得復(fù)雜化了。比如热幔,對(duì) babel 更新一個(gè)次要版本號(hào)時(shí)乐设,會(huì)產(chǎn)生多達(dá) 800,000 行的提交記錄,此外由于 lint 規(guī)則的存在绎巨,引起無(wú)效的 utf-8 字節(jié)序列近尚、windows 換行符、非 png 壓縮圖片等問(wèn)題時(shí)认烁,將會(huì)導(dǎo)致工程師經(jīng)常需要花費(fèi)一整天的時(shí)間合并 node_modules
目錄的文件肿男。而我們負(fù)責(zé)源碼控制的團(tuán)隊(duì)也指出,跟蹤 node_modules
目錄會(huì)引入過(guò)多的元數(shù)據(jù)却嗡。比如 React Native 的package.json
文件目前只列出了68項(xiàng)依賴(lài)舶沛,但在運(yùn)行 npm install
后,node_modules
目錄整整包含了 121,358 個(gè)文件窗价。
最后如庭,為了有效組織 Facebook 逐漸增長(zhǎng)的工程師人數(shù)以及管理需要安裝的代碼量,我們嘗試修改npm
客戶端撼港。我們決定壓縮整個(gè) node_modules
目錄坪它,并上傳到內(nèi)部 CDN,然后我們的工程師與持續(xù)集成系統(tǒng)都能從 CDN 上下載并解壓文件帝牡,從而保證了代碼一致性往毡。這樣我們就可以從源碼控制系統(tǒng)中刪除數(shù)以萬(wàn)計(jì)的文件了,但不足之處是工程師現(xiàn)在不僅在拉代碼時(shí)需要聯(lián)網(wǎng)了靶溜,構(gòu)建也同樣需要聯(lián)網(wǎng)开瞭。
我們還試圖為 npm
shrinkwrap 功能尋求優(yōu)化方案懒震,這個(gè)工具是用來(lái)鎖定依賴(lài)版本號(hào)的。但Shrinkwrap
功能的文件默認(rèn)不會(huì)生成嗤详,如果開(kāi)發(fā)者忘記了生成這一步驟个扰,文件就不會(huì)被同步更新,因此我們編寫(xiě)了一個(gè)工具葱色,以確定 Shrinkwrap
的文件內(nèi)容和 node_modules
目錄中的文件相符递宅。這些文件由大量的 JSON 塊組成,并且鍵名是無(wú)序的苍狰,因此每次更改通常會(huì)導(dǎo)致 Shrinkwrap
文件的內(nèi)容大幅變化办龄,難以進(jìn)行代碼審查。為減緩這一問(wèn)題舞痰,我們還需要借助一個(gè)額外的腳本土榴,對(duì)所有條目進(jìn)行排序诀姚。
最后响牛,通過(guò) npm
升級(jí)單個(gè)依賴(lài)包時(shí),基于 語(yǔ)義化版本號(hào) 規(guī)則赫段,npm
通常會(huì)連同其他無(wú)關(guān)依賴(lài)一起更新呀打。這使得每次更新都會(huì)比預(yù)期產(chǎn)生更多的變化,工程師們認(rèn)為這樣把 node_modules
提交上傳到 CDN 的過(guò)程糯笙,難以達(dá)到預(yù)期的效果贬丛。
構(gòu)建新客戶端
與其圍繞 npm
客戶端繼續(xù)構(gòu)建基礎(chǔ)設(shè)施,不如從整體上再次回顧這些問(wèn)題给涕。倫敦辦公室的 Sebastian McKenzie 提出豺憔,如果我們建立一個(gè)新客戶端工具以代替 npm
客戶端,從而解決我們的核心問(wèn)題呢够庙?這一構(gòu)思很快得到了我們的認(rèn)同恭应,團(tuán)隊(duì)對(duì)于這個(gè)主意也感到非常興奮。
在開(kāi)發(fā)過(guò)程中耘眨,我們與業(yè)界的工程師們進(jìn)行了交流討論昼榛,發(fā)現(xiàn)他們也面臨著類(lèi)似的問(wèn)題,也嘗試過(guò)許多類(lèi)似的解決方案剔难,通常只能把這些問(wèn)題逐一解決胆屿。很明顯,有必要把整個(gè) JavaScript 社區(qū)正在面臨的問(wèn)題集合起來(lái)偶宫,然后我們就可以開(kāi)發(fā)一個(gè)主流的解決方案了非迹。在此感謝 Exponent、 Google 與 Tilde 的工程師們的協(xié)助纯趋,我們共同建立了 Yarn
客戶端憎兽,并在每一個(gè)主流 JS 框架以及 Facebook 外的使用場(chǎng)景中測(cè)試驗(yàn)證了 Yarn 的性能。今天(2016-10-11),我們很榮幸把這個(gè)工具開(kāi)源分享到社區(qū)中唇兑。
介紹 Yarn
Yarn
是一個(gè)新的包管理器酒朵,用于替代現(xiàn)有的 npm
客戶端或者其他兼容 npm
倉(cāng)庫(kù)的包管理工具。Yarn
保留了現(xiàn)有工作流的特性扎附,優(yōu)點(diǎn)是更快蔫耽、更安全、更可靠留夜。
任何包管理器的主要功能都是安裝某些軟件包匙铡,軟件包即用于特定功能的某段代碼,通常是從一個(gè)全局的倉(cāng)庫(kù)安裝到工程師的本地環(huán)境碍粥。每個(gè)軟件包可以依賴(lài)于其他包鳖眼,也可以不依賴(lài)。一個(gè)典型的項(xiàng)目結(jié)構(gòu)的依賴(lài)樹(shù)通常會(huì)包含數(shù)十個(gè)嚼摩、數(shù)百個(gè)甚至上千個(gè)軟件包钦讳。
這些依賴(lài)包通常是帶版本號(hào)的,通過(guò)語(yǔ)義化版本控制(semver)安裝枕面。Semver 定義的版本號(hào)反映了每個(gè)新版本更改的類(lèi)型愿卒,到底是進(jìn)行了不兼容的API改動(dòng)(MAJOR),還是添加了向后兼容的新特性(MINOR)潮秘,還是進(jìn)行了向后兼容的 bug 修復(fù)(PATCH)琼开。然而,semver 依賴(lài)于軟件包的開(kāi)發(fā)者不能犯錯(cuò)誤——如果依賴(lài)關(guān)系沒(méi)有加鎖枕荞,可能會(huì)引入一些破壞性更改或者產(chǎn)生新的 bug柜候。
結(jié)構(gòu)
在 Node 生態(tài)系統(tǒng)中,依賴(lài)通常安裝在項(xiàng)目的 node_modules
文件夾中躏精。然而渣刷,這個(gè)文件的結(jié)構(gòu)和實(shí)際依賴(lài)樹(shù)可能有所區(qū)別,因?yàn)橹貜?fù)的依賴(lài)可以合并到一起玉控。npm
客戶端把依賴(lài)安裝到 node_modules
目錄的過(guò)程具有不確定性飞主。這意味著當(dāng)依賴(lài)的安裝順序不同時(shí),node_modules
目錄的結(jié)構(gòu)可能會(huì)發(fā)生變化高诺。這種差異可能會(huì)導(dǎo)致類(lèi)似“我的機(jī)子上可以運(yùn)行碌识,別的機(jī)子不行”的情況,并且通常要花費(fèi)大量時(shí)間定位與解決虱而。
Yarn
通過(guò) lockfiles 文件以及一個(gè)確定性的筏餐、可靠的安裝算法,解決了版本問(wèn)題和 npm
的不確定性問(wèn)題牡拇。Lockfile 文件把安裝的軟件包版本鎖定在某個(gè)特定版本魁瞪,并保證 node_modules
目錄在所有機(jī)器上的安裝結(jié)果都是相同的穆律。Lockfile 還使用簡(jiǎn)潔的有序鍵名的格式,保證了每次的文件變化最小化导俘,進(jìn)行代碼審查也更為簡(jiǎn)單峦耘。
安裝過(guò)程分為以下三個(gè)步驟:
處理: Yarn
通過(guò)向代碼倉(cāng)庫(kù)發(fā)送請(qǐng)求,并遞歸查找每個(gè)依賴(lài)項(xiàng)旅薄,從而解決依賴(lài)關(guān)系辅髓。
抓取: 接下來(lái)少梁,Yarn
會(huì)查找全局的緩存目錄洛口,檢查所需的軟件包是否已被下載。如果沒(méi)有凯沪,Yarn 會(huì)抓取對(duì)應(yīng)的壓縮包第焰,并放置在全局的緩存目錄中,因此 Yarn
支持離線安裝妨马,同一個(gè)安裝包不需要下載多次挺举。依賴(lài)也可以通過(guò) tarball 的壓縮形式放置在源碼控制系統(tǒng)中,以支持完整的離線安裝身笤。
生成: 最后豹悬,Yarn
從全局緩存中把需要用到的所有文件復(fù)制到本地的 node_modules
目錄中。

通過(guò)清晰地細(xì)分這些步驟液荸,以及確定性的算法支持,使得 Yarn
支持并行操作脱篙,從而最大化地利用資源娇钱,并加速安裝進(jìn)程。在一些 Facebook 的項(xiàng)目上绊困,Yarn
甚至可以把安裝過(guò)程降低一個(gè)數(shù)量級(jí)文搂,從幾分鐘到只需幾秒鐘。Yarn
還使用了互斥鎖秤朗,以確保多個(gè) CLI 實(shí)例同時(shí)運(yùn)行時(shí)不會(huì)互相沖突與影響煤蹭。
縱觀整個(gè)過(guò)程,Yarn
對(duì)于軟件包安裝加上了嚴(yán)格的限制取视。你可以對(duì)哪個(gè)生命周期腳本作用于哪個(gè)軟件包進(jìn)行控制硝皂。軟件包的 checksum 也會(huì)存儲(chǔ)在 lockfile 中,以確保每一次安裝都可以得到同一個(gè)包作谭。
特性
Yarn
除了讓安裝過(guò)程變得更快與更可靠稽物,還添加了一些額外的特性,從而進(jìn)一步簡(jiǎn)化依賴(lài)管理的工作流折欠。
同時(shí)兼容 npm
bower 工作流贝或,并支持兩種軟件倉(cāng)庫(kù)混合使用
可以限制已安裝模塊的協(xié)議吼过,并提供方法輸出協(xié)議信息
提供一套穩(wěn)定的公有 JS API,用于記錄構(gòu)建工具的輸出信息
可讀咪奖、最小化盗忱、美觀的 CLI 輸出信息

Yarn 用于生產(chǎn)環(huán)境
我們已經(jīng)在 Facebook 中把 Yarn
用于生產(chǎn)環(huán)境,并且效果非常理想羊赵。Yarn
有效地管理了許多 JavaScript 項(xiàng)目的包依賴(lài)關(guān)系售淡。在每次遷移時(shí),構(gòu)建都可以離線進(jìn)行慷垮,因此加速了工作流程揖闸。我們基于 React Native 在不同條件下進(jìn)行安裝時(shí)間測(cè)試,比較了 Yarn
與 npm
的性能料身,具體參見(jiàn)這里汤纸。


起步
最簡(jiǎn)單的起步方法是:
npm install -g yarnpkgyarn

yarn
CLI 代替了原有開(kāi)發(fā)工作流中 npm
CLI 的作用,用法可能是單純的替代芹血,也可能是一個(gè)新的贮泞、相似的命令:
npm install
→ yarn

不需要帶參數(shù),yarn
命令會(huì)讀取 package.json
文件幔烛,然后從 npm 倉(cāng)庫(kù)中抓取軟件包啃擦,并放置到 node_modules
目錄中。等價(jià)于運(yùn)行 npm install
饿悬。

npm install --save <name>
→ yarn add <name>

我們避免了 npm install <name>
命令中安裝“不可見(jiàn)的依賴(lài)”的行為令蛉,并分離出一個(gè)新命令。運(yùn)行 yarn add <name>
等價(jià)于運(yùn)行 npm install --save <name>
狡恬。

未來(lái)
目前已經(jīng)有許多成員一起參與到 Yarn
的構(gòu)建中珠叔,以解決我們的共同問(wèn)題,我們也希望 Yarn
未來(lái)能真正成為一個(gè)大眾化的社區(qū)項(xiàng)目弟劲。Yarn
目前已經(jīng) 在 GitHub 開(kāi)源 祷安,我們也已經(jīng)準(zhǔn)備好向 Node 社區(qū)進(jìn)行推廣:使用 Yarn
、分享構(gòu)思兔乞、編寫(xiě)文檔汇鞭、互相支持,并幫助構(gòu)建一個(gè)很棒的社區(qū)來(lái)進(jìn)行長(zhǎng)期維護(hù)庸追。我們相信 Yarn
已經(jīng)擁有一個(gè)良好的開(kāi)局霍骄,如果有你的幫助,Yarn
的未來(lái)將會(huì)更加美好锚国。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末腕巡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子血筑,更是在濱河造成了極大的恐慌绘沉,老刑警劉巖煎楣,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異车伞,居然都是意外死亡择懂,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)另玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)困曙,“玉大人,你說(shuō)我怎么就攤上這事谦去】独觯” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵鳄哭,是天一觀的道長(zhǎng)要糊。 經(jīng)常有香客問(wèn)我,道長(zhǎng)妆丘,這世上最難降的妖魔是什么锄俄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮勺拣,結(jié)果婚禮上奶赠,老公的妹妹穿的比我還像新娘。我一直安慰自己药有,他們只是感情好毅戈,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著塑猖,像睡著了一般竹祷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上羊苟,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音感憾,去河邊找鬼蜡励。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阻桅,可吹牛的內(nèi)容都是我干的凉倚。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼嫂沉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼稽寒!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起趟章,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤杏糙,失蹤者是張志新(化名)和其女友劉穎慎王,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體宏侍,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赖淤,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谅河。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咱旱。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖绷耍,靈堂內(nèi)的尸體忽然破棺而出吐限,到底是詐尸還是另有隱情,我是刑警寧澤褂始,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布诸典,位于F島的核電站,受9級(jí)特大地震影響病袄,放射性物質(zhì)發(fā)生泄漏搂赋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一益缠、第九天 我趴在偏房一處隱蔽的房頂上張望脑奠。 院中可真熱鬧,春花似錦幅慌、人聲如沸宋欺。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)齿诞。三九已至,卻和暖如春骂租,著一層夾襖步出監(jiān)牢的瞬間祷杈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工渗饮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留但汞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓互站,卻偏偏與公主長(zhǎng)得像私蕾,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胡桃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容