[譯] Yarn 官方介紹: 一款新的 JavaScript 包管理器

咖啡兔 9年前發布 | 12K 次閱讀 YARN JavaScript開發 JavaScript

Yarn 官方介紹: 一款新的 JavaScript 包管理器

  • Original: Yarn: A new package manager for JavaScript
  • Translated by:cssmagic

譯者前言

這兩天被 Yarn 刷屏了?對于新工具,范范地道聽途說或淺嘗輒止,不如靜下心來聽聽作者的心路歷程。我讀了多篇文章,感覺說得最清楚的還是 非死book 發表的這篇官方介紹,于是翻譯出來分享給大家。

在談論 Yarn 時,有人在談論前端圈的 “造輪子” 風氣,有人在談論 非死book 工程師的 PR 能力,有人在談論網絡速度……但讀完這篇文章之后,我看到的是前端工程、是開發體驗、是思維方式。相信不論是一線工程師還是架構師,都會從 非死book 團隊的思考中找到啟發。

In the JavaScript community, engineers share hundreds of thousands of pieces of code so we can avoid rewriting basic components, libraries, or frameworks of our own. Each piece of code may in turn depend on other pieces of code, and these dependencies are managed by package managers. The most popular JavaScript package manager is the npm client, which provides access to more than 300,000 packages in the npm registry. More than 5 million engineers use the npm registry, which sees up to 5 billion downloads every month.

在 JavaScript 社區里,開發者們共享出了成千上萬的代碼,這令我們不必自己從頭開始編寫最基礎的組件、類庫或框架。這些代碼之間通常層層依賴,而這些依賴關系正是由包管理器來管理的。當前最流行的 JavaScript 包管理器是 npm 客戶端,通過它,我們可以獲取 npm 倉庫中的 30 多萬個包。超過 500 萬名開發者在使用 npm 倉庫,每個月產生 50 多億次下載。

We've used the npm client successfully at 非死book for years, but as the size of our codebase and the number of engineers grew, we ran into problems with consistency, security, and performance. After trying to solve for each issue as it came up, we set out to build a new solution to help us manage our dependencies more reliably. The product of that work is called Yarn — a fast, reliable, and secure alternative npm client.

在 非死book,我們已經成功地使用 npm 客戶端多年了,但隨著代碼體積的不斷增長和團隊規模的不斷壯大,我們在一致性、安全性和性能方面遇到了問題。我們曾嘗試逐一解決這些問題,但最終,我們決定自己打造一套全新的解決方案,以一種更加可靠的方式來管理依賴。我們的工作成果叫作 Yarn——作為 npm 客戶端的替代器,它更加快速、可靠、安全。

We're pleased to announce the open source release of Yarn, a collaboration with Exponent, Google, and Tilde. With Yarn, engineers still have access to the npm registry, but can install packages more quickly and manage dependencies consistently across machines or in secure offline environments. Yarn enables engineers to move faster and with confidence when using shared code so they can focus on what matters — building new products and features.

今天,我們很榮幸地宣布,Yarn 以開源的方式發布,它是由 Exponent、 Google、Tilde 與我們合作完成的。在使用 Yarn 時,開發者們還像以前一樣從 npm 倉庫那里獲取資源,但安裝速度更快,不同的機器的安裝結果完全一致,甚至還可以在安全的離線環境中使用。Yarn 令開發者可以更加迅捷和從容地享受前人栽種的果實,進而集中精力打造自己的產品——這才是更加重要的事情。

The evolution of JavaScript package management at 非死book

JS 包管理方案在 非死book 的演變

In the days before package managers, it was commonplace for JavaScript engineers to rely on a small number of dependencies stored directly in their projects or served by a CDN. The first major JavaScript package manager, npm, was built shortly after Node.js was introduced, and it quickly became one of the most popular package managers in the world. Thousands of new open source projects were created and engineers shared more code than ever before.

在包管理器出現之前,JavaScript 開發者平時所用的依賴并不多,這些依賴通常會直接存放在項目中,或通過 CDN 引入。npm 是第一個正式的 JavaScript 包管理器,在 Node.js 誕生后不久它就建立起來了,隨后迅速成為全世界最流行的包管理器。從此,開源項目如雨后春筍般涌現,盛況空前。

