<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Yarn</title>
    <description>Fast, reliable, and secure dependency management.
</description>
    <link>https://yarnpkg.com/</link>
    <atom:link href="https://yarnpkg.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 13 Sep 2017 17:32:02 +0000</pubDate>
    <lastBuildDate>Wed, 13 Sep 2017 17:32:02 +0000</lastBuildDate>
    <generator>Jekyll v3.2.1</generator>
    
      <item>
        <title>Yarn 1.0 is Here</title>
        <description>&lt;p&gt;After a long wait, &lt;a href=&quot;https://code.facebook.com/posts/274518539716230&quot;&gt;Yarn 1.0 is out&lt;/a&gt;!&lt;/p&gt;
</description>
        <pubDate>Thu, 07 Sep 2017 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/09/07/yarn-1-is-here/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/09/07/yarn-1-is-here/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Workspaces in Yarn</title>
        <description>&lt;p&gt;Projects tend to grow over time, and, occasionally, some pieces of a project can be useful elsewhere in other projects. For example, &lt;a href=&quot;http://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt;, being a generic testing tool, gave birth to many packages, one of them is &lt;a href=&quot;https://yarnpkg.com/en/package/jest-snapshot&quot;&gt;jest-snapshot&lt;/a&gt; that is now used in other projects like &lt;a href=&quot;https://yarnpkg.com/en/package/snapguidist&quot;&gt;snapguidist&lt;/a&gt; and &lt;a href=&quot;https://yarnpkg.com/en/package/chai-jest-snapshot&quot;&gt;chai-jest-snapshot&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;monorepos&quot;&gt;Monorepos&lt;/h2&gt;

&lt;p&gt;Those who have &lt;a href=&quot;https://youtu.be/PvabBs_utr8?t=16m24s&quot;&gt;tried splitting a project into multiple packages&lt;/a&gt; know how hard it is to make changes across multiple packages at one time. To make the process easier, some big projects adopted a &lt;a href=&quot;http://www.drmaciver.com/2016/10/why-you-should-use-a-single-repository-for-all-your-companys-projects/&quot;&gt;monorepo&lt;/a&gt; approach, or multi-package repositories, which reduces the burden of writing code across packages.&lt;/p&gt;

&lt;p&gt;Several projects used every day by JavaScript developers are managed as monorepos: &lt;a href=&quot;https://github.com/babel/babel/tree/7.0/packages&quot;&gt;Babel&lt;/a&gt;, &lt;a href=&quot;https://github.com/facebook/react/tree/master/packages&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://github.com/facebook/jest/tree/master/packages&quot;&gt;Jest&lt;/a&gt;, &lt;a href=&quot;https://github.com/vuejs/vue/tree/dev/packages&quot;&gt;Vue&lt;/a&gt;, &lt;a href=&quot;https://github.com/angular/angular/tree/master/packages&quot;&gt;Angular&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, separating pieces of projects into their own folders is sometimes not enough. Testing, managing dependencies, and publishing multiple packages quickly gets complicated and many such projects &lt;a href=&quot;https://medium.com/@bebraw/the-case-for-monorepos-907c1361708a&quot;&gt;adopt&lt;/a&gt; tools such as &lt;a href=&quot;https://lernajs.io/&quot;&gt;Lerna&lt;/a&gt; to make working with monorepos easier.&lt;/p&gt;

&lt;h2 id=&quot;lerna&quot;&gt;Lerna&lt;/h2&gt;

&lt;p&gt;Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm. Internally it uses &lt;a href=&quot;https://code.facebook.com/posts/1840075619545360&quot;&gt;Yarn&lt;/a&gt; or the npm CLI to bootstrap (i.e. install all third party dependencies for each package) a project. In a nutshell, Lerna calls &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn/npm install&lt;/code&gt; for each package inside the project and then creates symlinks between the packages that refer each other.&lt;/p&gt;

&lt;p&gt;Being a wrapper of a package manager, Lerna can’t manipulate the contents of node_modules efficiently:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Lerna calls &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt; multiple times for each package which creates overhead because each &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; is considered independent and they can’t share dependencies with each other. This causes a lot of duplication for each node_modules folder which quite often use the same third-party packages.&lt;/li&gt;
  &lt;li&gt;Lerna manually creates links between packages that refer each other after installation has finished. This introduces inconsistency inside node_modules that a package manager may not be aware of, so running &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt; from within a package may break the meta structure that Lerna manages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Issues such as these convinced us, as package manager developers, that we should support multi-package repositories directly in Yarn. &lt;strong&gt;Starting with &lt;a href=&quot;https://yarnpkg.com/en/docs/install&quot;&gt;Yarn 0.28,&lt;/a&gt; we’re excited to share that we support such repositories under the Workspaces feature&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introducing-yarn-workspaces&quot;&gt;Introducing Yarn Workspaces&lt;/h2&gt;

&lt;p&gt;Yarn Workspaces is a feature that allows users to install dependencies from multiple package.json files in subfolders of a single root package.json file, all in one go.&lt;/p&gt;

&lt;p&gt;Making Workspaces native to Yarn enables faster, lighter installation by preventing package duplication across Workspaces. Yarn can also create symlinks between  Workspaces that depend on each other, and  will ensure the  consistency and correctness of all directories.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-workspaces&quot;&gt;Setting up Workspaces&lt;/h2&gt;

&lt;p&gt;To get started, users must enable Workspaces in Yarn by running the following command:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;yarn config set workspaces-experimental true
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;It will add &lt;code class=&quot;highlighter-rouge&quot;&gt;workspaces-experimental true&lt;/code&gt; to the &lt;code class=&quot;highlighter-rouge&quot;&gt;.yarnrc&lt;/code&gt; file in your OS home folder. Yarn Workspaces is still considered experimental while we gather feedback from the community.&lt;/p&gt;

&lt;p&gt;Let’s take &lt;a href=&quot;http://facebook.github.io/jest/&quot;&gt;Jest&lt;/a&gt; as an example and set Yarn Workspaces up for that structure. As a matter of fact, it has already been &lt;a href=&quot;https://github.com/facebook/jest/pull/3906&quot;&gt;done in a PR&lt;/a&gt;, and Jest has been using Yarn to bootstrap its packages for a while.&lt;/p&gt;

&lt;p&gt;Jest’s project structure is typical for an Open Source JavaScript monorepo.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;| jest/
| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ package.json
| -------- jest-diff/
| ------------ package.json
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The top-level &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; defines the root of the project, and folders with other package.json files are the Workspaces.
Workspaces usually are published to a registry like npm.
While the root is not supposed to be consumed as a package, it usually contains the glue code or business specific code that is not useful for sharing with other projects, that is why we mark it as “private”.&lt;/p&gt;

