<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Zoltan Kochan</title>
    <description>The latest articles on DEV Community by Zoltan Kochan (@zkochan).</description>
    <link>https://dev.to/zkochan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F30682%2Ff45cd99e-568a-448d-8035-d37e02e3f6d5.jpeg</url>
      <title>DEV Community: Zoltan Kochan</title>
      <link>https://dev.to/zkochan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zkochan"/>
    <language>en</language>
    <item>
      <title>2021 pnpm recap</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sat, 01 Jan 2022 21:18:19 +0000</pubDate>
      <link>https://dev.to/pnpm/2021-pnpm-recap-43a3</link>
      <guid>https://dev.to/pnpm/2021-pnpm-recap-43a3</guid>
      <description>&lt;p&gt;It is the end of the year and it was a good year for pnpm, so let's see how it went.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Download stats
&lt;/h3&gt;

&lt;p&gt;My goal this year was to beat Bower by the number of downloads. We were able to achieve this goal &lt;a href="https://npm-stat.com/charts.html?package=pnpm&amp;amp;package=bower&amp;amp;from=2021-01-01&amp;amp;to=2021-12-29" rel="noopener noreferrer"&gt;in November&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fpnpm-vs-bower-stats.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fpnpm-vs-bower-stats.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;pnpm was downloaded about &lt;a href="https://npm-stat.com/charts.html?package=pnpm&amp;amp;from=2016-12-01&amp;amp;to=2021-12-29" rel="noopener noreferrer"&gt;3 times more&lt;/a&gt; in 2021 than in 2020:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fdownload-stats-2021.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fdownload-stats-2021.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These stats don't even measure all the different ways that pnpm may be installed!&lt;br&gt;
They only measure the downloads of the &lt;a href="https://www.npmjs.com/package/pnpm" rel="noopener noreferrer"&gt;pnpm npm package&lt;/a&gt;. This year we also added compiled binary versions of pnpm, which are shipped differently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Docs visits
&lt;/h3&gt;

&lt;p&gt;We collect some unpersonalized stats from our docs using Google Analytics.&lt;br&gt;
In 2021, sometimes we had more than 2,000 unique visitors a week.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fga-unique-visits-2021.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fga-unique-visits-2021.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Most of our users are from the United States and China.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fcountries-2021.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fcountries-2021.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub stars
&lt;/h3&gt;

&lt;p&gt;Our &lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;main GitHub repository&lt;/a&gt; received +5,000 stars this year.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fstars-2021.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpnpm.io%2Fimg%2Fblog%2Fstars-2021.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  New users
&lt;/h3&gt;

&lt;p&gt;Our biggest new user this year is &lt;a href="https://github.com/pnpm/pnpm.github.io/pull/89" rel="noopener noreferrer"&gt;Bytedance&lt;/a&gt; (the company behind TikTok).&lt;/p&gt;

&lt;p&gt;Also, many great open-source projects started to use pnpm. Some switched to pnpm because of its great support of monorepos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/vuejs/vue-next" rel="noopener noreferrer"&gt;Vue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/vitejs/vite" rel="noopener noreferrer"&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and &lt;a href="https://pnpm.io/workspaces#usage-examples" rel="noopener noreferrer"&gt;others&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some switched because they like how efficient, fast, and beautiful pnpm is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://twitter.com/Autoprefixer/status/1476226146488692736" rel="noopener noreferrer"&gt;Autoprefixer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/PostCSS/status/1470438664006258701" rel="noopener noreferrer"&gt;PostCSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://twitter.com/Browserslist/status/1468264308308156419" rel="noopener noreferrer"&gt;Browserslist&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feature highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  New lockfile format (since &lt;a href="https://github.com/pnpm/pnpm/releases/tag/v6.0.0" rel="noopener noreferrer"&gt;v6.0.0&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;One of the first and most important changes this year was the new &lt;code&gt;pnpm-lock.yaml&lt;/code&gt; format. This was a breaking change, so we had to release v6. But it was a success. The old lockfile was causing Git conflicts frequently. Since the new format was introduced, we did not receive any complaints about Git conflicts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Managing Node.js versions (since &lt;a href="https://github.com/pnpm/pnpm/releases/tag/v6.12.0" rel="noopener noreferrer"&gt;v6.12.0&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;We shipped a new command (&lt;code&gt;pnpm env&lt;/code&gt;) that allows to manage Node.js versions. So you may use pnpm instead of Node.js version managers like nvm or Volta.&lt;/p&gt;