Many of our projects at 非死book, like React, depend on code in the npm registry. However, as we scaled internally, we faced problems with consistency when installing dependencies across different machines and users, the amount of time it took to pull dependencies in, and had some security concerns with the way the npm client executes code from some of those dependencies automatically. We attempted to build solutions around these issues, but they often raised new issues themselves.

非死book 的很多項目,比如 React,就依賴了 npm 倉庫中的代碼。但是,隨著內部規模的擴張,我們遇到了很多問題:不同機器或不同人所得到的安裝結果并不一致,安裝依賴所花費的時間也無法忽視;由于 npm 客戶端在安裝依賴包時會自動執行其中的腳本,安全性也令我們顧慮重重。我們不斷嘗試針對這些問題建立解決方案,但這些解決方案往往又不斷引發新的問題。

Attempts at scaling the npm client

關于理順 npm 客戶端的一系列嘗試

Initially, following the prescribed best practices, we only checked in package.json and asked engineers to manually run npm install . This worked well enough for engineers, but broke down in our continuous integration environments, which need to be sandboxed and cut off from the internet for security and reliability reasons.

最開始,我們遵循官方推薦的最佳實踐,只把 package.json 文件提交到代碼庫,然后要求工程師們手動運行 npm install 來安裝依賴。這種方法對工程師來說運作良好,但在我們的持續集成(CI)環境下就不靈了,因為 CI 環境需要運行在沙箱中,基于安全性和可靠性的考慮,它需要切斷與互聯網的連接。

The next solution we implemented was to check all of node_modules into the repository. While this worked, it made some simple operations quite difficult. For example, updating a minor version of babel generated an 800,000-line commit that was difficult to land and triggered lint rules for invalid utf8 byte sequences, windows line endings, non png-crushed images, and more. Merging changes to node_modules would often take engineers an entire day. Our source control team also pointed out that our checked-in node_modules folder was responsible for a tremendous amount of metadata. The React Native package.json currently lists just 68 dependencies, but after running npm install the node_modules directory contains 121,358 files.

后來我們改變了對策,把所有 node_modules 簽入代碼庫。這種方法也運行了一段時間,但它也讓一些原本簡單的操作變得困難起來。舉例來說,更新 Babel 的一個次版本號會產生一次 “80 萬行” 級別的提交動作,這種情況很難處理,而且會觸發一系列無意義的 lint 操作(諸如檢查 UTF-8 字節序列、Windows 換行符、未優化的 PNG 圖片等等)。把 node_modules 的變更合并進來往往要花費工程師一整天的時間。我們的版本控制團隊也指出我們提交的 node_modules 目錄直接導致元數據體積的飆升。比如 React Native 項目的 package.json 只列出了 68 個依賴,但在跑過了 npm install 之后, node_modules 目錄下會產生 121,358 個文件。

We made one final attempt to scale the npm client to work with the number of engineers at 非死book and the amount of code that we need to install. We decided to zip the entire node_modules folder and upload it to an internal CDN so that both engineers and our continuous integration systems could download and extract the files consistently. This enabled us to remove hundreds of thousands of files from source control, but made it so engineers needed internet access not just to pull new code, but also to build it.

為了讓 npm 的這一套工作流適應 非死book 的團隊人數和代碼量,我們動用了最后一招。我們決定把整個 node_modules 目錄打成一個壓縮包,上傳到專用的 CDN 上,這樣工程師和 CI 服務器都可以下載、解壓并得到完全一致的結果了。這個方案一上,我們就可以從版本控制系統中清掉成千上萬的文件了;但這同時也導致工程師不論是在拉取新代碼時,還是在編寫新代碼時,都需要保持網絡連接。

We also had to work around issues with npm's shrinkwrap feature, which we used to lock down dependency versions. Shrinkwrap files aren't generated by default and will fall out of sync if engineers forget to generate them, so we wrote a tool to verify that the contents of the shrinkwrap file matches what's in node_modules . These files are huge JSON blobs with unsorted keys, though, so changes to them would generate massive, difficult-to-review commits. To mitigate this, we needed to add an additional script to sort all the entries.