&lt;p&gt;The following example is a simplified root &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; that enables Workspaces for the project and defines third-party packages needed for the project build and test environment.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;chalk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^2.0.1&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;workspaces&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;packages/*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To keep things simple I’ll describe two small Workspaces packages:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;jest-matcher-utils Workspace:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jest-matcher-utils&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;description&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;20.0.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;browser&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;chalk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;pretty-format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^20.0.3&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;jest-diff Workspace that depends on jest-matcher-utils:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;jest-diff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;20.0.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;browser&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;chalk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;diff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^3.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;jest-matcher-utils&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^20.0.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;pretty-format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^20.0.3&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;A wrapper like Lerna would first run  &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt; for each &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; separately and then run &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn link&lt;/code&gt; for packages that depend on each other.&lt;/p&gt;

&lt;p&gt;If we used that approach, we would get a folder structure like the following:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;| jest/
| ---- node_modules/
| -------- chalk/
| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ node_modules/
| ---------------- chalk/
| ---------------- pretty-format/
| ------------ package.json
| -------- jest-diff/
| ------------ node_modules/
| ---------------- chalk/
| ---------------- diff/
| ---------------- jest-matcher-utils/  (symlink) -&amp;gt; ../jest-matcher-utils
| ---------------- pretty-format/
| ------------ package.json
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;As you see, there is a redundancy of third-party dependencies.&lt;/p&gt;

&lt;p&gt;With Workspaces enabled, Yarn can produce a much more optimized dependency structure and when you run the usual &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt; anywhere in the project you’ll get the following node_modules.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;| jest/
| ---- node_modules/
| -------- chalk/
| -------- diff/
| -------- pretty-format/
| -------- jest-matcher-utils/  (symlink) -&amp;gt; ../packages/jest-matcher-utils
| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ node_modules/
| ---------------- chalk/
| ------------ package.json
| -------- jest-diff/
| ------------ node_modules/
| ---------------- chalk/
| ------------ package.json
...
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Packages like &lt;code class=&quot;highlighter-rouge&quot;&gt;diff&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;pretty-format&lt;/code&gt; and the symlink to &lt;code class=&quot;highlighter-rouge&quot;&gt;jest-matcher-utils&lt;/code&gt; were hoisted to the root node_modules directory, making the installation faster and smaller. The package &lt;code class=&quot;highlighter-rouge&quot;&gt;chalk&lt;/code&gt; however could not be moved to the root  because the root already depends on a different, incompatible version of &lt;code class=&quot;highlighter-rouge&quot;&gt;chalk&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both of the structures above are compatible, but the latter is more optimal while still being correct regarding the Node.js module resolution logic.&lt;/p&gt;

&lt;p&gt;For avid Lerna users this is similar to bootstrapping code via the &lt;code class=&quot;highlighter-rouge&quot;&gt;--hoist&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;If you run code inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;jest-diff&lt;/code&gt; Workspace, it will be able to resolve all its dependencies:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;require(‘chalk’) resolves to &lt;code class=&quot;highlighter-rouge&quot;&gt;./node_modules/chalk&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;require(‘diff’) resolves to &lt;code class=&quot;highlighter-rouge&quot;&gt;../../node_modules/diff&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;require(‘pretty-format’) resolves to &lt;code class=&quot;highlighter-rouge&quot;&gt;../../node_modules/pretty-format&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;require(‘jest-matcher-utils’) resolves to &lt;code class=&quot;highlighter-rouge&quot;&gt;../../node_modules/jest-matcher-utils&lt;/code&gt;  that is a symlink to &lt;code class=&quot;highlighter-rouge&quot;&gt;../packages/jest-matcher-utils&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;managing-dependencies-of-workspaces&quot;&gt;Managing dependencies of Workspaces&lt;/h2&gt;

&lt;p&gt;If you want to modify a dependency of a Workspace, just  run the appropriate command inside the Workspace folder:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;$ cd packages/jest-matcher-utils/
$ yarn add left-pad
✨ Done in 1.77s.
$ git status
modified: package.json
modified: ../../yarn.lock
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Note that Workspaces don’t have their own yarn.lock files, and the root yarn.lock contains all the dependencies for all the Workspaces. 
When you want to change a dependency inside a Workspace, the root yarn.lock will be changed as well as the Workspace’s package.json.&lt;/p&gt;

&lt;h2 id=&quot;integrating-with-lerna&quot;&gt;Integrating with Lerna&lt;/h2&gt;

&lt;p&gt;Do Yarn Workspaces make Lerna obsolete?&lt;/p&gt;

&lt;p&gt;Not at all. Yarn Workspaces are easily integrated with Lerna.&lt;/p&gt;

&lt;p&gt;Lerna provides a lot more than just bootstrapping a project and it has a community of users around it that have fine-tuned Lerna for their needs.&lt;/p&gt;

&lt;p&gt;Starting with Lerna 2.0.0, when you pass the flag &lt;a href=&quot;https://github.com/lerna/lerna#--use-workspaces&quot;&gt;–use-workspaces&lt;/a&gt; when running Lerna commands, it will use Yarn to bootstrap the project and also it will use &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json/workspaces&lt;/code&gt; field to find the packages instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;lerna.json/packages&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is how Lerna is configured for Jest:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;npmClient&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yarn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;useWorkspaces&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Jest relies on Yarn to bootstrap the project, and on Lerna for running the publish command(s).&lt;/p&gt;

&lt;h2 id=&quot;what-is-next&quot;&gt;What is next?&lt;/h2&gt;

&lt;p&gt;Yarn Workspaces is the first step of what a package manager could do for managing monorepos as they become a more common solution to code sharing.&lt;/p&gt;

&lt;p&gt;At the same time we don’t want to put all the possible monorepo features into Yarn. We want to keep Yarn focused and lean, and this means that Yarn and projects like Lerna will continue working together.&lt;/p&gt;

&lt;p&gt;Our next goal is to finalize Yarn 1.0, which is meant to summarize the work we have done on Yarn over the past year, and recognizing how reliable Yarn has become. We’ll also share our thoughts on what we’d like to build next for Yarn then.&lt;/p&gt;

&lt;p&gt;Stay tuned.&lt;/p&gt;

</description>
        <pubDate>Wed, 02 Aug 2017 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/08/02/introducing-workspaces/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Let's Dev: A Package Manager</title>
        <description>&lt;p&gt;Hello everyone! Today, we’re gonna write a new package manager, even better than Yarn! Ok, maybe not, but at least we’re gonna have some fun, learn how package managers work, and think about what could come next on Yarn.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;The devil is in the details&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;This article omits small details and environment quirks, and focuses on the high-level architecture of a package manager, in an effort to stay succinct. For example, we’re gonna assume that all paths are regular POSIX paths.&lt;/p&gt;

  &lt;p&gt;That being said, there’s much to say about these compatibility layers, and maybe talking about them could be an interesting follow up! Feel free to tweet at &lt;a href=&quot;https://twitter.com/yarnpkg&quot;&gt;@yarnpkg&lt;/a&gt; if you’re interested to know more about them! 😃&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To fully understand how things work, we’re gonna go step by step, incrementally, adding or extending a single function at a time. We’ll treat each of those steps as a separate chapter, and you will find an index of all chapters below this paragraph. Don’t worry - they’re all relatively short! Note that ES2017 features will be used all through the article - if you’re unfamiliar with them, we recommend you to take a look at the great books &lt;a href=&quot;http://exploringjs.com/es6/&quot;&gt;Explore ES6&lt;/a&gt; and/or &lt;a href=&quot;https://leanpub.com/understandinges6/read&quot;&gt;Understanding ECMAScript 6&lt;/a&gt;, and &lt;a href=&quot;http://exploringjs.com/es2016-es2017/&quot;&gt;Explore ES2017&lt;/a&gt;. Good lecture!&lt;/p&gt;

&lt;hr /&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-1---bravely-download&quot;&gt;#&lt;/a&gt; Chapter 1 - Bravely Download&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we download package tarballs&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-2---one-reference-to-rule-them-all&quot;&gt;#&lt;/a&gt; Chapter 2 - One Reference to Rule Them All&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we resolve package ranges&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-3---dependencies-of-our-dependencies-are-our-dependencies&quot;&gt;#&lt;/a&gt; Chapter 3 - Dependencies of Our Dependencies Are Our Dependencies&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we extract dependencies from packages&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-4---super-dependency-world&quot;&gt;#&lt;/a&gt; Chapter 4 - Super Dependency World&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we do the same thing, but recursively&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-5---links-awakening&quot;&gt;#&lt;/a&gt; Chapter 5 - Links Awakening&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we install our dependencies on the filesystem&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#chapter-6---lord-of-the-optimization&quot;&gt;#&lt;/a&gt; Chapter 6 - Lord of the Optimization&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we try not to install the whole world on our system&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;&lt;a href=&quot;#conclusion---there-really-was-a-cakehttpsgithubcomyarnpkglets-dev-demo&quot;&gt;#&lt;/a&gt; Conclusion - There Really Was a &lt;a href=&quot;https://github.com/yarnpkg/lets-dev-demo&quot;&gt;Cake&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

    &lt;p&gt;&lt;em&gt;Or: where we reflect on what we’ve learned&lt;/em&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-1---bravely-download&quot;&gt;Chapter 1 - Bravely Download&lt;/h2&gt;

&lt;p&gt;So, where should we start? First we have to think about what a package manager is. Let’s forget the caches, the mirrors, the lockfiles, and all of the fancy command-line stuff, and let’s focus on the very core: a package manager is a download manager. You ask it to download a package, and it happily executes. That’s how we’ll begin our adventure: with a very basic function that simply downloads something from the internet.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'node-fetch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Couldn&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${reference}&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Nice job! We just have to give this function a URL, and we’ll eventually get the referenced package back! Of course, it only works if you know the exact URL for your package, but it’s a good start. Rome wasn’t built in one day, and our package manager won’t be built with a single function either.&lt;/p&gt;

&lt;p&gt;Ok, what’s next? Let’s take a break and look at a classic package.json file to see what we could implement.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;react&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;^15.5.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;babel-core&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;6.25.0&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Oh, right, version ranges! It would be nice if we were able to just pass a version number to our fetcher, and let it convert it to an URL, right? Then let’s do this! To make it easier, we’ll only add support for pinned references (ie. &lt;code class=&quot;highlighter-rouge&quot;&gt;1.0.0&lt;/code&gt; will be supported, but not &lt;code class=&quot;highlighter-rouge&quot;&gt;^1.0.0&lt;/code&gt;). Finding the right regexp could be tedious, but thankfully we can rely on the excellent &lt;a href=&quot;https://github.com/npm/node-semver&quot;&gt;semver&lt;/a&gt; module, which will handle the bulk of the work for us! That being said, we’ll still need to make a small change to the signature of our &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchPackage&lt;/code&gt; function. Instead of using a string to describe a package, we’ll now use a &lt;code class=&quot;highlighter-rouge&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;name,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt; object, where the name is the package name and the reference is the identifier that allows us to unequivocally locate this package. Thanks to this change, we can now write:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'semver'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;valid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//registry.yarnpkg.com/${name}/-/${name}-${reference}.tgz`});&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ... same code as before&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;What do you think? If we detect that the reference is a semver version, then we convert it to an actual URL located on the Yarn registry. That’s a nice download manager we have here, right? Ok, let’s add a quick support for filesystem paths before we call it a day:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'fs-extra'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// In a pure JS fashion, if it looks like a path, it must be a path.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;startsWith&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ... same code as before&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;What do you think? Pretty simple, right?&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-2---one-reference-to-rule-them-all&quot;&gt;Chapter 2 - One Reference to Rule Them All&lt;/h2&gt;

&lt;p&gt;Our &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchPackage&lt;/code&gt; function is great, but it has one shortcoming, and a big one: As we said, our function can currently only serve pinned references. Ranges such as &lt;code class=&quot;highlighter-rouge&quot;&gt;^1.0.0&lt;/code&gt; cannot be served, because they can potentially refer to multiple different versions, each of them having their own tarballs. So, in order to serve them, we’ll need to find a way to extract a unique pinned reference from those ranges. Fortunately, it’s not that hard! See for yourself:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'semver'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPinnedReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// 1.0.0 is a valid range per semver syntax, but since it's also a pinned&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// reference, we don't actually need to process it. Less work, yeay!~&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;valid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//registry.yarnpkg.com/${name}`);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;versions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;versions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;maxSatisfying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;maxSatisfying&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;versions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;maxSatisfying&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Couldn&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;matching&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${reference}&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${name}&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;maxSatisfying&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// getPinnedReference({name: &quot;react&quot;, reference: &quot;~15.3.0&quot;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//     → {name: &quot;react&quot;, reference: &quot;15.3.2&quot;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// getPinnedReference({name: &quot;react&quot;, reference: &quot;15.3.0&quot;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//     → {name: &quot;react&quot;, reference: &quot;15.3.0&quot;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// getPinnedReference({name: &quot;react&quot;, reference: &quot;/tmp/react-15.3.2.tar.gz&quot;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//     → {name: &quot;react&quot;, reference: &quot;/tmp/react-15.3.2.tar.gz&quot;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And … that’s it! If we see a semver range, we just have to query the NPM registry to retrieve the list of all available versions. Once we’ve obtained it, it’s just a matter of selecting the best one (which is made easy thanks to the &lt;code class=&quot;highlighter-rouge&quot;&gt;maxSatisfying&lt;/code&gt; function provided by the semver module), and we’re all set.&lt;/p&gt;

&lt;p&gt;Note that we don’t need to do anything particular with semver versions, direct URLs, nor filesystem paths, since they’ll always refer to a single package at any given time. So when we encounter them, we can just return them back without doing anything fancy.&lt;/p&gt;

&lt;p&gt;Thanks to this function, we can now rest assured that the references we’ll send to our &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchPackage&lt;/code&gt; function will always be pinned references! Another day, another great victory for us.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-3---dependencies-of-our-dependencies-are-our-dependencies&quot;&gt;Chapter 3 - Dependencies of Our Dependencies Are Our Dependencies&lt;/h2&gt;

&lt;p&gt;In Chapter 1 we saw how to make a magic function that would download any package from anywhere, and return it. In Chapter 2, we saw how to convert volatile dependencies into pinned dependencies. That’s a great start! But now we’ll need to resolve a bigger issue: dependencies. See, the Node ecosystem being what it is, most packages rely on other packages in order to work properly. Fortunately, they all agreed on using a single standard to list those dependencies (remember the &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file we’ve seen above), and so we should be able to make good use of this. Let’s write our function. Given a package, we want it to return the dependencies this package relies on.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Can’t escape the tooling&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Even if this article tries to stay focused on the core principle of package managers, we will need some utility function from time to time. When you encounter a symbol imported from &lt;code class=&quot;highlighter-rouge&quot;&gt;./utilities&lt;/code&gt;, just don’t bother understanding how it works under the hood. It’s usually some boring and verbose code. That being said, all sources are available in the repository linked at the end of this post, including the utilities, so if you’re really interested, give it a look later!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This function reads a file stored within an archive&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readPackageJsonFromArchive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./utilities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;readPackageJsonFromArchive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Some packages have no dependency field&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// It's much easier for us to just keep using the same {name, reference}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// data structure across all of our code, so we convert it there.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// getPackageDependencies({name: &quot;react&quot;, reference: &quot;15.6.1&quot;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//     → [{name: &quot;create-react-class&quot;, reference: &quot;^15.6.0&quot;},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//        {name: &quot;prop-types&quot;, reference: &quot;^15.5.10&quot;}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;What do you think? We’ve even been able to use our very own &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchPackage&lt;/code&gt; implementation to get the archive from where we extract the package information! From now on, whatever package people send us, we’ll be able to know what other packages it depends on. That’s a good start, but we’ll now have to expand this ability a bit further: instead of resolving the first level of dependencies only, we’ll want to resolve &lt;em&gt;everything&lt;/em&gt;. And that’s what the next chapter is about!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-4---super-dependency-world&quot;&gt;Chapter 4 - Super Dependency World&lt;/h2&gt;

&lt;p&gt;Time we go full recursion. See, the idea is that before being able to install your packages into your &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder, we’ll first have to “install” them in memory. Why, you say? Well, proceeding this way will allow us to manipulate the tree before actually persisting it on the filesystem. Whether it’s deduplication or hoisting, everything will have to be applied on this tree rather than on the actual disk (which would be really slow otherwise). But we’ll cover that in another chapter! Right now, let’s focus on extracting a complete dependency tree from a single root dependency. Since we’ve already written all the needed pieces (first the function to convert a volatile reference to a pinned reference, then the function to obtain a package dependencies), it will be quick. Let’s get down to it:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPinnedReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}))};&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This one might look hard to digest, but bear with me! We start from a single package with its list of dependencies. Then, for each one of those dependencies, we first resolve the dependency’s reference to become a pinned reference, then fetch its own dependencies, and then repeat the cycle on those sub-dependencies. In the end, we’ll have a tree structure, where each package will be a node that contains its own dependencies!&lt;/p&gt;

&lt;p&gt;In order to use this function, we just have to read the initial dependencies from the &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file located in the local working directory - everything inside is there for us to use!&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'path'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;util&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'util'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// We'll use the first command line argument (argv[2]) as working directory,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// but if there's none we'll just use the directory from which we've executed&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// the script&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Remember that because we use a different format for our dependencies than&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// a simple dictionary, we also need to convert it when reading this file&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;depth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;Infinity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now, let’s test this code. Try running it inside a directory that contains the following &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my-awesome-package&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;tar-stream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;If everything goes According To Plan, here’s what you should obtain (or similar, depending on whether a package has been upgraded since the time this article has been written):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Undefined Reference&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;You might notice a weird reference on the following snippet: &lt;code class=&quot;highlighter-rouge&quot;&gt;undefined&lt;/code&gt;. It’s actually expected! This reference is used on the root package in order to inform the linker (more on that later) that this package is a bit special. In a real-life situation, we would probably want to use a special type of reference (for example &lt;code class=&quot;highlighter-rouge&quot;&gt;root:///path/to/package&lt;/code&gt;), but in our case it’s not necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;my-awesome-package&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'tar-stream'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.5.4'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bl'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.2.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'readable-stream'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2.2.11'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'core-util-is'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'inherits'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2.0.3'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'isarray'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'process-nextick-args'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.7'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'safe-buffer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'string_decoder'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                      &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'safe-buffer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'util-deprecate'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'end-of-stream'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.4.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'once'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.4.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'wrappy'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'readable-stream'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2.2.11'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'core-util-is'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'inherits'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2.0.3'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'isarray'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'process-nextick-args'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.7'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'safe-buffer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'string_decoder'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'safe-buffer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
               &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'util-deprecate'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.0.2'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'xtend'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'4.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Perfect. Now, let’s try to run it with larger packages. Let’s try with babel-core! Use the following &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file :&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;babel-core&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Don’t worry, I’ll wait.&lt;/p&gt;

&lt;p&gt;…
Still waiting.&lt;/p&gt;

&lt;p&gt;…
Still… wait, is this script still running? That’s not good, right?&lt;/p&gt;

&lt;p&gt;At this point we can safely assume that there’s something wrong in our code - Babel is not that large, and the execution should have stopped a long time ago. In order to better understand what happened, open the &lt;a href=&quot;https://yarnpkg.com/en/package/babel-core&quot;&gt;babel-core&lt;/a&gt; page on Yarnpkg, and check its dependencies. You should see babel-register. Good. Now, open the &lt;a href=&quot;https://yarnpkg.com/en/package/babel-runtime&quot;&gt;babel-register&lt;/a&gt; page on Yarnpkg, and check its own dependencies. You should see… Yup. Babel-core. Now can you guess what happened? Because of the circular dependency, we’ve been iterating over babel-core, then babel-register, then babel-core, then… etc. Eventually, our code will end up using too much RAM and will get killed by the OS. That’s really not good.&lt;/p&gt;

&lt;p&gt;Fortunately, the fix is fairly easy! Remember that in Node, &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; directories can be nested. If a package can’t be located inside the current directory &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, Node will try looking for it inside the parent directory &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, then its grandparent &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, etc, until it finds a satisfying match. Let’s take advantage of that:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Look, we've added an extra optional parameter! ---------------------------------v&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;available&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;availableReference&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// If the volatile reference exactly matches the available reference (for&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// example in the case of two URLs, or two file paths), it means that it&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// is already satisfied by the package provided by its parent. In such a&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// case, we can safely ignore this dependency!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;availableReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// If the volatile dependency is a semver range, and if the package&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// provided by its parent satisfies it, we can also safely ignore the&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// dependency.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validRange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;satisfies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;availableReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPinnedReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;volatileDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subAvailable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;available&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;subAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;pinnedDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subAvailable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}))};&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This change adds a filtering pass to our dependencies processing: if any of them happens to be already satisfied by a package made available somewhere in the upstream dependency chain, then we can just skip it, since there isn’t any point in resolving it. Otherwise, we continue as usual, except that we insert them into the registry that contains our dependency chain packages. This way, our own dependencies will be able to skip installing us later on.&lt;/p&gt;

&lt;p&gt;If we go back to our babel-core example, it will go like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;- seeing babel-core@*

  - is it available in a parent module? NO
  - resolve it to babel-core@6.25.0
  - resolve its dependencies

    - seeing babel-register@^6.24.1
    - is it available in a parent module? NO
    - resolve it to babel-register@6.24.1
    - resolve its dependencies

      - seeing babel-core@^6.24.1
      - is it available in a parent module? YES, BECAUSE 6.25.0 MATCHES ^6.24.1
      - skip resolution
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Awesome. We now have a working algorithm to compute our full dependency tree. We’re almost done, just two more mandatory steps before we reach the fun and optional parts!&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-5---links-awakening&quot;&gt;Chapter 5 - Links Awakening&lt;/h2&gt;

&lt;p&gt;In Chapter 4, we saw how to obtain a complete tree of all of our dependencies. Now, we just have to download their tarballs somewhere, and extract them on the disk. The first part being made trivial by this awesome &lt;code class=&quot;highlighter-rouge&quot;&gt;fetchPackage&lt;/code&gt; function we’ve conveniently written not so long ago, our linker will only be a matter of a few lines:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This function extracts an archive somewhere on the disk&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extractNpmArchiveTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'./utilities'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;linkPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencyTree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getPackageDependencyTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// As we previously seen, the root package will be the only one containing&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// no reference. We can simply skip its linking, since by definition it already&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// contains the entirety of its own code :)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;packageBuffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fetchPackage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;extractNpmArchiveTo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;packageBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;linkPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/node_modules/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And that’s about it. This code will traverse your tree, unpack each package inside its designated directory (check the repository at the end of the article for the &lt;code class=&quot;highlighter-rouge&quot;&gt;extractArchiveTo&lt;/code&gt; implementation if you care about it), then iterate over its children and do the same for each of them. Seems good enough, but I feel like we might be forgetting something… oh right! The binaries! See, NPM’s &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; files offers a way for packages to expose utilities to the public (more details &lt;a href=&quot;https://docs.npmjs.com/files/package.json#bin&quot;&gt;here&lt;/a&gt;). We’ll need to add a few extra lines to support this use case:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'fs-extra'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'path'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;linkPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ... same code as before, except for the end:&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/node_modules/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;binTarget&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/node_modules/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;linkPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencyPackageJson&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/package.json`&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;
&lt;/span&gt;        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencyPackageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{};&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;binName&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

            &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binTarget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/${binName}`&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;;
&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mkdirp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/node_modules/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;symlink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;relative&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;binTarget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Good. But still, I can shake this feeling that… scripts! We’re missing install scripts! Packages can specify commands that should run after a package has been installed (for example, they might want to compile or transpile some code depending on your environment). We don’t execute them yet, but that should be fairly easy:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'child_process'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;util&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'util'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promisify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;linkPackages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// ... same code as before except the end:&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// ... same code as before&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencyPackageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scripts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;scriptName&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;preinstall&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;postinstall&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

                &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencyPackageJson&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scripts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;scriptName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

                &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/node_modules/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;})});&lt;/span&gt;

            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;All your environments are belong to it&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Note that we’ve only set the &lt;code class=&quot;highlighter-rouge&quot;&gt;PATH&lt;/code&gt; environment variable inside this snippet, but packages usually have access to a whole lot of extra environment variables (more details &lt;a href=&quot;https://docs.npmjs.com/misc/scripts#environment&quot;&gt;here&lt;/a&gt;). They are rarely used, but if you plan to write a package manager then you’ll have to make sure that you actually define them one way or the other.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, calling our linker function will install everything we need on the filesystem! Better yet, all build scripts will be run correctly, meaning you will end up with a working &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; directory! Good job! Our next chapter will be about performances, things will now start to get really interesting.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;chapter-6---lord-of-the-optimization&quot;&gt;Chapter 6 - Lord of the Optimization&lt;/h2&gt;

&lt;p&gt;Our package manager is working! However, you may notice something … Because we’re not taking advantage of Node’s resolution algorithm, and because we don’t try to remove duplicates from our package tree, we might end up with a really huge &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder! You might think that it’s not that much of a problem, but it has proven to &lt;a href=&quot;https://scottaddie.com/2015/08/16/npm-vs-windows-max_path-limitation/&quot;&gt;cause issues in the past&lt;/a&gt;. For example, on most Windows installations, paths have a hard limit of 260 characters. For packages that are deeply nested, this limit is often exceeded and it breaks things. Fortunately, Node’s resolution algorithm help us by allowing us to move the dependencies lower in the tree, as long as there is no conflicts.&lt;/p&gt;

&lt;p&gt;So let’s go! Our job in this chapter will be to decrease the number of packages that get installed on the filesystem, by any means necessary. However, we will also do the best we can to keep our algorithm both simple and encapsulated, so that it can be easily understood by maintainers and contributors alike, and can be switched or disabled in a single line if we need to.&lt;/p&gt;

&lt;p&gt;Here’s a possible implementation. It’s not perfect, but it’s a good start! Don’t be scared by its length, most of this is just comments:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;optimizePackageTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// This is a Divide &amp;amp; Conquer algorithm - we split the large problem into&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// subproblems that we solve on their own, then we combine their results&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// to find the final solution.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// In this particular case, we will say that our optimized tree is the result&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// of optimizing a single depth of already-optimized dependencies (ie we first&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// optimize each one of our dependencies independently, then we aggregate their&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// results and optimize them all a last time).&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;optimizePackageTree&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Now that our dependencies have been optimized, we can start working on&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// doing the second pass to combine their results together. We'll iterate on&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// each one of those &quot;hard&quot; dependencies (called as such because they are&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// strictly required by the package itself rather than one of its dependencies),&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// and check if they contain any sub-dependency that we could &quot;adopt&quot; as our own.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hardDependency&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependency&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;hardDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// First we look for a dependency we own that is called&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// just like the sub-dependency we're iterating on.&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;availableDependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// If there's none, great! It means that there won't be any collision&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// if we decide to adopt this one, so we can just go ahead.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;availableDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

            &lt;span class=&quot;c1&quot;&gt;// If we've adopted the sub-dependency, or if the already existing&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// dependency has the exact same reference than the sub-dependency,&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// then it becames useless and we can simply delete it.&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;availableDependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;availableDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;hardDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;splice&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hardDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;subDependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}));&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;reference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dependencies&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;And that’s it. We’ll just have to call this function after resolving and before linking, and we’ll get a much simpler tree that will still produce a valid output according to Node’s resolution algorithm!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;The devil really was in the details&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;As we saw in the introduction of this article, a large amount of what makes package managers complex software lies in the details. Our optimizer code suffers from this: despite it working in many cases, it actually has an unfortunate bug related to how binaries are linked. With the code shown above, package binaries will not be installed where they should, because when optimizing we lost the information that would allow the linker to correctly link each binary to the right location. Because of this, they will not be found when running the &lt;code class=&quot;highlighter-rouge&quot;&gt;build&lt;/code&gt; scripts. Oops!&lt;/p&gt;

  &lt;p&gt;Solving this would require adding some fields into our resolution tree nodes that we would then use to track the nodes original locations in the tree. The linker would then be able to link the binaries directly inside its children in a post-processing pass. Unfortunately, it would also make the code much less clear, so we opted not to implement this here. Such is the tough life of package manager writers…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;conclusion---there-really-was-a-cakehttpsgithubcomyarnpkglets-dev-demo&quot;&gt;Conclusion - There Really Was a &lt;a href=&quot;https://github.com/yarnpkg/lets-dev-demo&quot;&gt;Cake&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Finally! After all this time, we have our tiny package manager! You can even see its full code on &lt;a href=&quot;https://github.com/yarnpkg/lets-dev-demo&quot;&gt;this repository&lt;/a&gt; - you can try it, it really works! It is admittedly pretty basic, kind of slow, and without much features, but we love it nevertheless and that’s all that matters. And because it’s young, there is still room for a lot of evolutions and improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;We could implement a powerful CLI that would be similar to Yarn! With progress bars, and emojis, and all those fancy things! In fact, the demo already has progress bars, so that’s a good start!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We could split our functions into modules! Our package manager would then be a simple CLI, and our fetchers / resolvers / linkers would be loaded from a configuration file. Want to link everything using symlinks or hardlinks instead of copying files? Just use another linker than the default one! Want to add support for extra fetchers? Add them to your config files and be done with it! In fact, we even &lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3501&quot;&gt;started experimenting with something similar in Yarn&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We could also improve our optimizer so that it would actually work in every case! ;) And assuming a plugin architecture like the one we talked about in the previous bullet point, we could even implement different optimization strategies — from the &lt;code class=&quot;highlighter-rouge&quot;&gt;[--flat](https://yarnpkg.com/lang/en/docs/cli/install/#toc-yarn-install-flat)&lt;/code&gt; option to ensure that we wouldn’t use multiple versions of any single package, up to the more esoteric ones that would use more complex algorithms, such as &lt;a href=&quot;https://github.com/yarnpkg/yarn/issues/422&quot;&gt;SAT solvers&lt;/a&gt; — and all the while without any risk of hurting the package manager core experience!&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We could persist our resolution tree to a file on the disk, which we would call &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt;, and each time we would need to process a package from within our &lt;code class=&quot;highlighter-rouge&quot;&gt;getPinnedReference&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;getPackageDependencies&lt;/code&gt; functions, we would instead extract that information from the file instead of over the network! (In case you’re wondering, that’s exactly how both Yarn’s &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; and NPM@5’s &lt;code class=&quot;highlighter-rouge&quot;&gt;package-lock.json&lt;/code&gt; files work)&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We could save the tarballs in some sort of a cache, so that we wouldn’t have to download them from the network multiple times. By doing this we could even install our packages offline, if our cache is sufficiently well furnished!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is only a short list, far from being exhaustive! Package managers can implement a wide range of features, and all of them can each be improved in a lot of different ways. As you can see, the future looks bright: who can tell what new features and improvements will come during the incoming years? No one can tell for sure, but what I &lt;em&gt;can&lt;/em&gt; tell you is to watch this blog for the next Yarn announcement!&lt;/p&gt;

&lt;hr /&gt;

&lt;blockquote&gt;
  &lt;p&gt;I hope you’ve enjoyed this article as much as I’ve taken pleasure in writing it! If you want to discuss it, whether it’s to correct some mistake or to just talk about package managers, ping me on Twitter via &lt;a href=&quot;https://twitter.com/arcanis&quot;&gt;@arcanis&lt;/a&gt;, or on Yarn’s &lt;a href=&quot;https://discord.gg/yarnpkg&quot;&gt;Discord&lt;/a&gt; server where the core team regularly lurks :)&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Tue, 11 Jul 2017 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/07/11/lets-dev-a-package-manager/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/07/11/lets-dev-a-package-manager/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Adding Command Line Aliases for Yarn</title>
        <description>&lt;p&gt;One of the core design philosophies of Yarn is to strive for simpleness; a lean CLI without redundant features. That’s why Yarn has resisted adding random built-in shorthands like &lt;code class=&quot;highlighter-rouge&quot;&gt;npm r&lt;/code&gt; or an aliases system like the one you can find in Git. We believe that the benefits they could possibly bring to the Yarn experience are not justified by the cost required to build and maintain such a full-fledged subsystem.&lt;/p&gt;

&lt;p&gt;We’ve also noticed, however, that it is among one of the most common feature requests we received from the community. People do use aliases for several reasons, for example, to replicate their experiences from the &lt;code class=&quot;highlighter-rouge&quot;&gt;npm&lt;/code&gt; command. The good news is, all modern shell environments actually support command aliases in one form or another, and we encourage you to improve your CLI experience using these ways that are baked into your favorite shell already.&lt;/p&gt;

&lt;p&gt;Let’s say you check for package distribution tags information pretty often, are a report message addict as well as an emoji hater, and you’d like to have a handy shorthand for this common task. Below we’ve compiled a list of ways to add the command alias of &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn info --verbose --no-emoji &amp;lt;package&amp;gt; dist-tags&lt;/code&gt; in a number of popular shells for your convenience:&lt;/p&gt;

&lt;h2 id=&quot;bash--zsh&quot;&gt;Bash &amp;amp; Zsh&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Bash_(Unix_shell)&quot;&gt;Bash&lt;/a&gt; is the default shell on most Unix-like systems; together with &lt;a href=&quot;https://en.wikipedia.org/wiki/Z_shell&quot;&gt;Zsh&lt;/a&gt;, they both descended from the earlier &lt;a href=&quot;https://en.wikipedia.org/wiki/Bourne_shell&quot;&gt;Bourne shell&lt;/a&gt; and hence syntaxes are largely compatible. To add a simple alias in either Bash or Zsh, simply have the following line added into your &lt;code class=&quot;highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;.zshrc&lt;/code&gt;, respectively:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ynf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yarn info --verbose --no-emoji&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Restart your shell and now you’ll be able to do:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;ynf react dist-tags
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;yarn info v0.24.6
verbose 0.261 Checking for configuration file &quot;/Users/gsklee/.npmrc&quot;.
verbose 0.262 Checking for configuration file &quot;/Users/gsklee/.npmrc&quot;.
verbose 0.262 Checking for configuration file &quot;/Users/gsklee/.nvm/versions/node/v8.1.2/.npmrc&quot;.
verbose 0.263 Checking for configuration file &quot;/Users/gsklee/.npmrc&quot;.
verbose 0.263 Checking for configuration file &quot;/Users/.npmrc&quot;.
verbose 0.265 Checking for configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.265 Found configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.267 Checking for configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.267 Found configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.268 Checking for configuration file &quot;/Users/gsklee/.nvm/versions/node/v8.1.2/.yarnrc&quot;.
verbose 0.268 Checking for configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.268 Found configuration file &quot;/Users/gsklee/.yarnrc&quot;.
verbose 0.27 Checking for configuration file &quot;/Users/.yarnrc&quot;.
verbose 0.274 current time: 2017-06-16T09:43:50.256Z
verbose 0.339 Performing &quot;GET&quot; request to &quot;https://registry.yarnpkg.com/react&quot;.
verbose 0.488 Request &quot;https://registry.yarnpkg.com/react&quot; finished with status code 200.
{ latest: '15.6.1',
  '0.10.0-rc1': '0.10.0-rc1',
  '0.11.0-rc1': '0.11.0-rc1',
  next: '16.0.0-alpha.13',
  dev: '15.5.0-rc.2',
  '0.14-stable': '0.14.9',
  '15-next': '15.6.0-rc.1' }
Done in 0.28s.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now, if you’d like to further alias the &lt;code class=&quot;highlighter-rouge&quot;&gt;dist-tags&lt;/code&gt; part as well, you’ll need to use a function instead because Bash/Zsh aliases do not accept additional parameters:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;ynftag &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; yarn info --verbose --no-emoji &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; dist-tags; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;You’ll then be able to get the same output by simply typing:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;ynftag react
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;fish&quot;&gt;Fish&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Friendly_interactive_shell&quot;&gt;Fish&lt;/a&gt; is a newer “&lt;a href=&quot;https://en.wikipedia.org/wiki/Unix_shell#Exotic_shells&quot;&gt;exotic shell&lt;/a&gt;” that deviates from traditional shell designs. It offers “abbreviations” that expand into full commands live as you type, much like the so-called snippets in modern code editors. To add an abbreviation:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;abbr --add ynf yarn info --verbose --no-emoji
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When it comes to passing in additional arguments, however, you have to use functions just like in Bash and Zsh:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;ynftag --wraps yarn --description &lt;span class=&quot;s2&quot;&gt;&quot;yarn info --verbose --no-emoji &amp;lt;package&amp;gt; dist-tags&quot;&lt;/span&gt;
  yarn info --verbose --no-emoji &lt;span class=&quot;nv&quot;&gt;$argv&lt;/span&gt; dist-tags
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;To persist your alias command definition, save it to your autoload directory:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;funcsave ynftag
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;powershell&quot;&gt;PowerShell&lt;/h2&gt;

&lt;p&gt;For Windows developers, chances are that you’ve been using &lt;a href=&quot;https://en.wikipedia.org/wiki/PowerShell&quot;&gt;PowerShell&lt;/a&gt; instead. Unlike Unix shells which are built upon text processing and piping, inputs and outputs in PowerShell are .NET objects; as such, aliases in PowerShell do not work as string substitutions, but rather pointers to existing functions. This means that you’ll need to use functions to define your aliases whether additional parameters are involved or not.&lt;/p&gt;

&lt;p&gt;Here is a &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms714428&quot;&gt;guidelines-abiding&lt;/a&gt; example of the &lt;code class=&quot;highlighter-rouge&quot;&gt;ynftag&lt;/code&gt; alias:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;Get-NpmPackageDistributionTags &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; yarn info --verbose --no-emoji @Args dist-tags &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
New-Alias ynftag Get-NpmPackageDistributionTags
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Save the code above to one of the many &lt;a href=&quot;https://blogs.technet.microsoft.com/heyscriptingguy/2013/01/04/understanding-and-using-powershell-profiles/&quot;&gt;PowerShell profiles&lt;/a&gt; that suits you best to persist the definition.&lt;/p&gt;

&lt;h2 id=&quot;command-prompt-cmd&quot;&gt;Command Prompt (&lt;code class=&quot;highlighter-rouge&quot;&gt;cmd&lt;/code&gt;)&lt;/h2&gt;

&lt;p&gt;If you’re still using the clunky Command Prompt, we believe that it’d be better for you, in the long run, to learn to use PowerShell instead. It’s more capable, modern, and everything is just way more consistent. Nonetheless, here is how you define an alias within the current Command Prompt instance:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;doskey &lt;span class=&quot;nv&quot;&gt;ynftag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;yarn info --verbose --no-emoji &lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt; dist-tags
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Since Command Prompt doesn’t come with a &lt;code class=&quot;highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt; equivalent, in order to persist your aliases permanently, you’ll need to create a custom &lt;code class=&quot;highlighter-rouge&quot;&gt;cmdrc.cmd&lt;/code&gt; file (could be any name, but we recommend you to stick with the long-standing naming convention) inside your home directory, with the following content:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;@echo off
doskey &lt;span class=&quot;nv&quot;&gt;ynftag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;yarn info --verbose --no-emoji &lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt; dist-tags
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Then modify your Command Prompt shortcut target to:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Replace `cmdrc.cmd` with the full path that leads to the file.&lt;/span&gt;

cmd.exe /k cmdrc.cmd
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt;

&lt;p&gt;Yarn is a powerful JavaScript tool, but it’s also a tool that resides in your shell environment. By leveraging the innate capabilities of your shell, Yarn can do far more for you right now and right away.&lt;/p&gt;
</description>
        <pubDate>Mon, 19 Jun 2017 00:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/06/19/adding-command-line-aliases-for-yarn/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/06/19/adding-command-line-aliases-for-yarn/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Private Registry Support</title>
        <description>&lt;p&gt;Today, Yarn already supports a wide variety of different package feeds when fetching and downloading your dependencies. Up until now, there was however a small subset of public and private package feed providers that Yarn could not yet handle very well. One example of these package feed providers that were not yet supported was &lt;a href=&quot;https://www.visualstudio.com/team-services/&quot;&gt;Visual Studio Team Services&lt;/a&gt; (VSTS).&lt;/p&gt;

&lt;p&gt;Let’s explain why:&lt;/p&gt;

&lt;h3 id=&quot;registry-and-package-location-url-differences&quot;&gt;Registry and package location URL differences&lt;/h3&gt;

&lt;p&gt;Some registries, such as VSTS, use two slightly different URL structures for the location of the package feed and the location of the actual package archive binary itself.&lt;br /&gt;
For example, a private feed’s URL would look like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;// Package feed URL
https://$ACCOUNT_NAME.pkgs.visualstudio.com/_packaging/$FEED_NAME/npm/registry
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;but the URLs to fetch the actual tar archives would then be returned by the feed in this format:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;// Package archive URL
https://$ACCOUNT_NAME.pkgs.visualstudio.com/_packaging/da6e033f-20ad-4ee1-a784-8995dd6836b72/npm/registry/@scope/package-name/-/package-name-0.0.1.tgz
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, the archive’s URL does not contain the actual feed name anymore but rather a random GUID, followed by the package name and version. This differing layout of the path part of the URL lead to Yarn not recognizing that the two URLs actually both do belong to a request to the same registry and would therefore refuse to download the package.&lt;/p&gt;

&lt;h3 id=&quot;introducing-custom-host-suffixes&quot;&gt;Introducing custom host suffixes&lt;/h3&gt;

&lt;p&gt;Starting with version &lt;code class=&quot;highlighter-rouge&quot;&gt;0.26.0&lt;/code&gt;, Yarn now understands a new configuration option called &lt;code class=&quot;highlighter-rouge&quot;&gt;custom-host-suffix&lt;/code&gt;. This allows you to keep the same strict URL validations for most of your package URLs but also selectively loosen that check for a specific registry provider so that Yarn will now match the URLs where the host part ends with the value from this new option.&lt;/p&gt;

&lt;p&gt;Simply add &lt;code class=&quot;highlighter-rouge&quot;&gt;custom-host-suffix&lt;/code&gt; to either your global user-level &lt;code class=&quot;highlighter-rouge&quot;&gt;.npmrc&lt;/code&gt; or your project’s individual &lt;code class=&quot;highlighter-rouge&quot;&gt;.npmrc&lt;/code&gt; and Yarn will be able to download your packages as desired.
In the above example of Visual Studio Team Services, the &lt;code class=&quot;highlighter-rouge&quot;&gt;.npmrc&lt;/code&gt; should contain an entry like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;custom-host-suffix='pkgs.visualstudio.com'
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;We hope you will find this new option useful and are happy that Yarn can now be used in even more projects!&lt;/p&gt;
</description>
        <pubDate>Fri, 16 Jun 2017 12:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/06/16/supporting-more-registries/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/06/16/supporting-more-registries/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Yarn determinism</title>
        <description>&lt;p&gt;One of the claims that Yarn makes is that it makes your package management “deterministic”. But what exactly does this mean? This blog post highlights how both Yarn and npm 5 are deterministic, but differ in the exact guarantees they provide and the tradeoffs they have chosen.&lt;/p&gt;

&lt;h2 id=&quot;what-is-determinism&quot;&gt;What is determinism?&lt;/h2&gt;

&lt;p&gt;Determinism in the context of JavaScript package management is defined as always getting the exact same &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder given a &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; and companion lock file.&lt;/p&gt;

&lt;h2 id=&quot;what-factors-does-yarns-determinism-guarantee&quot;&gt;What factors does Yarn’s determinism guarantee?&lt;/h2&gt;

&lt;h3 id=&quot;lockfile&quot;&gt;Lockfile&lt;/h3&gt;

&lt;p&gt;Yarn is fully deterministic as long as all your teammates are using the same Yarn version. In both Yarn and npm 5, the determinism is ensured by lockfiles that contain information about the whole tree. However the lockfile formats are different between these two projects. We haven’t publicly talked about why we chose this format, so we want to walk you through it:&lt;/p&gt;

&lt;p&gt;If you’ve ever seen a &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; then you should be pretty familiar with the following structure:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;has-flag@^1.0.0:
  version &quot;1.0.0&quot;
  resolved &quot;https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa&quot;

supports-color@^3.2.3:
  version &quot;3.2.3&quot;
  resolved &quot;https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6&quot;
  dependencies:
    has-flag &quot;^1.0.0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is the &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock &lt;/code&gt;file generated by running the command &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn add supports-color&lt;/code&gt;. This file contains the version of supports-color that our project is using as well as the exact version of all its sub-dependencies.&lt;/p&gt;

&lt;p&gt;With this lock file we can ensure that the version of &lt;code class=&quot;highlighter-rouge&quot;&gt;has-flag&lt;/code&gt; that &lt;code class=&quot;highlighter-rouge&quot;&gt;supports-color&lt;/code&gt; relies on is always the same version.&lt;/p&gt;

&lt;p&gt;But there’s one key piece of information that the yarn lockfile doesn’t contain and that’s the hoisting and location of each dependency in the tree. For example, given a &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; it’s impossible to determine what are the top level dependencies unless you have it’s accompanying &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;. Even knowing the top level packages, we still cannot infer what hoisting position packages should be in.&lt;/p&gt;

&lt;p&gt;In practice this means that the position of packages in &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; is computed internally in Yarn, which causes Yarn to be non-deterministic between people using different versions.&lt;/p&gt;

&lt;p&gt;The reason that we do this is that this lockfile format is great for diffing. That is, changes to the lockfile can easily be human reviewed. The reason we use a custom format instead of JSON and have everything at the top level is so that it’s easy to read and review. Merge conflicts are usually automatically handled by version control and it reduces thrash.&lt;/p&gt;

&lt;h3 id=&quot;hoisting-guarantees&quot;&gt;Hoisting guarantees&lt;/h3&gt;

&lt;p&gt;Even though Yarn hoisting may differ between versions we still make very strong guarantees around hoisting when the same version of Yarn is used. The most significant of these guarantees is that omitting environmental dependencies like &lt;code class=&quot;highlighter-rouge&quot;&gt;optionalDependencies&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;devDependencies&lt;/code&gt; still influences the position of normal &lt;code class=&quot;highlighter-rouge&quot;&gt;dependencies&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Woah there, that’s a lot of dependency mumbo jumbo. What does that actually mean?&lt;/p&gt;

&lt;p&gt;There are several types of dependencies that you can declare in your &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;. Two of these are plain &lt;code class=&quot;highlighter-rouge&quot;&gt;dependencies&lt;/code&gt; which are installed all the time, and there are &lt;code class=&quot;highlighter-rouge&quot;&gt;devDependencies&lt;/code&gt; which are only installed when you run &lt;code class=&quot;highlighter-rouge&quot;&gt;npm install&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn&lt;/code&gt; within the directory where the &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; file is present.&lt;/p&gt;

&lt;p&gt;Due to these features it’s possible to have different layouts of &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; with omitted dependencies. But Yarn still factors all dependencies into account when determining the position that they should be at in &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt;, so even if they aren’t installed, they still influence the hoisting position of others. This is important as having variance in hoisting position of packages in production and development can cause really weird obscure bugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: This guarantee isn’t unique to Yarn and npm 5 also does this.&lt;/p&gt;

&lt;h2 id=&quot;how-does-this-compare-to-npm-5&quot;&gt;How does this compare to npm 5?&lt;/h2&gt;

&lt;p&gt;npm 5 introduces a rework of the shrinkwrap feature called package-lock. This file includes all the information required to create &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; as well as all hoisting information. The npm version of the previous &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; would be:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;react-example&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;lockfileVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;has-flag&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;resolved&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;integrity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;supports-color&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;3.2.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;resolved&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;integrity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Note that here all the packages listed in the first dependencies object are hoisted. This means that npm can use only the package-lock as the source of truth in order to build the final dependency graph whereas Yarn needs the accompanying&lt;code class=&quot;highlighter-rouge&quot;&gt; package.json&lt;/code&gt; to seed it.&lt;/p&gt;

&lt;p&gt;This means that npm has better assurances around hoisting position across npm versions at the cost of having a more dense lockfile. There’s currently no plan on how to support &lt;code class=&quot;highlighter-rouge&quot;&gt;package-lock.json&lt;/code&gt; in Yarn as the story around lockfile interoperability is unclear. You could however imagine a future where Yarn supports both and updates them in tandem. We’re very interested in community feedback and encourage proposals for how this would work to be submitted as an &lt;a href=&quot;https://github.com/yarnpkg/rfcs&quot;&gt;RFC&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;closing-remarks&quot;&gt;Closing remarks&lt;/h2&gt;

&lt;p&gt;Each lock file format has different tradeoffs and there doesn’t appear to be a perfect format without disadvantages. It’s important to evaluate what sort of guarantees you’re looking for when deciding what package manager to use.&lt;/p&gt;

&lt;p&gt;npm 5 has stronger guarantees across versions and has a stronger deterministic lockfile, but Yarn only has those guarantees when you’re on the same version in favor of a lighter lockfile that is better for review. It’s possible that there’s a lockfile solution that has the best of both worlds, but for now this is current state of the ecosystem and possible convergence could happen in the future.&lt;/p&gt;

&lt;p&gt;Hopefully this post has highlighted the determinism guarantees that differ between Yarn and npm and helped you decide what works better for your company or project.&lt;/p&gt;
</description>
        <pubDate>Wed, 31 May 2017 09:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/05/31/determinism/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/05/31/determinism/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Yarn Create &amp; Yarn 1.0</title>
        <description>&lt;p&gt;Last year was a great time for Javascript newcomers! A lot of starter-kit projects were published, refined, and some of them eventually went on to offer command line tools dedicated to make project creation easier. One such example is &lt;a href=&quot;https://github.com/facebookincubator/create-react-app&quot;&gt;create-react-app&lt;/a&gt;, but most frameworks have their own tools, with various flavors and syntaxes.&lt;/p&gt;

&lt;p&gt;Despite these tools, one problem remains: Users still need to know how to use their package managers before being able to start a new project. They need to know what’s the difference between global packages and local packages, and how to make sure that the binaries are available from the shell, which can sometimes cause subtle issues. Further, because these globally installed tools need to be manually updated, most projects maintain a small cli wrapper that downloads the latest version of the tool itself. Fortunately, we’re in a position where we can help with this to make building new applications more cohesive:&lt;/p&gt;

&lt;h3 id=&quot;yarn-create-pkg-name&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create &amp;lt;pkg-name&amp;gt;&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;With &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create&lt;/code&gt;, you can start building apps with many of the existing projects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create react-app my-app&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create react-native-app my-app&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create next-app my-app&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When ran, the create command will automatically install or update the requested package, prefixing its name with &lt;code class=&quot;highlighter-rouge&quot;&gt;create-&lt;/code&gt;. Running &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create react-app&lt;/code&gt; will start by doing the same thing as &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn global add create-react-app&lt;/code&gt;. Then, once the package installed, Yarn will run the executable located in the &lt;code class=&quot;highlighter-rouge&quot;&gt;bin&lt;/code&gt; field of the newly installed package’s &lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt;, forwarding to it any remaining command line argument.&lt;/p&gt;

&lt;p&gt;It is important to us to keep the feature small and extensible. Yarn should be a lightweight tool and &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create&lt;/code&gt; is no exception: An immediate implication is that the create command is a completely agnostic tool: we make no assumption regarding what you want to create, and delegate all the behavior to the &lt;code class=&quot;highlighter-rouge&quot;&gt;create-*&lt;/code&gt; packages! It is our hope that the community will come up with creative way to use this tool. Creating apps is but only one thing! Feel free to make packages that create tests, readmes, changelogs or anything else you want!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The &lt;code class=&quot;highlighter-rouge&quot;&gt;create-&lt;/code&gt; prefix is inserted right before the package name. So, for example, if you run yarn create &lt;code class=&quot;highlighter-rouge&quot;&gt;@ng/app&lt;/code&gt;, it will install the &lt;code class=&quot;highlighter-rouge&quot;&gt;@ng/create-app&lt;/code&gt; package, then run it.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;other-improvements&quot;&gt;Other Improvements&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;yarn create&lt;/code&gt; is but one of the many things we have been working on over the last couple of weeks. Thanks to numerous pull requests from many open source contributors, the recent releases also ship with the following features &amp;amp; improvements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The offline mirror does not require changes to the yarn lockfile any longer (&lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/2970&quot;&gt;#2970&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Command-line arguments and environment variables can now be set in the yarnrc file (&lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3033&quot;&gt;#3033&lt;/a&gt;, &lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3218&quot;&gt;#3218&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Prepare &amp;amp; prepublish-only lifecycle hooks are now implemented (&lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3004&quot;&gt;#3004&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;The offline mirror can be pruned if used by a single one of your projects (&lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/2836&quot;&gt;#2836&lt;/a&gt;)&lt;/li&gt;
  &lt;li&gt;Various improvements for yarn pack (&lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3175&quot;&gt;#3175&lt;/a&gt;, &lt;a href=&quot;https://github.com/yarnpkg/yarn/pull/3092&quot;&gt;#3092&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list of all improvements and bugfixes over the last couple of months can be found in our &lt;a href=&quot;https://github.com/yarnpkg/yarn/releases&quot;&gt;releases section on GitHub&lt;/a&gt;. We would specifically like to thank a team from the Delft University of Technology: &lt;a href=&quot;https://github.com/timvdlippe&quot;&gt;Tim van der Lippe&lt;/a&gt;, &lt;a href=&quot;https://github.com/clanghout&quot;&gt;Chris Langhout&lt;/a&gt;, &lt;a href=&quot;https://github.com/gijsweterings&quot;&gt;Gijs Weterings&lt;/a&gt; and &lt;a href=&quot;https://github.com/keraito&quot;&gt;Chak Shun Yu&lt;/a&gt;. The four of them did a fantastic &lt;a href=&quot;https://delftswa.gitbooks.io/desosa-2017/content/yarn/chapter.html&quot;&gt;analysis of the Yarn project&lt;/a&gt; and sent pull requests to improve it in many areas. They also pointed out gaps in our test coverage, which our new core contributor &lt;a href=&quot;https://github.com/voxsim&quot;&gt;Simon Vocella&lt;/a&gt; has been working on improving.&lt;/p&gt;

&lt;h3 id=&quot;planning-for-yarn-10&quot;&gt;Planning for Yarn 1.0&lt;/h3&gt;

&lt;p&gt;Yarn has made substantial improvements since its initial release 7 months ago and the project recently surpassed 1,000 Pull Requests. Currently, we are planning for the 1.0 release of Yarn which is scheduled for this summer and will come with stability improvements, new features and performance wins. To hear more about Yarn’s present and future, please watch Konstantin’s talk about &lt;a href=&quot;https://developers.facebook.com/videos/f8-2017/building-high-quality-javascript-tools/&quot;&gt;Building High-Quality JavaScript Tools&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We thank each and every one of you for your help to make this project great. If you’d like to contribute to Yarn, please don’t hesitate to reach out to us on &lt;a href=&quot;https://github.com/yarnpkg/yarn&quot;&gt;GitHub&lt;/a&gt; or on &lt;a href=&quot;https://discordapp.com/invite/yarnpkg&quot;&gt;Discord&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 12 May 2017 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/05/12/introducing-yarn/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/05/12/introducing-yarn/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Cloudflare security incident and impact on Yarn users</title>
        <description>&lt;p&gt;Yarn uses its own proxy to the npm registry in order to allow us to experiment
with the way the Yarn client works and allow optimizations in the future around
how packages are resolved. This registry is used by all Yarn users by default.&lt;/p&gt;

&lt;p&gt;In order to do this we use the popular service, Cloudflare, which is used by
thousands of companies and who had offered to work with us to make Yarn installs
faster globally.&lt;/p&gt;

&lt;p&gt;Recently it was &lt;a href=&quot;https://blog.cloudflare.com/incident-report-on-memory-leak-caused-by-cloudflare-parser-bug/&quot;&gt;reported&lt;/a&gt;
that Cloudflare had a serious bug that was leading to requests from other websites
being leaked into HTTP responses.&lt;/p&gt;

&lt;p&gt;When it comes to registry authentication, the Yarn client differs from the npm
client in that when we perform authentication we do not store the resulting token
and invalidate it after it’s used.&lt;/p&gt;

&lt;p&gt;However, Yarn still allows you to login with your npm account to perform actions
such as publishing and downloading private packages. Out of the 70 million requests
performed daily we only get 10-30 requests that involve registry authentication.
This means that for these requests there was the possibility of user passwords
being leaked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Since the Cloudflare announcement we’ve been in contact and have been assured
that Yarn has not been affected and no Yarn users data has been leaked. Even with
this assurance we’d recommend that if you’re one of those 30 people a day using Yarn
for registry authentication that you reset your password as a precautionary measure.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a result of this we’re evaluating our security policy and have created a new email
address &lt;a href=&quot;mailto:security@yarnpkg.com&quot;&gt;security@yarnpkg.com&lt;/a&gt; that can be used to report
security vulnerabilities without going through the public issue tracker. We’re also in
the process of setting up a HackerOne account and will make an announcement when this
is available.&lt;/p&gt;

&lt;p&gt;We’d like to apologize for this disruption and want to reaffirm our commitment to security
and transparency in cases like these.&lt;/p&gt;
</description>
        <pubDate>Fri, 24 Feb 2017 14:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2017/02/24/cloudflare-statement/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2017/02/24/cloudflare-statement/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Lockfiles should be committed on all projects</title>
        <description>&lt;p&gt;Yarn is a new package manager that we built to be consistent and reliable. When
installing hundreds or even thousands of third-party packages from the internet
you want to be sure that you’re executing the same code across every system.&lt;/p&gt;

&lt;p&gt;Yarn maintains consistency across machines in two key ways:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Yarn uses a deterministic algorithm that builds up the entire dependency tree
before placing files where they need to be.&lt;/li&gt;
  &lt;li&gt;Important info from the install process is stored in the &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; lockfile
so that it can be shared between every system installing the dependencies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This lockfile contains information about the exact versions of every single
dependency that was installed as well as checksums of the code to make sure the
code is identical.&lt;/p&gt;

&lt;p&gt;Yarn needs this info about every dependency because packages are constantly
changing. New versions of packages are published all the time and since
&lt;code class=&quot;highlighter-rouge&quot;&gt;package.json&lt;/code&gt; specifies version ranges you need to lock them down to a single
version.&lt;/p&gt;

&lt;p&gt;These version ranges exist because Yarn follows
&lt;a href=&quot;http://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt;, or “SemVer”. SemVer is a versioning
system designed around “breaking” or “non-breaking” changes.&lt;/p&gt;

&lt;p&gt;When you have a version such as &lt;code class=&quot;highlighter-rouge&quot;&gt;v1.2.3&lt;/code&gt;, it’s broken into three parts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Major (1.x.x)&lt;/strong&gt; – &lt;em&gt;Changes that may cause user code to break&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Minor (x.2.x)&lt;/strong&gt; – &lt;em&gt;Changes that add new features (but should not break user
code)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Patch (x.x.3)&lt;/strong&gt; – &lt;em&gt;Changes that are fixing bugs in previous versions (but
do not add new features and should not break user code)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a package publishes a new version, the author bumps major, minor, or patch
based on the changes that they have made as a way to communicate them.&lt;/p&gt;

&lt;p&gt;Users of packages should typically welcome minor and patch versions but should
be wary of major versions as they could break your code.&lt;/p&gt;

&lt;p&gt;Version ranges are a way of specifying which types of changes you want to
accept and which versions you want to prevent.  These version ranges then
resolve down to a single version which is either the version you have installed
or the latest published version that matches your version range.&lt;/p&gt;

&lt;p&gt;If you don’t store which version you ended up installing, someone could be
installing the same set of dependencies and end up with different versions
depending on when they installed. This can lead to “Works On My Machine”
problems and should be avoided.&lt;/p&gt;

&lt;p&gt;Also, since package authors are people and they can make mistake, it’s possible
for them to publish an accidental breaking change in a minor or patch version.
If you install this breaking change when you don’t intend to it could have bad
consequences like breaking your app in production.&lt;/p&gt;

&lt;p&gt;Lockfiles &lt;em&gt;lock&lt;/em&gt; the versions for every single dependency you have installed.
This prevents “Works On My Machine” problems, and ensures that you don’t
accidentally get a bad dependency.&lt;/p&gt;

&lt;p&gt;It also works as a security precaution: If the package author is either
malicious or is attacked by someone malicious and a bad version is published,
you do not want that code to end up running without you knowing about it.&lt;/p&gt;

&lt;h2 id=&quot;libraries-vs-applications&quot;&gt;Libraries vs Applications&lt;/h2&gt;

&lt;p&gt;There are two primary types of projects that use Yarn:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Libraries&lt;/strong&gt; – &lt;em&gt;Projects that get published as packages to the registry and
installed by users. (i.e. React or Babel)&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Applications&lt;/strong&gt; – &lt;em&gt;Projects that only consume other packages, typically
building some kind of product. (i.e. Your company’s app)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For applications, most developers agree that lockfiles are A Good Idea™.
But there has been some question about using them when building libraries.&lt;/p&gt;

&lt;p&gt;When you publish a package that contains a &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt;, any user of that
library will not be affected by it. When you install dependencies in your
application or library, only your own &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; file is respected. Lockfiles
within your dependencies will be ignored.&lt;/p&gt;

&lt;p&gt;It is important that Yarn behaves this way for two reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You would never be able to update the versions of sub-dependencies because
they would be locked by other &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; files.&lt;/li&gt;
  &lt;li&gt;Yarn would never be able to fold (de-duplicate) dependencies so that
compatible version ranges only install a single version.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some have wondered why libraries should use lockfiles at all if they do not and
should not affect users. Even further, some have said that using lockfiles when
developing libraries creates a &lt;em&gt;false sense of security&lt;/em&gt; since your users could
be installing different versions than you.&lt;/p&gt;

&lt;p&gt;This seems to logically makes sense, but let’s dive deeper into the problem.&lt;/p&gt;

&lt;h2 id=&quot;development-dependencies&quot;&gt;Development Dependencies&lt;/h2&gt;

&lt;p&gt;So far we’ve been talking about dependencies as if there were only one type of
dependency when in fact there are several different types. These are broken
down into two categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Runtime&lt;/strong&gt; – &lt;em&gt;Dependencies that are used by the project’s code and needed
when the code is run.&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Development&lt;/strong&gt; – &lt;em&gt;Dependencies that are only needed to work directly on the
project&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a library is installed by a user, only the runtime dependencies are
installed. The development dependencies are only ever installed when working
directly on the project that specifies them.&lt;/p&gt;

&lt;p&gt;Each type of dependency creates a whole tree of dependencies which are needed
for them to be used.&lt;/p&gt;

&lt;p&gt;It turns out that most projects (libraries or applications) have far more
dependencies for development than for runtime. The tree of dependencies created
by a projects development dependencies is almost always the largest part of the
total.&lt;/p&gt;

&lt;p&gt;You can blame this on how frustratingly complicated JavaScript development is,
but it seems to hold true across every ecosystem. You almost always need more
code to develop projects than you need to run them.&lt;/p&gt;

&lt;p&gt;When working on a library, it is far more likely that a development dependency
breaks just because there are more of them that &lt;em&gt;could&lt;/em&gt; break.&lt;/p&gt;

&lt;h2 id=&quot;the-breaking-change-race&quot;&gt;The Breaking Change Race&lt;/h2&gt;

&lt;p&gt;When a package accidentally publishes a breaking change it starts the clock on
who will be the first person to catch it. Whoever installs that breaking change
first will (most likely) be the first to discover it.&lt;/p&gt;

&lt;p&gt;Let’s &lt;em&gt;imagine&lt;/em&gt; we have a package called &lt;code class=&quot;highlighter-rouge&quot;&gt;left-pad&lt;/code&gt; which takes a string and
adds a specified amount of padding in front of it. This small and seemingly
harmless package is used by a really big project, which we’ll just call…
Babel.&lt;/p&gt;

&lt;p&gt;One day, the maintainer of  &lt;code class=&quot;highlighter-rouge&quot;&gt;left-pad&lt;/code&gt;  decides they are going to do something
unspeakably evil and make it pad the right side instead. They publish it as a
patch version which quickly spreads to everyone using it.&lt;/p&gt;

&lt;p&gt;Remember, Babel is a really huge project with tens of thousands of users and
dozens of contributors. Let’s try and figure out who will catch the padding
fiasco first.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Looking at build history, Babel was installed in CI (with the &lt;code class=&quot;highlighter-rouge&quot;&gt;left-pad&lt;/code&gt;
dependency) exactly &lt;strong&gt;103 times&lt;/strong&gt; in the last 30 days.&lt;/li&gt;
  &lt;li&gt;Looking at statistics from the registry, Babel was installed (with
&lt;code class=&quot;highlighter-rouge&quot;&gt;left-pad&lt;/code&gt;) by users over &lt;strong&gt;5.5 Million times&lt;/strong&gt; in the same 30 days.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To put that in a different measurement:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Contributors install Babel on average &lt;strong&gt;every 7 hours&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Users install Babel about on average &lt;strong&gt;every 0.5 seconds&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the &lt;code class=&quot;highlighter-rouge&quot;&gt;left-pad&lt;/code&gt; incident happened, users discovered it almost immediately.
Notifying the Babel contributors via GitHub issues, tweets, Facebook messages,
emails, phone calls, smoke signals, and by carrier pigeon.&lt;/p&gt;

&lt;p&gt;Babel contributors couldn’t possibly prevent users from being affected by every
error. In order to do so, every 0.5 seconds they would need to be able to run
CI, notice the error, find a fix, publish a new version, and get every user to
upgrade. There’s just no way to make this happen.&lt;/p&gt;

&lt;p&gt;This might seem like a bit too extreme of an example to apply broadly, but the
reasoning stays the same just with different numbers. Libraries should always
be installed more frequently by users than by contributors. If that isn’t true,
it’s because no one uses that library anyways– and we should not be optimizing
our workflow around code that no one uses.&lt;/p&gt;

&lt;h2 id=&quot;user-testing&quot;&gt;User testing&lt;/h2&gt;

&lt;p&gt;Many library developers work very hard to maintain a test suite that has 100%
code coverage. This coverage ensures that every single line of code is run at
least once during the tests.&lt;/p&gt;

&lt;p&gt;But it still does not catch everything. If a library has even a small number of
users, it will be far better tested by the users than it will be by any test
suite the contributors can come up with.&lt;/p&gt;

&lt;p&gt;Users just write more code, and the code they write is not always what a
library author will expect. The more popular the library the more edge cases
users will find. Users will do things that you didn’t even think was possible–
it will &lt;em&gt;horrify&lt;/em&gt; you. It will make you question the goodness of humanity.&lt;/p&gt;

&lt;p&gt;Even if a contributor happened to beat users to finding a breaking change,
there’s a pretty decent chance they won’t catch it anyways. Untested edge cases
are the most likely things to break.&lt;/p&gt;

&lt;h2 id=&quot;the-contributors-burden&quot;&gt;The contributor’s burden&lt;/h2&gt;

&lt;p&gt;Now let’s talk a bit about the social side of not using lockfiles in libraries.&lt;/p&gt;

&lt;p&gt;As mentioned previously, the majority of breaking changes that occur in library
dependencies will be development dependencies.&lt;/p&gt;

&lt;p&gt;Some percentage of these breaking changes will be caught and (hopefully) fixed
by regular contributors. However, the remaining breaking changes will be caught
by new or infrequent contributors.&lt;/p&gt;

&lt;p&gt;Contributing to a project for the first time is a very intimidating experience
for anyone who is not an open source veteran. If the first thing a potential
new contributor runs into is a broken build or test suite, they could be so
intimidated that they decide to forget about contributing back.&lt;/p&gt;

&lt;p&gt;Even as someone who contributes to lots of open source projects, it’s a
terrible thing to have to debug a build system for a few hours when you just
want to fix a bug or add a small feature to a library.&lt;/p&gt;

&lt;h2 id=&quot;the-users-burden&quot;&gt;The user’s burden&lt;/h2&gt;

&lt;p&gt;Of course not every breaking change is a development dependency, and
theoretically contributors &lt;em&gt;could&lt;/em&gt; catch breaking changes before users notice
them. In that (narrow) scenario, aren’t we shifting the burden from
contributors to users?&lt;/p&gt;

&lt;p&gt;First, it’s not going to be every user that is affected by this. It’s well
agreed upon that applications should be using lockfiles, and if they are then
they won’t be affected by sudden breaking changes.&lt;/p&gt;

&lt;p&gt;We’re only talking about users that are either installing a package for the
first time, or are upgrading the versions of their dependencies.&lt;/p&gt;

&lt;p&gt;For users upgrading their dependencies, they should be trained to look out for
breaking changes and if they encounter one, to roll back the version to a
working state and open an issue in the library.&lt;/p&gt;

&lt;p&gt;The only really negative experience that we are adding is for new users. Which
is admittedly terrible, you want new users to have the best possible
experience.&lt;/p&gt;

&lt;p&gt;But remember that they already face this burden in the majority of cases. It’s
only when contributors could have caught breaking changes before users
experienced them that we are now placing an additional burden on new users.&lt;/p&gt;

&lt;p&gt;It’s also important to note that new users make up a minority of the total
installations. The majority of the time it will be existing users that are the
first to catch breaking changes because they are the ones installing a library
the most.&lt;/p&gt;

&lt;h2 id=&quot;in-closing&quot;&gt;In Closing&lt;/h2&gt;

&lt;p&gt;There is a simple universal rule that everyone should follow with Yarn: If you
are installing a new dependency or upgrading an existing one you should check
to make sure the package works as intended and is not breaking your code.&lt;/p&gt;

&lt;p&gt;You should follow that rule regardless of what your libraries are doing.&lt;/p&gt;

&lt;p&gt;Without lockfiles it gets even more complicated: In applications or libraries,
if there is no lockfile, you will have to check the dependencies every time you
install or re-install them and make sure that everything still works. Otherwise
the build might be broken or the tests might fail. You could break something
without even realizing it. You could run into situations where code works on
your machine but no one else’s.&lt;/p&gt;

&lt;p&gt;The idea that not using lockfiles in libraries somehow saves users from
encountering breaking changes is at best extremely rare and at worst is never
true.&lt;/p&gt;

&lt;p&gt;By not using lockfiles in libraries, the only tangible thing you accomplish is
making the project harder to contribute to.&lt;/p&gt;

&lt;p&gt;We should work as a community to keep all of our libraries up to date. We
should go out and build tooling for automatically upgrading dependencies that
makes it painless to do. There has been attempts at such tooling before, but we
can do better.&lt;/p&gt;

&lt;p&gt;Please commit your &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; files.&lt;/p&gt;
</description>
        <pubDate>Thu, 24 Nov 2016 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2016/11/24/lockfiles-for-all/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2016/11/24/lockfiles-for-all/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
      <item>
        <title>Running Yarn offline</title>
        <description>&lt;p&gt;Repeatable and reliable builds for large JavaScript projects  are vital.
If your builds depend on dependencies being downloaded from network, this build system is neither repeatable nor reliable.&lt;/p&gt;

&lt;p&gt;One of the main advantages of Yarn is that it can install node_modules from files located in file system.
We call it “Offline Mirror” because it mirrors the files downloaded from registry during the first build and stores them locally for future builds.&lt;/p&gt;

&lt;p&gt;“Offline mirror” is different from cache that both npm CLI and Yarn have.
Caches store already unzipped tarballs downloaded from registry, they also can be implementation specific and may be invalid between multiple versions of CLI tools.
The tarballs in “Offline mirror” can be consumed by any version Yarn that will build cache based on them.
It is also easier to store files when they are compressed.&lt;/p&gt;

&lt;h2 id=&quot;lets-set-up-offline-mirror-for-a-simple-js-project&quot;&gt;Let’s set up “Offline mirror” for a simple JS project&lt;/h2&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yarn-offline&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;index.js&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;license&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;MIT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;is-array&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.0.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;left-pad&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&quot;mime-types&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^2.1.13&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;When you run &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt;, the generated &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; file has sections for every dependency:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# yarn lockfile v1&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;is-array@^1.0.1&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.0.1&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/is-array/-/is-array-1.0.1.tgz#e9850cc2cc860c3bc0977e84ccf0dd464584279a&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;left-pad@^1.1.3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.1.3&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/left-pad/-/left-pad-1.1.3.tgz#612f61c033f3a9e08e939f1caebeea41b6f3199a&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;mime-db@~1.25.0&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.25.0&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;mime-types@^2.1.13&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;2.1.13&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;mime-db &quot;~1.25.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Each of these dependencies have a &lt;code class=&quot;highlighter-rouge&quot;&gt;resolved&lt;/code&gt; field with a remote URL. If you delete your &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder and run &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn install&lt;/code&gt; again, Yarn will download the same resolved dependencies specified in this lockfile.
It will even guarantee that no one modified the files since your first installs by verifying checksum for each of them.&lt;/p&gt;

&lt;p&gt;However, if for some reason these urls are unreachable during your build, it will fail. To solve this, we’ll need an “Offline mirror”.&lt;/p&gt;

&lt;h3 id=&quot;set-up-yarnrc&quot;&gt;Set up .yarnrc&lt;/h3&gt;

&lt;p&gt;First we need to setup a directory to be our “Offline mirror” storage, we can do that with &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn config&lt;/code&gt; command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;yarn config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;yarn-offline-mirror ./npm-packages-offline-cache
yarn config v0.23.2
success Set &lt;span class=&quot;s2&quot;&gt;&quot;yarn-offline-mirror&quot;&lt;/span&gt; to &lt;span class=&quot;s2&quot;&gt;&quot;./npm-packages-offline-cache&quot;&lt;/span&gt;.
✨  Done &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0.06s.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;./npm-packages-offline-cache&lt;/code&gt; is an example location relative to home folder where all the source&lt;code class=&quot;highlighter-rouge&quot;&gt; .tar.gz&lt;/code&gt; files will be downloaded to from the registry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Offline mirror does not come with removing tarballs. In order to keep the cache folder up to date, you need to add the following to the config file:&lt;/p&gt;

&lt;p&gt;This feature is only available in version 0.23.0 and above.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;yarn config &lt;span class=&quot;nb&quot;&gt;set &lt;/span&gt;yarn-offline-mirror-pruning &lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;yarn config v0.23.2
success Set &lt;span class=&quot;s2&quot;&gt;&quot;yarn-offline-mirror-pruning&quot;&lt;/span&gt; to &lt;span class=&quot;s2&quot;&gt;&quot;true&quot;&lt;/span&gt;.
✨  Done &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0.06s.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This will create a .yarnrc file in your HOME directory.
Let’s move this file to the project root so that offline mirror would be used only for this project.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;mv ~/.yarnrc ./
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;initialize-the-new-lockfile&quot;&gt;Initialize the new lockfile&lt;/h3&gt;

&lt;p&gt;Remove node_modules and yarn.lock that were generated previously and run yarn install again:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;rm -rf node_modules/ yarn.lock
&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;yarn install
yarn install v0.17.8
info No lockfile found.
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1/4] 🔍  Resolving packages...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2/4] 🚚  Fetching packages...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;3/4] 🔗  Linking dependencies...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;4/4] 📃  Building fresh packages...
success Saved lockfile.
✨  Done &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0.57s.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The dependency resolutions in your &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; should look the same as the original:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# yarn lockfile v1&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;is-array@^1.0.1&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.0.1&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/is-array/-/is-array-1.0.1.tgz#e9850cc2cc860c3bc0977e84ccf0dd464584279a&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;left-pad@^1.1.3&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.1.3&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/left-pad/-/left-pad-1.1.3.tgz#612f61c033f3a9e08e939f1caebeea41b6f3199a&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;mime-db@~1.25.0&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;1.25.0&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392&quot;&lt;/span&gt;

&lt;span class=&quot;s&quot;&gt;mime-types@^2.1.13&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;version &quot;2.1.13&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;resolved &quot;https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88&quot;&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;mime-db &quot;~1.25.0&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;The offline cache filename is derived from the base name of the resolved URL. It will be stored in the npm-packages-offline-cache folder that was configured earlier. Each resolved dependency also contains a checksum after the file name to ensure that no one mangles with the downloaded files.&lt;/p&gt;

&lt;p&gt;And inside the “Offline mirror” folder we have the .tgz files that yarn will use for the following builds without reaching out to network.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;ls npm-packages-offline-cache/
is-array-1.0.1.tgz    left-pad-1.1.3.tgz    mime-db-1.25.0.tgz    mime-types-2.1.13.tgz
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;How can you test to make sure it is offline?&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;Clear your global cache with “yarn cache clean”&lt;/li&gt;
    &lt;li&gt;Turn off wifi&lt;/li&gt;
    &lt;li&gt;Run “yarn install –offline”. The offline flag will make sure yarn does not reach out to the network&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;In a nutshell, to enable “Offline mirror” for your project you need:&lt;/p&gt;
  &lt;ul&gt;
    &lt;li&gt;add “yarn-offline-mirror” configuration to .yarnrc file&lt;/li&gt;
    &lt;li&gt;generate a new yarn.lock with “yarn install” command&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;a-few-tips-and-tricks&quot;&gt;A few tips and tricks&lt;/h2&gt;

&lt;h3 id=&quot;updating-your-package&quot;&gt;Updating your package&lt;/h3&gt;

&lt;p&gt;If you want to make sure you have a clean cached modules, here are few of the steps you can take:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Remove the package first. Make sure you have “yarn-offline-mirror-pruning” set to true in your .yarnrc file&lt;/li&gt;
  &lt;li&gt;Clear the yarn cache with “yarn cache clean” before adding the updated version of the package&lt;/li&gt;
  &lt;li&gt;Add your package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The “yarn-offline-mirror-pruning” will help clean up any unlinked dependencies. When you add the updated package, it will check the yarn cache first and pull any missing dependencies from there. This will prevent yarn adding new tarball back with the updated package. You want to make sure the yarn cache is all clean before you do any adding for cache module.&lt;/p&gt;

&lt;h3 id=&quot;you-can-check-in-offline-mirror-into-git-or-mercurial-repository&quot;&gt;You can check in “Offline mirror” into git or mercurial repository&lt;/h3&gt;

&lt;p&gt;The “Offline Mirror” can be shared between build servers or development machines in any way that is convenient: a Box / Dropbox folder, stored in source control or on a network drive. At Facebook the offline mirror lives inside of our big Mercurial “monorepo”.&lt;/p&gt;

&lt;p&gt;Whether to commit binary files into a repository or not depends on the number and size of your project’s dependencies.
For example, out of 849 React Native dependencies totaling 23MB, only 10% are larger than 30KB.
&lt;img src=&quot;/assets/posts/2016-11-24-offline-mirror/yarn-offline-blog-offline-mirror-list.png&quot; alt=&quot;list of React Native .tgz files sorted by size descending&quot; style=&quot;max-width: 700px&quot; /&gt;
&lt;img src=&quot;/assets/posts/2016-11-24-offline-mirror/yarn-offline-blog-offline-mirror-size.png&quot; alt=&quot;Size of all .tgz files used in React Native&quot; style=&quot;max-width: 700px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Many Facebook teams, including the React Native team, decided to check in their “Offline mirror”.
They all share the same “Offline mirror” which means that most dependencies for new projects are often already checked into that folder, so the cost of storing the packages in source control gets lower the more projects use it.&lt;/p&gt;

&lt;h3 id=&quot;lets-compare-checking-in-nodemodules-to-checking-in-offline-mirror&quot;&gt;Let’s compare checking in node_modules to checking in “Offline mirror”&lt;/h3&gt;

&lt;p&gt;The React Native team used to check in the &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; folder but they hit several limits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; contains more than 37,000 files (and more than 100,000 files back when we were using npm2). This had a bad performance impact on our Mercurial repository.&lt;/li&gt;
  &lt;li&gt;Reviewing Pull Requests that changed a dependency was quite hard as all the files in &lt;code class=&quot;highlighter-rouge&quot;&gt;node_modules&lt;/code&gt; that were added and removed created a ton of noise, making code reviews unpleasant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In comparison, updating a third-party dependency with the Offline Mirror adds just a few files that are very easy to review:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;yarn add shelljs@0.7.0 --dev
yarn add v0.23.2
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;1/4] 🔍  Resolving packages...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;2/4] 🚚  Fetching packages...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;3/4] 🔗  Linking dependencies...
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;4/4] 📃  Building fresh packages...
success Saved lockfile.
success Saved 4 new dependencies.
├─ interpret@1.0.1
├─ rechoir@0.6.2
└─ shelljs@0.7.0
│  └─ glob@7.1.1
✨  Done &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;8.15s.

&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git diff
diff --git a/package.json b/package.json
index 4619f16..7acb42f 100644
--- a/package.json
+++ b/package.json
@@ -220,7 +220,7 @@
     &lt;span class=&quot;s2&quot;&gt;&quot;mock-fs&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;^3.11.0&quot;&lt;/span&gt;,
     &lt;span class=&quot;s2&quot;&gt;&quot;portfinder&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;0.4.0&quot;&lt;/span&gt;,
     &lt;span class=&quot;s2&quot;&gt;&quot;react&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;~15.3.1&quot;&lt;/span&gt;,
-    &lt;span class=&quot;s2&quot;&gt;&quot;shelljs&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;0.6.0&quot;&lt;/span&gt;,
+    &lt;span class=&quot;s2&quot;&gt;&quot;shelljs&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;0.7.0&quot;&lt;/span&gt;,
     &lt;span class=&quot;s2&quot;&gt;&quot;sinon&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;^2.0.0-pre.2&quot;&lt;/span&gt;
   &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
diff --git a/yarn.lock b/yarn.lock
index 11ce116..f5d81ba 100644
--- a/yarn.lock
+++ b/yarn.lock
...
-shelljs@0.6.0:
-  version &lt;span class=&quot;s2&quot;&gt;&quot;0.6.0&quot;&lt;/span&gt;
-  resolved https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.0.tgz#ce1ed837b4b0e55b5ec3dab84251ab9dbdc0c7ec
+shelljs@0.7.0:
+  version &lt;span class=&quot;s2&quot;&gt;&quot;0.7.0&quot;&lt;/span&gt;
+  resolved https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.0.tgz#3f6f2e4965cec565f65ff3861d644f879281a576
+  dependencies:
+    glob &lt;span class=&quot;s2&quot;&gt;&quot;^7.0.0&quot;&lt;/span&gt;
+    interpret &lt;span class=&quot;s2&quot;&gt;&quot;^1.0.0&quot;&lt;/span&gt;
+    rechoir &lt;span class=&quot;s2&quot;&gt;&quot;^0.6.2&quot;&lt;/span&gt;

 shellwords@^0.1.0:
   version &lt;span class=&quot;s2&quot;&gt;&quot;0.1.0&quot;&lt;/span&gt;

&lt;span class=&quot;gp&quot;&gt;$ &lt;/span&gt;git status
On branch testing-yarn
Changes not staged &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;commit:
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;use &lt;span class=&quot;s2&quot;&gt;&quot;git add &amp;lt;file&amp;gt;...&quot;&lt;/span&gt; to update what will be committed&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;use &lt;span class=&quot;s2&quot;&gt;&quot;git checkout -- &amp;lt;file&amp;gt;...&quot;&lt;/span&gt; to discard changes &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;working directory&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

    modified:   package.json
    modified:   yarn.lock

Untracked files:
  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;use &lt;span class=&quot;s2&quot;&gt;&quot;git add &amp;lt;file&amp;gt;...&quot;&lt;/span&gt; to include &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;what will be committed&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

    yarn-offline-mirror/interpret-1.0.1.tgz
    yarn-offline-mirror/rechoir-0.6.2.tgz
    yarn-offline-mirror/shelljs-0.7.0.tgz

no changes added to commit &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;use &lt;span class=&quot;s2&quot;&gt;&quot;git add&quot;&lt;/span&gt; and/or &lt;span class=&quot;s2&quot;&gt;&quot;git commit -a&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 id=&quot;did-you-know-that-yarn-is-also-distributed-as-a-single-bundle-js-file-in-releaseshttpsgithubcomyarnpkgyarnreleases-that-can-be-used-on-ci-systems-without-internet-access&quot;&gt;Did you know that Yarn is also distributed as a single bundle JS file in &lt;a href=&quot;https://github.com/yarnpkg/yarn/releases&quot;&gt;releases&lt;/a&gt; that can be used on CI systems without internet access?&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/posts/2016-11-24-offline-mirror/yarn-offline-blog-releases.png&quot; alt=&quot;Files distributed with Yarn releases&quot; style=&quot;max-width: 700px&quot; /&gt;
**yarn-&lt;version&gt;.js** (for Node 5+) and **yarn-legacy-&lt;version&gt;.js** (for Node 4) can be used stand-alone in CI systems without a need to install it.&lt;/version&gt;&lt;/version&gt;&lt;/p&gt;

&lt;p&gt;Just check it into your project’s repository and use it in the build script:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;pre class=&quot;rougeHighlight&quot;&gt;&lt;code&gt;node ./yarn-0.23.2.js install
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;This is quite convenient for teams that use multiple operating systems and want to have atomic updates for Yarn.&lt;/p&gt;

&lt;h3 id=&quot;this-is-going-to-get-better&quot;&gt;This is going to get better&lt;/h3&gt;

&lt;p&gt;The “Offline mirror” was implemented early in Yarn’s development cycle and we are working on improving it in a backwards compatible way:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;resolved&lt;/code&gt; field is used both for offline mirror paths and registry URIs. This means that the &lt;code class=&quot;highlighter-rouge&quot;&gt;yarn.lock&lt;/code&gt; file that React Native team uses internally can’t be shared with the open source community because the React Native team does not sync the offline mirror with the open source version of React Native. &lt;a href=&quot;https://github.com/yarnpkg/yarn/issues/394&quot;&gt;Issue&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;There is an &lt;a href=&quot;https://github.com/yarnpkg/yarn/issues/393&quot;&gt;improved workflow being considered&lt;/a&gt; for future versions of Yarn. It is not drastically different but some settings and lock files may change.&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 24 Nov 2016 08:00:00 +0000</pubDate>
        <link>https://yarnpkg.com/blog/2016/11/24/offline-mirror/</link>
        <guid isPermaLink="true">https://yarnpkg.com/blog/2016/11/24/offline-mirror/</guid>
        
        
        <category>announcements</category>
        
      </item>
    
  </channel>
</rss>