&lt;p&gt;Also, pnpm is shipped as a standalone executable, so you can run it even with no Node.js preinstalled on the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Injecting local dependencies (since &lt;a href="https://github.com/pnpm/pnpm/releases/tag/v6.20.0" rel="noopener noreferrer"&gt;v6.20.0&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;You may "inject" a local dependency. By default, local dependencies are symlinked to &lt;code&gt;node_modules&lt;/code&gt; but with this new feature you may instruct pnpm to hard link the files of the package instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improved reporting of peer dependency issues (since &lt;a href="https://github.com/pnpm/pnpm/releases/tag/v6.24.0" rel="noopener noreferrer"&gt;v6.24.0&lt;/a&gt;)
&lt;/h3&gt;

&lt;p&gt;Peer dependency issues used to be printed as plain text and it was hard to understand them. They are now all grouped and printed in a nice hierarchy structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  The competition
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Yarn
&lt;/h3&gt;

&lt;p&gt;Yarn added a pnpm linker in &lt;a href="https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak#new-install-mode-raw-pnpm-endraw-"&gt;v3.1&lt;/a&gt;. So Yarn can create a similar node-modules directory structure to the one that pnpm creates.&lt;/p&gt;

&lt;p&gt;Also, the Yarn team plans to implement a content-addressable storage to be more disk space efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  npm
&lt;/h3&gt;

&lt;p&gt;The npm team decided to also adopt the symlinked node-modules directory structure that pnpm uses (related &lt;a href="https://github.com/npm/rfcs/blob/main/accepted/0042-isolated-mode.md" rel="noopener noreferrer"&gt;RFC&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Others
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://twitter.com/jarredsumner/status/1473416431291174912/photo/1" rel="noopener noreferrer"&gt;Bun&lt;/a&gt; written in Zig and &lt;a href="https://github.com/voltpkg/volt" rel="noopener noreferrer"&gt;Volt&lt;/a&gt; written in Rust both claim to be faster than npm/Yarn/pnpm. I did not benchmark these new package managers yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Plans
&lt;/h2&gt;

&lt;p&gt;Faster, better, best.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>pnpm v4.9 comes with command completion!</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Fri, 31 Jan 2020 20:56:55 +0000</pubDate>
      <link>https://dev.to/pnpm/pnpm-v4-9-comes-with-command-completion-4713</link>
      <guid>https://dev.to/pnpm/pnpm-v4-9-comes-with-command-completion-4713</guid>
      <description>&lt;p&gt;Command completion in bash, zsh, fish is awesome! Unfortunately, even though there are thousands of great command-line tools in the npm registry, I cannot recall any (except the npm CLI) that comes with command completion.&lt;/p&gt;

&lt;p&gt;A few weeks ago &lt;a href="https://github.com/nikoladev"&gt;nikoladev&lt;/a&gt; suggested to &lt;a href="https://github.com/pnpm/pnpm/issues/2229"&gt;implement autompletion in pnpm&lt;/a&gt;. After a brief investigation, I have found a brilliant tool that helps with autocompletion of CLI apps written in Node.js. This tool is called &lt;a href="https://github.com/mklabs/tabtab"&gt;tabtab&lt;/a&gt; and is currently not maintained, so I &lt;a href="https://github.com/pnpm/tabtab"&gt;forked it&lt;/a&gt; and added autocompletions to pnpm👌.&lt;/p&gt;

&lt;p&gt;To set up autocompletion, just update &lt;a href="https://github.com/pnpm/pnpm"&gt;pnpm&lt;/a&gt; to v4.9 and run &lt;code&gt;pnpm install-completion&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's see what you can do with it.&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;pnpm &amp;lt;tab-tab&amp;gt;&lt;/code&gt; and see all the available commands:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fycr3o0khsnx62dxv5b87.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fycr3o0khsnx62dxv5b87.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;pnpm remove &amp;lt;tab-tab&amp;gt;&lt;/code&gt; and see the list of dependencies currently installed. This also works with &lt;code&gt;pnpm update&lt;/code&gt; and &lt;code&gt;pnpm outdated&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn5zj6lk6nnniabxcle1l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fn5zj6lk6nnniabxcle1l.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;pnpm --filter &amp;lt;tab-tab&amp;gt;&lt;/code&gt; and see the list of projects in the workspace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6uuymuc9conrz0umb1zr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6uuymuc9conrz0umb1zr.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;pnpm run &amp;lt;tab-tab&amp;gt;&lt;/code&gt; and see the list of available scripts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frsu3kfm6lo5n0qjnktgv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frsu3kfm6lo5n0qjnktgv.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type any command, type tab-tab and see the list of supported options:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flhosl3mqp71po68jd6re.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flhosl3mqp71po68jd6re.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Type an option and see the possible values:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmw41erm8g48aas5vesqw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmw41erm8g48aas5vesqw.png" alt="Alt Text" width="516" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And these are just a few examples! Happy tabbing😃&lt;/p&gt;

&lt;p&gt;In a future version of pnpm we will also add descriptions to completions😍&lt;/p&gt;

</description>
      <category>pnpm</category>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>pnpm vs Yarn: monorepo node_modules</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sun, 04 Nov 2018 20:12:04 +0000</pubDate>
      <link>https://dev.to/zkochan/pnpm-vs-yarn-monorepo-nodemodules-54hg</link>
      <guid>https://dev.to/zkochan/pnpm-vs-yarn-monorepo-nodemodules-54hg</guid>
      <description>&lt;p&gt;Both &lt;a href="https://pnpm.js.org/" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt; (as of v2.17) and &lt;a href="https://yarnpkg.com/en/" rel="noopener noreferrer"&gt;Yarn&lt;/a&gt; (as of v1.12) support fast, concurrent installations in monorepos. However, there is a big difference between how they store dependencies in monorepos. Yarn tries to hoist all dependencies from all workspace packages into the root &lt;code&gt;node_modules&lt;/code&gt; of the monorepo, which means that packages have access to dependencies of other packages in the workspace. This is described in the &lt;a href="https://yarnpkg.com/lang/en/docs/workspaces/#toc-limitations-caveats" rel="noopener noreferrer"&gt;Yarn docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Be careful when publishing packages in a workspace. If you are preparing your next release and you decided to use a new dependency but forgot to declare it in the package.json file, your tests might still pass locally if another package already downloaded that dependency into the workspace root. However, it will be broken for consumers that pull it from a registry, since the dependency list is now incomplete so they have no way to download the new dependency. Currently, there is no way to throw a warning in this scenario.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like Yarn, pnpm hoists all packages to the root. However, pnpm stores all dependencies in a hidden folder and only links the direct dependencies of every package into their &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's see how Yarn and pnpm work on a simple example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there is a small monorepo with two packages: &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foo&lt;/code&gt; has &lt;code&gt;is-negative@1.0.0&lt;/code&gt; as a dependency&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bar&lt;/code&gt; has &lt;code&gt;is-positive@1.0.0&lt;/code&gt; as a dependency&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Yarn in action
&lt;/h2&gt;

&lt;p&gt;To make this repo work with Yarn, there should be a &lt;code&gt;package.json&lt;/code&gt; in the root of the repo with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"workspaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install all dependencies of all workspace packages, you should run &lt;code&gt;yarn install&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See results &lt;a href="https://github.com/zkochan/comparing-monorepo-node-modules/tree/master/yarn-example" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this case, Yarn will create a single &lt;code&gt;node_modules&lt;/code&gt; in the root of the repo with both &lt;code&gt;is-negative&lt;/code&gt; and &lt;code&gt;is-positive&lt;/code&gt;. It means that both &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; will have access to the dependencies of each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  pnpm in action
&lt;/h2&gt;

&lt;p&gt;To make pnpm install dependencies in this repo, you'll need to create a &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; in the root of the repo (it can be empty) and a &lt;code&gt;.npmrc&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;shared-workspace-shrinkwrap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;link-workspace-packages&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To install all dependencies of all workspace packages with pnpm, you should run &lt;code&gt;pnpm multi install&lt;/code&gt; (or just &lt;code&gt;pnpm m i&lt;/code&gt;).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;See results &lt;a href="https://github.com/zkochan/comparing-monorepo-node-modules/tree/master/pnpm-example" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Like Yarn, pnpm creates a &lt;code&gt;node_modules&lt;/code&gt; in the root of the repo. However, if you open that folder, you'll see that all directories and files are hidden there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
+ .registry.npmjs.org
+ .modules.yaml
+ .shrinkwrap.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;node_modules&lt;/code&gt; stores all the dependencies but they are hidden in &lt;code&gt;.registry.npmjs.org&lt;/code&gt;. Node's resolution algorithm will not find them.&lt;/p&gt;

&lt;p&gt;Now if you check the &lt;a href="https://github.com/zkochan/comparing-monorepo-node-modules/tree/master/pnpm-example/foo" rel="noopener noreferrer"&gt;directory of bar&lt;/a&gt;, you'll see a &lt;code&gt;node_modules&lt;/code&gt; there as well, with a single symlink called &lt;code&gt;is-negative&lt;/code&gt;. This symlink is pointing at &lt;code&gt;../../node_modules/.registry.npmjs.org/is-negative/1.0.0/node_modules/is-negative&lt;/code&gt;. Likewise, there is a symlink to &lt;code&gt;is-positive&lt;/code&gt; in the &lt;code&gt;node_modules&lt;/code&gt; directory of &lt;code&gt;foo&lt;/code&gt;. So &lt;code&gt;foo&lt;/code&gt; is able to resolve only &lt;code&gt;is-positive&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; is only able to resolve &lt;code&gt;is-negative&lt;/code&gt; 🎉😊&lt;/p&gt;




&lt;p&gt;As you can see, pnpm is strict &lt;a href="https://medium.com/pnpm/pnpms-strictness-helps-to-avoid-silly-bugs-9a15fb306308" rel="noopener noreferrer"&gt;not only when used with a single &lt;code&gt;package.json&lt;/code&gt;&lt;/a&gt; but also in a multi-package repository.&lt;/p&gt;

</description>
      <category>pnpm</category>
      <category>yarn</category>
      <category>monorepo</category>
    </item>
    <item>
      <title>It is OK to keep random things in a single monorepo</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Mon, 22 Oct 2018 22:21:34 +0000</pubDate>
      <link>https://dev.to/zkochan/it-is-ok-to-keep-random-things-in-a-single-monorepo-566e</link>
      <guid>https://dev.to/zkochan/it-is-ok-to-keep-random-things-in-a-single-monorepo-566e</guid>
      <description>&lt;p&gt;For a long time, I was an opponent of monorepos. There are many popular open source contributors that have hundreds of packages on npm and each of those packages have a dedicated GitHub repository. I thought everyone does it this way, so it should be the right way! No?&lt;/p&gt;

&lt;p&gt;I started to publish some things to npm as well and after a few years, I have now almost 300 packages in the registry. It took me a long time but I realized, the &lt;em&gt;majority&lt;/em&gt; of npm packages don't need dedicated repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  Most of the npm packages are almost never updated
&lt;/h2&gt;

&lt;p&gt;Once a package is ready, you will probably never update it again. The only time you will need to update a package is when Renovate or Greenkeeper will open a PR to update dependencies that had major version changes.&lt;/p&gt;

&lt;p&gt;So why create a dedicated repository for a package that will have less than 10 useful commits?&lt;/p&gt;

&lt;h2&gt;
  
  
  Most of the npm packages never get any contributions
&lt;/h2&gt;

&lt;p&gt;Even popular packages get few contributions. Certainly, you will be &lt;em&gt;the only&lt;/em&gt; contributor of your non-popular packages.&lt;/p&gt;

&lt;p&gt;So why keeping a separate GitHub repository? There will be no other developers that will need admin permissions to a given npm package.&lt;/p&gt;

&lt;h2&gt;
  
  
  It is OK, use one repo!
&lt;/h2&gt;

&lt;p&gt;You might think: "but those packages are completely unrelated". And that is true. But that is the only downside: keeping random packages in a single repository. Think about all the advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer notifications from Greenkeeper/Renovate&lt;/li&gt;
&lt;li&gt;less CI setup&lt;/li&gt;
&lt;li&gt;less boilerplate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additional advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you can use services that limit the number of repositories you use.&lt;/li&gt;
&lt;li&gt;you can easily migrate all your code to other git servers because there is only one repository to migrate&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to
&lt;/h2&gt;

&lt;p&gt;My recipe is using the &lt;a href="https://pnpm.js.org/docs/en/pnpm-recursive.html" rel="noopener noreferrer"&gt;recursive commands&lt;/a&gt; of &lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt; to install all dependencies of your packages and run their tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm recursive install
pnpm recursive test --workspace-concurrency 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you may also use &lt;a href="https://rushjs.io/" rel="noopener noreferrer"&gt;Rush&lt;/a&gt;, &lt;a href="https://github.com/lerna/lerna/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt;, or other monorepo managing tools.&lt;/p&gt;

&lt;p&gt;To see how I moved some of my packages to a single repo, see &lt;a href="https://github.com/zkochan/packages" rel="noopener noreferrer"&gt;zkochan/packages&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can always create a dedicated repository later
&lt;/h2&gt;

&lt;p&gt;If one of your packages will receive a lot of attention, you can always move it to a dedicated repository later.&lt;/p&gt;




&lt;p&gt;Photo by Olav Ahrens Røtne on Unsplash&lt;/p&gt;

</description>
      <category>monorepo</category>
      <category>javascript</category>
      <category>node</category>
      <category>npm</category>
    </item>
    <item>
      <title>pnpm vs Lerna: filtering in a multi-package repository</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sun, 02 Sep 2018 21:53:00 +0000</pubDate>
      <link>https://dev.to/zkochan/pnpm-vs-lerna-filtering-in-a-multi-package-repository-587i</link>
      <guid>https://dev.to/zkochan/pnpm-vs-lerna-filtering-in-a-multi-package-repository-587i</guid>
      <description>&lt;p&gt;Everyone heard about &lt;a href="https://github.com/lerna/lerna/" rel="noopener noreferrer"&gt;Lerna&lt;/a&gt;, which is "A tool for managing JavaScript projects with multiple packages." A lot fewer devs heard about &lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt;, which is a fast, disk space efficient package manager for JavaScript. Both Lerna and pnpm try to improve tooling for multi-package repositories (MPR). For Lerna it was the reason for creation. For pnpm, MPR support is a nice bonus feature that is implemented via a set of commands called &lt;a href="https://pnpm.js.org/en/cli/recursive" rel="noopener noreferrer"&gt;recursive&lt;/a&gt;. Of course, there are many differences between how Lerna manages a multi-package repo vs pnpm. In this article, I want to compare one seemingly simple aspect: filtering.&lt;/p&gt;

&lt;p&gt;Filtering in an MPR is important because, during development, changes are mainly made inside one or two packages. It wouldn't make sense to run commands on the whole repository if only a few packages were modified.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v8af8krvqumdz6g76bm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2v8af8krvqumdz6g76bm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering in Lerna
&lt;/h2&gt;

&lt;p&gt;Filtering in Lerna (as of &lt;code&gt;v3.2.1&lt;/code&gt;) is achieved by the following flags:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt; - Include only packages with names matching the given glob.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;include-filtered-dependents&lt;/code&gt; - Include all transitive dependents when running a command regardless of &lt;code&gt;--scope&lt;/code&gt;, &lt;code&gt;--ignore&lt;/code&gt;, or &lt;code&gt;--since&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;include-filtered-dependencies&lt;/code&gt; - Include all transitive dependencies when running a command regardless of &lt;code&gt;--scope&lt;/code&gt;, &lt;code&gt;--ignore&lt;/code&gt;, or &lt;code&gt;--since&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ignore&lt;/code&gt; - Exclude packages with names matching the given glob.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;private&lt;/code&gt; - Include private packages. Pass --no-private to exclude private packages.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;since&lt;/code&gt; - Only include packages that have been updated since the specified [ref]. If no ref is passed, it defaults to the most recent tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These flags make filtering in Lerna quiet powerful. However, they are pretty hard to type. Let's say you downloaded a repository and want to work only on &lt;code&gt;login-page&lt;/code&gt; component. You'd want to run installation for &lt;code&gt;login-page&lt;/code&gt; and any of its dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lerna bootstrap &lt;span class="nt"&gt;--scope&lt;/span&gt; login-page &lt;span class="nt"&gt;--include-filtered-dependencies&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or maybe you changed a component called &lt;code&gt;site-header&lt;/code&gt; and would like to run tests on all the dependent packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;lerna run &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--scope&lt;/span&gt; site-header &lt;span class="nt"&gt;--include-filtered-dependents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These flags are not only hard to type but also hard to remember and easy to mix up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyxxeeafuh90kbu3wma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfyxxeeafuh90kbu3wma.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filtering in pnpm
&lt;/h2&gt;

&lt;p&gt;Unlike Lerna, pnpm uses a special package selector syntax to restrict its commands. So instead of memorizing a set of long flag names, you should only remember a very easy-to-remember selector syntax.&lt;/p&gt;

&lt;p&gt;As of version &lt;code&gt;2.15.0&lt;/code&gt;, these are the selectors that pnpm supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;pattern&amp;gt;&lt;/code&gt; - Restricts the scope to package names matching the given pattern. E.g.: &lt;code&gt;foo&lt;/code&gt;, &lt;code&gt;@bar/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;pattern&amp;gt;...&lt;/code&gt; - Includes all direct and indirect dependencies of the matched packages. E.g.: &lt;code&gt;foo...&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;...&amp;lt;pattern&amp;gt;&lt;/code&gt; - Includes all direct and indirect dependents of the matched packages. E.g.: &lt;code&gt;...foo&lt;/code&gt;, &lt;code&gt;...@bar/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;./&amp;lt;directory&amp;gt;&lt;/code&gt; - Includes all packages that are inside a given subdirectory. E.g.: &lt;code&gt;./components&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.&lt;/code&gt; - Includes all packages that are under the current working directory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These filters may be specified either via the &lt;code&gt;--filter&lt;/code&gt; flag or after a &lt;code&gt;--&lt;/code&gt;at the end of the command.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: as of &lt;code&gt;v2.15.0&lt;/code&gt;, filters after &lt;code&gt;--&lt;/code&gt; are not supported by &lt;code&gt;run&lt;/code&gt;, &lt;code&gt;exec&lt;/code&gt;, &lt;code&gt;test&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So if you want to bootstrap &lt;code&gt;login-page&lt;/code&gt; and all of its dependencies, this is the way you do it with pnpm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm recursive &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; login-page...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you want to run tests of &lt;code&gt;site-header&lt;/code&gt; and all of its dependents, use the &lt;code&gt;...&amp;lt;pattern&amp;gt;&lt;/code&gt; selector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm recursive &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--filter&lt;/span&gt; ...site-header
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you can combine as many selectors as you'd like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pnpm recursive update -- ...site-header login-page... ./utils @style/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command above updates dependencies in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;site-header&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;dependents of &lt;code&gt;site-header&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;login-page&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;dependencies of &lt;code&gt;login-page&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;all packages that are located in the &lt;code&gt;utils&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;all packages from the &lt;code&gt;@style&lt;/code&gt; scope&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;pnpm might not have yet all the features that Lerna provides but for many users it might be enough already.&lt;/p&gt;

&lt;p&gt;If you haven't heard about pnpm yet, I recommend reading also &lt;a href="https://medium.com/pnpm/flat-node-modules-is-not-the-only-way-d2e40f7296a3" rel="noopener noreferrer"&gt;Flat node_modules is not the only way&lt;/a&gt; which explains the unique node_modules structure created by pnpm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheatsheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lerna v3.2&lt;/th&gt;
&lt;th&gt;pnpm v2.15&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;--scope my-component&lt;/td&gt;
&lt;td&gt;-- my-component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;--scope toolbar-*&lt;/td&gt;
&lt;td&gt;-- toolbar-*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;--scope my-component --include-filtered-dependencies&lt;/td&gt;
&lt;td&gt;-- my-component...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;--scope my-component --include-filtered-dependents&lt;/td&gt;
&lt;td&gt;-- ...my-component&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;em&gt;originally posted in &lt;a href="https://medium.com/pnpm/pnpm-vs-lerna-filtering-in-a-multi-package-repository-1f68bc644d6a" rel="noopener noreferrer"&gt;pnpm blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pnpm</category>
      <category>javascript</category>
      <category>node</category>
      <category>multipackagerepo</category>
    </item>
    <item>
      <title>The not fancy CLI output of pnpm</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sun, 26 Aug 2018 21:36:57 +0000</pubDate>
      <link>https://dev.to/zkochan/the-not-fancy-cli-output-of-pnpm-36ao</link>
      <guid>https://dev.to/zkochan/the-not-fancy-cli-output-of-pnpm-36ao</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt; is a JavaScript package manager that differs from npm and Yarn in many ways. If you haven't heard about it yet, I recommend checking it out. In this article, I would love to write about the design system that we use to report during installation.&lt;/p&gt;

&lt;p&gt;When I first started contributing to pnpm (around &lt;code&gt;v0.15&lt;/code&gt;), this is how an installation was reported:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27ljrz12fqycm8gjqp3d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27ljrz12fqycm8gjqp3d.gif" width="638" height="259"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It wasn't really useful but some users of pnpm liked it. They thought it was beautiful. But then as we started adding more features, we realized that it is very important to print the right amount of information in a nice readable format.&lt;/p&gt;

&lt;p&gt;So let's see how pnpm has evolved and how it reports in different scenarios as of &lt;code&gt;v2.13.6&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reporting installation in a single project
&lt;/h2&gt;

&lt;p&gt;When you first install pnpm and you run &lt;code&gt;pnpm install&lt;/code&gt; in a project, you'll see an output like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut9r3katnf7u3l3v8ojc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut9r3katnf7u3l3v8ojc.png" width="800" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike the old output, this one is very static and minimalistic but it contains a lot more useful information.&lt;/p&gt;

&lt;p&gt;We see that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one of the installed packages is deprecated&lt;/li&gt;
&lt;li&gt;117 new packages were added to &lt;code&gt;node_modules&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Installation slowed down a bit because the huge typescript tarball was being downloaded&lt;/li&gt;
&lt;li&gt;0 packages were available in the store, so all 117 packages were downloaded (pnpm saves one version of a package only ever once on a disk, so when a package is available in the store, it is just hard linked to the &lt;code&gt;node_modules&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;express@4.16.0&lt;/code&gt; was added as a production dependency&lt;/li&gt;
&lt;li&gt;a newer version of express is available in the registry&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;babel-preset-es2015@6.24.1&lt;/code&gt; and &lt;code&gt;typescript@3.0.1&lt;/code&gt; were added as dev dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now lets update express to the latest version and see what we get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ften47xvs12eykm88tmk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ften47xvs12eykm88tmk0.png" width="458" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;5 packages were removed from node_modules&lt;/li&gt;
&lt;li&gt;5 packages were added to node_modules&lt;/li&gt;
&lt;li&gt;all 5 packages were downloaded from the registry&lt;/li&gt;
&lt;li&gt;the newest express was added to the project&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reporting installation in a multi-package repository
&lt;/h2&gt;

&lt;p&gt;pnpm has a set of commands for working with multi-package repositories (MPR). When installing dependencies in an MPR, the amount of information that is being processed is so big that printing all of it would just make an unreadable mess. In order to provide some basic information anyway, we came out with the concept of zoomed-out reporting. A zoomed-out reporting contains just the most important pieces of information.&lt;/p&gt;

&lt;p&gt;Every package in the MPR is printed with the number of added/removed packages (inspired by Git):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn1iuaw710s3hs8uxnuh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjn1iuaw710s3hs8uxnuh.png" width="684" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Zoomed-out reporting also prints warnings (only warnings, no info messages):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojjpfjmmzjmw3j62qwj9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojjpfjmmzjmw3j62qwj9.png" width="711" height="228"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we came out with the concept of zoomed-out reporting for the &lt;a href="https://pnpm.js.org/docs/en/pnpm-recursive.html" rel="noopener noreferrer"&gt;recursive commands&lt;/a&gt;, we realized that there are other scenarios in which they are useful. For instance, when packages are linked in, it should be a mixture of zoomed-out and zoomed-in reporting. Packages that are linked in should be reported briefly and the package in the current working directory should be in focus:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdvlw207kppbwagc3p7h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdvlw207kppbwagc3p7h.png" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation details
&lt;/h2&gt;

&lt;p&gt;Although the output seems minimalistic and simple, it is produced by a very complex system. pnpm consists of many components and many operations may happen in random order (this is one of the reasons pnpm is &lt;a href="https://github.com/pnpm/node-package-manager-benchmark#readme" rel="noopener noreferrer"&gt;so fast&lt;/a&gt;). That is why reporting is performed by a specialized part of pnpm called "reporter" (&lt;a href="https://github.com/pnpm/pnpm/tree/master/packages/default-reporter" rel="noopener noreferrer"&gt;code&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The reporter is a package that listens for logs, filters them, combines and forms an output from them. pnpm uses &lt;a href="https://github.com/rvagg/bole" rel="noopener noreferrer"&gt;bole&lt;/a&gt; to pass the logs from the loggers to the reporter. This modularization is great because we can mock the logs and cover reporting with tests!&lt;/p&gt;

&lt;p&gt;For printing the output to the console, we use &lt;a href="https://github.com/mafintosh/ansi-diff" rel="noopener noreferrer"&gt;ansi-diff&lt;/a&gt;. &lt;code&gt;ansi-diff&lt;/code&gt; is great because it accepts "frames" of output and it updates only those parts of the console that are changed (and it is fast). Before we switched to &lt;code&gt;ansi-diff&lt;/code&gt;, we used another popular library for updating the console output but it was doing the update with noticeable flickering.&lt;/p&gt;

&lt;h2&gt;
  
  
  P.S.
&lt;/h2&gt;

&lt;p&gt;It is very hard to implement good CLI reporting. But good reporting allows developers to focus on the important things and possibly notice issues earlier.&lt;/p&gt;

&lt;p&gt;Of course, pnpm's reporting can improved a lot and we have many &lt;a href="https://github.com/pnpm/pnpm/issues?q=is%3Aissue+is%3Aopen+label%3A%22area%3A+reporting%22" rel="noopener noreferrer"&gt;open issues&lt;/a&gt; in that area. Give pnpm a try and don't hesitate to let us know if there are things that can be improved further.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;originally posted in the &lt;a href="https://medium.com/pnpm/the-not-fancy-cli-output-of-pnpm-5bd4398716ce" rel="noopener noreferrer"&gt;pnpm blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>pnpm</category>
      <category>javascript</category>
      <category>node</category>
      <category>npm</category>
    </item>
    <item>
      <title>Flat node_modules is not the only way</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sun, 24 Jun 2018 18:24:17 +0000</pubDate>
      <link>https://dev.to/zkochan/flat-nodemodules-is-not-the-only-way-mo2</link>
      <guid>https://dev.to/zkochan/flat-nodemodules-is-not-the-only-way-mo2</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article covers an old version of pnpm. For an updated version of the article &lt;a href="https://pnpm.js.org/blog/2020/05/27/flat-node-modules-is-not-the-only-way" rel="noopener noreferrer"&gt;go here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;New users of &lt;a href="https://pnpm.js.org/" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt; frequently ask me about the weird structure of &lt;code&gt;node_modules&lt;/code&gt; that pnpm creates. Why is it not flat? Where are all the sub-dependencies?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am going to assume that readers of the article are already familiar with flat &lt;code&gt;node_modules&lt;/code&gt; created by npm and Yarn. If you don't understand why npm 3 had to start using flat &lt;code&gt;node_modules&lt;/code&gt; in v3, you can find some prehistory in &lt;a href="https://www.kochan.io/nodejs/why-should-we-use-pnpm.html" rel="noopener noreferrer"&gt;Why should we use pnpm?&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So why is pnpm's &lt;code&gt;node_modules&lt;/code&gt; unusual? Let's create two directories and run &lt;code&gt;npm install express&lt;/code&gt; in one of them and &lt;code&gt;pnpm install express&lt;/code&gt; in the other one. Here's the top of what you get in the first directory's &lt;code&gt;node_modules&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwawdb7l130w8alzohmc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwawdb7l130w8alzohmc4.png" width="166" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the whole directory &lt;a href="https://github.com/zkochan/comparing-node-modules/tree/master/npm-example/node_modules" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And this is what you get in the &lt;code&gt;node_modules&lt;/code&gt; created by pnpm:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhlxa55h881hy7reps5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyhlxa55h881hy7reps5h.png" alt="pnpm node_modules" width="176" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check it &lt;a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm-example/node_modules" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So where are all the dependencies? There is only one folder in the &lt;code&gt;node_modules&lt;/code&gt; called &lt;code&gt;.registry.npmjs.org&lt;/code&gt; and a symlink called &lt;code&gt;express&lt;/code&gt;. Well, we installed only &lt;code&gt;express&lt;/code&gt;, so that is the only package that your application has to have access to &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read more about why pnpm's strictness is a good thing &lt;a href="https://medium.com/pnpm/pnpms-strictness-helps-to-avoid-silly-bugs-9a15fb306308" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's see what is inside &lt;code&gt;express&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoagvcxd6rv391s4l9cg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpoagvcxd6rv391s4l9cg.png" width="154" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;express&lt;/code&gt; has no &lt;code&gt;node_modules&lt;/code&gt;? Where are all the dependencies of &lt;code&gt;express&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The trick is that &lt;code&gt;express&lt;/code&gt; is just a symlink. When Node.js resolves dependencies, it uses their real locations, so it does not preserve symlinks. But where is the real location of &lt;code&gt;express&lt;/code&gt;, you might ask?&lt;/p&gt;

&lt;p&gt;Here: &lt;a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm-example/node_modules/.registry.npmjs.org/express/4.16.3/node_modules/express" rel="noopener noreferrer"&gt;node_modules/.registry.npmjs.org/express/4.16.3/node_modules/express&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OK, so now we know the purpose of the &lt;code&gt;.registry.npmjs.org/&lt;/code&gt; folder. &lt;code&gt;.registry.npmjs.org/&lt;/code&gt; stores all the packages in a flat folder structure, so every package can be found in a folder named by this pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.registry.npmjs.org/&amp;lt;name&amp;gt;/&amp;lt;version&amp;gt;/node_modules/&amp;lt;name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This flat structure avoids the long path issues that were caused by the nested &lt;code&gt;node_modules&lt;/code&gt; created by npm v2 but keeps packages isolated unlike the flat &lt;code&gt;node_modules&lt;/code&gt; created by npm v3,4,5,6.&lt;/p&gt;

&lt;p&gt;Now let's look into the real location of &lt;code&gt;express&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe86p8cxwpwgs8w1noqvj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe86p8cxwpwgs8w1noqvj.png" width="121" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Is it a scam? It still lacks &lt;code&gt;node_modules&lt;/code&gt;! The second trick of pnpm's &lt;code&gt;node_modules&lt;/code&gt; structure is that the dependencies of packages are on the same directory level on which the real location of the dependent package. So dependencies of &lt;code&gt;express&lt;/code&gt; are not in &lt;code&gt;/express/4.16.4/node_modules/express/node_modules/&lt;/code&gt; but in &lt;a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm-example/node_modules/.registry.npmjs.org/express/4.16.3/node_modules" rel="noopener noreferrer"&gt;/express/4.16.4/node_modules/&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7r5g9vbonq0urezaeyk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp7r5g9vbonq0urezaeyk.png" width="173" height="547"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All the dependencies of &lt;code&gt;express&lt;/code&gt; are symlinks to appropriate directories in &lt;code&gt;node_modules/.registry.npmjs.org/&lt;/code&gt;. Placing dependencies of &lt;code&gt;express&lt;/code&gt; one level up allows avoiding circular symlinks.&lt;/p&gt;

&lt;p&gt;So as you can see, even though pnpm's &lt;code&gt;node_modules&lt;/code&gt; structure seems unusual at first&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it is completely Node.js compatible&lt;/li&gt;
&lt;li&gt;packages are nicely grouped with their dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The structure is a little bit &lt;a href="https://pnpm.js.org/docs/en/how-peers-are-resolved.html" rel="noopener noreferrer"&gt;more complex&lt;/a&gt; for packages with peer dependencies but the idea is the same: using symlinks to create a nesting with a flat directory structure.&lt;/p&gt;




&lt;p&gt;If you'd like to try out &lt;a href="https://github.com/pnpm/pnpm/" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt;, you can easily install it with npm: &lt;code&gt;npm i -g pnpm&lt;/code&gt;. Then just run it instead of npm when you need to install something: &lt;code&gt;pnpm install foo bar&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>pnpm</category>
      <category>npm</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Why package managers need hook systems</title>
      <dc:creator>Zoltan Kochan</dc:creator>
      <pubDate>Sat, 02 Sep 2017 22:20:07 +0000</pubDate>
      <link>https://dev.to/zkochan/why-package-managers-need-hook-systems</link>
      <guid>https://dev.to/zkochan/why-package-managers-need-hook-systems</guid>
      <description>&lt;p&gt;Installation hooks were introduced to &lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm&lt;/a&gt; in &lt;a href="https://github.com/pnpm/pnpm/releases/tag/v1.12.0" rel="noopener noreferrer"&gt;version 1.12&lt;/a&gt;. In this article, I want to write about why I think package managers (PMs) need hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would we want to hook into &lt;code&gt;node_modules&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;When installing dependencies of a Node-project, the &lt;code&gt;node_modules&lt;/code&gt; structure is 100% controlled by the &lt;code&gt;package.json&lt;/code&gt; files of the dependencies (a.k.a. manifests). So if your project depends on &lt;code&gt;foo@1.0.0&lt;/code&gt; which depends on &lt;code&gt;bar@2.0.0&lt;/code&gt; then you’ll be going to have two dependencies installed in your &lt;code&gt;node_modules&lt;/code&gt;. While you can change your project’s dependency set, you don’t have control over the manifests of your dependencies.&lt;/p&gt;

&lt;p&gt;A typical dependency tree is huge and you have no ownership over the majority of your dependencies. Just analyze any of your dependencies at &lt;a href="http://npm.anvaka.com" rel="noopener noreferrer"&gt;npm.anvaka.com&lt;/a&gt;. For instance, this is the dependency graph of &lt;code&gt;browserify&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FrynJysq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FrynJysq.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What to do if there is a bug in one of the packages inside your &lt;code&gt;node_modules&lt;/code&gt;? If the issue is in a root dependency, then you have 3 options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; find an alternative, more reliable package&lt;/li&gt;
&lt;li&gt; submit a pull request (PR) that fixes the issue&lt;/li&gt;
&lt;li&gt; create your own package and use it instead of the buggy one&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 2nd option seems to be the correct one and I encourage everyone to contribute as frequently as possible. However, submitting a PR doesn’t mean that your changes will be merged/published. Even if they will be merged and published, it won’t happen immediately, you might have to wait for years. Here are some frequent issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  the project is unmaintained/poorly maintained&lt;/li&gt;
&lt;li&gt;  you did breaking changes and the author doesn’t like bumping major versions. The author will wait for several breaking changes to come in, before publishing a major version&lt;/li&gt;
&lt;li&gt;  the author thinks the bug is not a bug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the problematic package is a root dependency, then you can easily switch to another package or to your fork. The problem is match harder to solve if the package is a sub-dependency. In that case, your options are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; submit a PR that fixes the issue&lt;/li&gt;
&lt;li&gt; submit many PRs to packages that depend on the buggy package&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With hooks though, you can have a third option: create a fork and install it instead of the problematic package. So if you have &lt;code&gt;foo@1.0.0&lt;/code&gt; that depends on &lt;code&gt;bar@2.0.0&lt;/code&gt; you can have a hook that will override the dependency.&lt;/p&gt;

&lt;p&gt;Let’s say there is a bug in &lt;code&gt;bar@2.0.0&lt;/code&gt; and you submitted a PR with a fix. However, the maintainer of bar is on vacation. You can use a hook to make pnpm install bar from your PR branch instead of &lt;code&gt;bar@2.0.0&lt;/code&gt; from the npm registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hooks are important for pnpm’s survival
&lt;/h2&gt;

&lt;p&gt;Hooks are nice to have in any PM but for pnpm they are especially important. As you may know already, pnpm creates a strict symlinked node_modules structure. You can read more about it in: &lt;a href="https://medium.com/pnpm/pnpms-strictness-helps-to-avoid-silly-bugs-9a15fb306308" rel="noopener noreferrer"&gt;pnpm’s strictness helps to avoid silly bugs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the &lt;code&gt;node_modules&lt;/code&gt; structure created by pnpm is Node.js-compatible, many packages have bugs that show up only when installed via pnpm. As a consequence, pnpm has issues with some popular frameworks and tools.&lt;/p&gt;

&lt;p&gt;Of course, we try to solve these issues via PRs (I want to give a shout out to &lt;a href="https://github.com/aecz" rel="noopener noreferrer"&gt;aecz&lt;/a&gt; who managed to fix many such issues in Angular). But besides the usual issues, some of the maintainers are hostile and refuse to accept PRs just because they don’t like pnpm or believe that the flat &lt;code&gt;node_modules&lt;/code&gt; created by npm/Yarn is a feature (it is not).&lt;/p&gt;

&lt;p&gt;In the end, we have two options to fix the ecosystem for the strict pnpm:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; make pnpm popular enough. In that case, authors of frameworks/toolings will be testing their product with pnpm as well as npm and Yarn.&lt;/li&gt;
&lt;li&gt; make a hook system to temporarily substitute the buggy packages that don’t work with pnpm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;IMHO, the 1st scenario is pretty much impossible. pnpm can’t become popular without being a drop-in replacement for npm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-life example
&lt;/h2&gt;

&lt;p&gt;There is a popular package called &lt;a href="https://github.com/browserify/resolve" rel="noopener noreferrer"&gt;resolve&lt;/a&gt; for resolving dependencies from &lt;code&gt;node_modules&lt;/code&gt; (1,3K dependents, 765K downloads a day). Unfortunately for pnpm, &lt;code&gt;resolve&lt;/code&gt; preserves symlinks when resolving modules. This is an issue on resolve’s end as Node.js does not preserve symlinks during resolution. I did a &lt;a href="https://github.com/browserify/resolve/pull/131" rel="noopener noreferrer"&gt;PR&lt;/a&gt; to fix this issue and now resolve from version 1.4 has an option to not preserve symlinks.&lt;/p&gt;

&lt;p&gt;This does not solve the problem for pnpm though. We can’t submit PRs to the 1.3K dependent packages to update &lt;code&gt;resolve&lt;/code&gt; and pass &lt;code&gt;preserverSymlink: false&lt;/code&gt; to it. The lead maintainer of resolve agreed to switch the option’s default value in the next major version. So I hoped Greenkeeper would create the PRs for us and most of the packages would update resolve to version 2.&lt;/p&gt;

&lt;p&gt;I created another &lt;a href="https://github.com/browserify/resolve/pull/135" rel="noopener noreferrer"&gt;PR&lt;/a&gt; with the breaking change but resolve’s maintainer wants to wait for more breaking changes before changing resolve to version 2.&lt;/p&gt;

&lt;p&gt;I realized that we cannot change the world but we can change pnpm, so I released the &lt;code&gt;readPackage&lt;/code&gt; hook. My changes to resolve are available via my fork on GitHub, so all we have to do is to tell pnpm to install resolve from the fork. This can be done by declaring the hook in a file called &lt;code&gt;pnpmfile.js&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;During installation, pnpm will pass every &lt;code&gt;package.json&lt;/code&gt; to this hook first and use the version of the &lt;code&gt;package.json&lt;/code&gt; returned by the hook. So it won’t matter on which version of resolve the package depends, my fork will be installed instead and the project will work fine with pnpm.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I did not describe all the use cases when the &lt;code&gt;readPackage&lt;/code&gt; can be useful. It is a really powerful tool and I think we’ll learn how to use it smartly.&lt;/p&gt;

&lt;p&gt;Also, I want to say thanks to &lt;a href="https://medium.com/u/334c14ed4bfc" rel="noopener noreferrer"&gt;Andrei Neculau&lt;/a&gt;, who convinced me that this hook-system was a good idea.&lt;/p&gt;

&lt;p&gt;To make it a little bit interactive, check how many unresolved PRs you have on GitHub and post the number in the comments section. You can use &lt;a href="https://github.com/pulls" rel="noopener noreferrer"&gt;this link&lt;/a&gt; to see all your open PRs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Do you want to give pnpm a try?
&lt;/h2&gt;

&lt;p&gt;Just install pnpm via npm: &lt;code&gt;npm install -g pnpm&lt;/code&gt;. And use it instead of npm whenever you want to install something: &lt;code&gt;pnpm i foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also, you can read more info at the &lt;a href="https://github.com/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm GitHub repo&lt;/a&gt; or &lt;a href="https://pnpm.js.org/" rel="noopener noreferrer"&gt;pnpm.js.org&lt;/a&gt;. You can follow &lt;a href="https://twitter.com/pnpmjs" rel="noopener noreferrer"&gt;pnpm on Twitter&lt;/a&gt; or ask for help at the &lt;a href="https://gitter.im/pnpm/pnpm" rel="noopener noreferrer"&gt;pnpm Gitter Chat Room&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post was originally published on &lt;a href="https://www.kochan.io/nodejs/why-package-managers-need-hook-systems.html" rel="noopener noreferrer"&gt;kochan.io&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>pnpm</category>
      <category>npm</category>
    </item>
  </channel>
</rss>