我們還不得不應付 npm 的 shrinkwrap 功能所帶來的問題,因為我們使用 shrinkwrap 來鎖定依賴版本。Shrinkwrap 文件并不是默認生成的,一旦工程師在提交代碼前忘記生成這個文件,則這個文件跟代碼就不同步了。為此我們還特意寫了一個工具,用來校驗 shrinkwrap 文件的內容跟 node_modules 的內容是否匹配。這個 shrinkwrap 文件是由一堆亂序字段所組成的巨型 JSON 數據,因此每次修改都會產生一次巨型的、無法 review 的提交。為了緩解這個問題,我們又需要寫一個額外的腳本來把所有的字段排好序。

Finally, updating a single dependency with npm also updates many unrelated ones based on semantic versioning rules. This makes every change much larger than anticipated, and having to do things like committing node_modules or uploading it to a CDN made the process less than ideal for engineers.

這還沒完呢。在 npm 中,更新一項單獨的依賴其實還會按照 “語義化版本”(semantic versioning)的規則更新一堆無關的依賴。這使得每次代碼變更都比預期的要多,而我們所能做的也就是上述這一系列的下策。

Building a new client

構建新的客戶端

Rather than continue building infrastructure around the npm client, we decided to try looking at the problem more holistically. What if instead we attempted to build a new client that addressed the core issues we were experiencing? Sebastian McKenzie in our London office started hacking on this idea and we quickly became excited about its potential.

痛定思痛,我們決定不再圍繞 npm 客戶端來構建基礎設施,而是從一個更高的高度來審視整件事情。如果我們針對當下的痛點來打造一款全新的客戶端會怎么樣?我們倫敦辦事處的 Sebastian McKenzie 同學開始推進這個想法,很快我們就發現這條道路充滿光明。

As we worked on this, we began speaking with engineers across the industry and found that they faced a similar set of problems and had attempted many of the same solutions, often focused on resolving a single issue at a time. It became obvious that by collaborating on the whole set of problems the community was facing, we could develop a solution that worked for everyone. With the help of engineers from Exponent, Google, and Tilde, we built out the Yarn client and tested and validated its performance on every major JS framework and for additional use cases outside of 非死book. Today, we're excited to share it with the community.

在推進這個計劃的同時,我們也開始跟業內的工程師們廣泛交談。我們發現大家遇到的問題其實都差不多,也都嘗試過差不多的解決方案,效果也差不多都是按下個葫蘆浮起個瓢。接下來的事情就變得水到渠成了——我們集合社區的力量來解決共通的問題,產出一個適用于每個人的解決方案。由此我們收到了來自 Exponent、Google 和 Tilde 公司的工程師的幫助,共同開發出了 Yarn 客戶端;為了確保它也適用于 非死book 之外的使用場景,我們還在所有主流的 JS 框架身上驗證了它的性能。今天,我們懷著激動的心情,將它推薦給整個社區。

Introducing Yarn

Yarn 介紹

Yarn is a new package manager that replaces the existing workflow for the npm client or other package managers while remaining compatible with the npm registry. It has the same feature set as existing workflows while operating faster, more securely, and more reliably.

Yarn 是一款新的包管理器,它將取代原有的基于 npm 客戶端(或其它包管理器)的工作流,但同時又保留了與 npm 倉庫的兼容性。它具備原有工作流的所有功能,但相比之下更加快速、安全、可靠。

The primary function of any package manager is to install some package — a piece of code that serves a particular purpose — from a global registry into an engineer's local environment. Each package may or may not depend on other packages. A typical project could have tens, hundreds, or even thousands of packages within its tree of dependencies.

所有包管理器的核心功能都是從一個通用倉庫中獲取包,然后安裝到開發者的本地環境中。所謂 “包”,就是一套解決特定任務的代碼。一個包可能依賴、也可能不依賴其它包。一個典型的項目可能會在它的依賴樹中涉及數十、數百甚至數千個包。

These dependencies are versioned and installed based on semantic versioning (semver). Semver defines a versioning scheme that reflects the types of changes in each new version, whether a change breaks an API, adds a new feature, or fixes a bug. However, semver relies on package developers not making mistakes — breaking changes or new bugs may find their way into installed dependencies if the dependencies are not locked down.

這些依賴包都是有版本的,它們按照 “語義化版本”(semver)的規則被安裝進來。Semver 定義了一套版本描述規范,用于表明每個版本的變更類型:是 API 行為出現了向后不兼容的破壞性變更、是增加了一個新功能、還是修復了一個 bug。但是,semver 是否奏效,取決于包的開發者是否遵守規則。在理想情況下,即使依賴包沒有鎖定版本,包的不同類型的變更版本都會在 semver 的約定下以不同的方式被正確地安裝進來。

Architecture

架構設計

In the Node ecosystem, dependencies get placed within a node_modules directory in your project. However, this file structure can differ from the actual dependency tree as duplicate dependencies are merged together. The npm client installs dependencies into the node_modules directory non-deterministically. This means that based on the order dependencies are installed, the structure of a node_modules directory could be different from one person to another. These differences can cause “works on my machine” bugs that take a long time to hunt down.

在 Node 的生態系統中,依賴會被安裝到你的項目中的 node_modules 目錄中。不過,其內部的文件結構和實際的依賴關系樹并不完全對應,因為安裝過程存在重復依賴的合并機制。npm 客戶端在把依賴安裝到 node_modules 目錄時存在不確定性。這種 “不確定性” 是指,由于安裝依賴的順序不同,你得到的 node_modules 目錄的內部結構可能跟別人不一樣。這種差異可能會導致 “我電腦上是好的” 之類的 bug,而這類 bug 往往是極難定位的。

Yarn resolves these issues around versioning and non-determinism by using lockfiles and an install algorithm that is deterministic and reliable. These lockfiles lock the installed dependencies to a specific version, and ensure that every install results in the exact same file structure in node_modules across all machines. The written lockfile uses a concise format with ordered keys to ensure that changes are minimal and review is simple.

Yarn 解決上述版本問題和不確性問題的方案是引入 lockfile(鎖定文件),并啟用了一套新的安裝算法,以此達到一致、可靠的結果。這個 lockfile 會把所有已安裝的依賴鎖定在一個固定的版本上,確保每次安裝所產生的 node_modules 目錄的文件結構在不同機器上總是一致的。這個 lockfile 采用一種簡明的格式來書寫,其字段是有序的,以確保每次更新都是最小化的、易于 reivew 的。

The install process is broken down into three steps:

整個安裝過程被分解為以下三個步驟:

  1. Resolution: Yarn starts resolving dependencies by making requests to the registry and recursively looking up each dependency.
  2. Fetching: Next, Yarn looks in a global cache directory to see if the package needed has already been downloaded. If it hasn't, Yarn fetches the tarball for the package and places it in the global cache so it can work offline and won't need to download dependencies more than once. Dependencies can also be placed in source control as tarballs for full offline installs.
  3. Linking: Finally, Yarn links everything together by copying all the files needed from the global cache into the local node_modules directory.
  1. 解析 :Yarn 首先開始解析依賴關系。它向包倉庫發出請求,并遞歸地查詢各層依賴。
  2. 獲取 :接下來,Yarn 會在一個全局的緩存目錄中查找當前所需的包是不是已經下載過了。如果還沒有,Yarn 會把這個包的 tarball 拉下來,并把它存放在全局緩存中,這樣它下次就可以離線安裝了,無需重復下載。依賴包也可以以 tarball 的形式存放到版本控制系統中,以實現完全的離線安裝。
  3. 鏈接 :最后,Yarn 會把所需的所有文件從緩存中復制到本地的 node_modules 目錄中,這樣所有東西就鏈接為一個整體了。

By breaking these steps down cleanly and having deterministic results, Yarn is able to parallelize operations, which maximizes resource utilization and makes the install process faster. On some 非死book projects, Yarn reduced the install process by an order of magnitude, from several minutes to just seconds. Yarn also uses a mutex to ensure that multiple running CLI instances don't collide and pollute each other.

由于我們把安裝過程清晰地拆解開來,消滅了安裝結果的不確定性,Yarn 天生具備并行操作的能力。這種并行能力可以最大化資源的利用率,提升安裝速度。在 非死book 的某些項目中,Yarn 可以帶來一個數量級的性能提升,安裝耗時從幾分鐘縮短到幾秒。Yarn 內建互斥特性,以確保同時運行多個 CLI 實例也不會相互沖突、相互污染。

Throughout this entire process, Yarn imposes strict guarantees around package installation. You have control over which lifecycle scripts are executed for which packages. Package checksums are also stored in the lockfile to ensure that you get the same package every single time.

在整個安裝過程中,Yarn 還提供了嚴格的安全保障。你可以精確控制某個包的某個生命周期腳本是否運行。包的校驗信息(checksum)也會保存在 lockfile 中,確保你每次安裝得到的都是同一個包。

Features

其它特性

In addition to making installs much faster and more reliable, Yarn has additional features to further simplify the dependency management workflow.

除了讓包的安裝變得更加快速和可靠以外,Yarn 還提供了如下特性,進一步簡化了依賴管理的工作流。

  • Compatibility with both the npm and bower workflows and supports mixing registries.
  • Ability to restrict licenses of installed modules and a means for outputting license information.
  • Exposes a stable public JS API with logging abstracted for consumption via build tools.
  • Readable, minimal, pretty CLI output.
  • 同時兼容 npm 和 Bower 工作流,支持混用多種倉庫類型。
  • 可以限制依賴包的授權類型,并且可以輸出依賴包的授權信息。
  • 暴露一個穩定的 JS API,提供抽象化的日志信息以便與其它構建工具集成。
  • 提供可讀的、最小化的、美觀的 CLI 輸出信息。

Yarn in production

應用到生產環境

At 非死book we're already using Yarn in production, and it's been working really well for us. It powers the dependency and package management for many of our JavaScript projects. With each migration we've enabled engineers to build offline and helped speed up their workflow. You can see how install times for Yarn and npm compare on React Native under different conditions, which you can find here .

在 非死book,我們已經將 Yarn 用于生產環境了,而且它跑得也確實不錯。我們的很多 JavaScript 項目都是由它來完成依賴安裝和包管理的。每當一個項目完成遷移后,工程師們都會獲得離線工作的能力,進而加快工作流。,用來展示不同條件下 Yarn 和 npm 在安裝耗時方面的對比。

Getting started

如何上手

The easiest way to get started is to run:

最簡單的上手方式就是運行以下命令:

npm install -g yarn

yarn</code></pre>

The yarn CLI replaces npm in your development workflow, either with a matching command or a new, similar command:

新的 yarn CLI 將會在你的開發工作流中替代 npm 。在各種場景下,Yarn 要么提供了一個對等的命令,要么提供了一個功能相似的新命令:

  • npm install → yarn

    With no arguments, the yarn command will read your package.json , fetch packages from the npm registry, and populate your node_modules folder. It is equivalent to running npm install .

    在不加任何參數的情況下, yarn 命令將會讀取你的 package.json 文件,從 npm 倉庫拉取包,然后存放到你的 node_modules 目錄中。其效果等同于直接運行 npm install 。

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

    We removed the “invisible dependency” behavior of npm install <name> and split the command. Running yarn add <name> is equivalent to running npm install --save <name> .

    我們去掉了 npm install <name> 命令產生 “隱形依賴” 的行為,只保留了顯式安裝行為。運行 yarn add <name> 將等同于運行 npm install --save <name> 。

Future

未來

Many of us came together to build Yarn to solve common problems, and we knew that we wanted Yarn to be a true community project that everyone can use. Yarn is nowavailable on GitHub and we're ready for the Node community to do what it does best: Use Yarn, share ideas, write documentation, support each other, and help build a great community to care for it. We believe that Yarn is already off to a great start, and it can be even better with your help.

我們這一群人走到一起構建了 Yarn,目的在于解決社區共通的問題;我們的愿景也很明確,希望 Yarn 成為一個真正的社區項目,人人均可從中受益。Yarn 已經在 GitHub 開源,我們也已經準備好迎接來自 Node 社區的幫助:開始使用、交換想法、編寫文檔、互相扶持,共同建立一個強大的社區來推動它的發展。我們相信 Yarn 已經邁出了堅實的第一步,而且你的參與會讓它變得更好!

 

 

 

 

來自:https://github.com/cssmagic/blog/issues/67

 

 本文由用戶 咖啡兔 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!