<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://pnpm.io/pnpm/blog</id>
    <title>pnpm Blog</title>
    <updated>2022-12-30T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://pnpm.io/pnpm/blog"/>
    <subtitle>pnpm Blog</subtitle>
    <icon>https://pnpm.io/pnpm/img/favicon.png</icon>
    <entry>
        <title type="html"><![CDATA[The year 2022 for pnpm]]></title>
        <id>https://pnpm.io/pnpm/blog/2022/12/30/yearly-update</id>
        <link href="https://pnpm.io/pnpm/blog/2022/12/30/yearly-update"/>
        <updated>2022-12-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[It is the end of the year. A really hard year. As you may know, I live in Ukraine, so due to Russia's war against us, it was harder to lead this project than in previous years. Nevertheless, it was a good year for pnpm. We've got a lot of new users, contributors, and we have implemented many great features.]]></summary>
        <content type="html"><![CDATA[<p>It is the end of the year. A really hard year. As you may know, I live in Ukraine, so due to Russia's war against us, it was harder to lead this project than in previous years. Nevertheless, it was a good year for pnpm. We've got a lot of new users, contributors, and we have implemented many great features.</p><p><img loading="lazy" src="/pnpm/assets/images/2022-review-092f8f0dfe82b760c2e90fd776d82f75.png" width="640" height="640" class="img_XicP"></p><p>(the above illustration was generated by Midjourney. The tiger symolizes the year of the tiger)</p><h2 class="anchor anchorWithStickyNavbar_M9ON" id="usage">Usage<a href="#usage" class="hash-link" aria-label="Direct link to Usage" title="Direct link to Usage">​</a></h2><h3 class="anchor anchorWithStickyNavbar_M9ON" id="download-stats">Download Stats<a href="#download-stats" class="hash-link" aria-label="Direct link to Download Stats" title="Direct link to Download Stats">​</a></h3><p>My goal this year was to beat Lerna by the number of downloads. We were able to achieve this goal <a href="https://npm-stat.com/charts.html?package=pnpm&amp;package=lerna&amp;from=2022-01-01&amp;to=2022-12-30" target="_blank" rel="noopener noreferrer">in August</a>:</p><p><img loading="lazy" src="/pnpm/assets/images/pnpm-vs-lerna-stats-cad28f3b9685ef684c864f919f7f9c5e.png" width="997" height="400" class="img_XicP"></p><p>pnpm was downloaded more than <a href="https://npm-stat.com/charts.html?package=pnpm&amp;from=2016-12-01&amp;to=2022-12-30" target="_blank" rel="noopener noreferrer">5 times more</a> in 2022 than in 2021:</p><p><img loading="lazy" src="/pnpm/assets/images/download-stats-2022-e4de79bf61e1066802166f9d97cb36ac.png" width="997" height="400" class="img_XicP"></p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="docs-visits">Docs visits<a href="#docs-visits" class="hash-link" aria-label="Direct link to Docs visits" title="Direct link to Docs visits">​</a></h3><p>We collect some unpersonalized stats from our docs using Google Analytics.
In 2022, sometimes we had more than 20,000 unique visitors a week. This is 10 times more than in 2021!</p><p><img loading="lazy" src="/pnpm/assets/images/ga-unique-visits-2022-b2e9bf0b6c559a5c59fdbfd8bb1861f0.png" width="778" height="391" class="img_XicP"></p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="github-stars">GitHub stars<a href="#github-stars" class="hash-link" aria-label="Direct link to GitHub stars" title="Direct link to GitHub stars">​</a></h3><p>Our <a href="https://github.com/pnpm/pnpm" target="_blank" rel="noopener noreferrer">main GitHub repository</a> received almost +7,000 stars this year.</p><p><img loading="lazy" src="/pnpm/assets/images/stars-2022-434ca95e6da688fdff1bb1bf89d6a2d9.png" width="584" height="787" class="img_XicP"></p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="our-contributors">Our contributors<a href="#our-contributors" class="hash-link" aria-label="Direct link to Our contributors" title="Direct link to Our contributors">​</a></h3><p>We had a lot of new and active contributors this year. These are the people the merge at least one PR in 2022:</p><ul><li><a href="https://github.com/zkochan" target="_blank" rel="noopener noreferrer">Zoltan Kochan</a></li><li><a href="https://github.com/lvqq" target="_blank" rel="noopener noreferrer">chlorine</a></li><li><a href="https://github.com/await-ovo" target="_blank" rel="noopener noreferrer">await-ovo</a></li><li><a href="https://github.com/gluxon" target="_blank" rel="noopener noreferrer">Brandon Cheng</a></li><li><a href="https://github.com/d3lm" target="_blank" rel="noopener noreferrer">Dominic Elm</a></li><li><a href="https://github.com/mcmxcdev" target="_blank" rel="noopener noreferrer">MCMXC</a></li><li><a href="https://github.com/dev-itsheng" target="_blank" rel="noopener noreferrer">那里好脏不可以</a></li><li><a href="https://github.com/HomyeeKing" target="_blank" rel="noopener noreferrer">Homyee King</a></li><li><a href="https://github.com/Shinyaigeek" target="_blank" rel="noopener noreferrer">Shinobu Hayashi</a></li><li><a href="https://github.com/BlackHole1" target="_blank" rel="noopener noreferrer">Black-Hole</a></li><li><a href="https://github.com/kenrick95" target="_blank" rel="noopener noreferrer">Kenrick</a></li><li><a href="https://github.com/weyert" target="_blank" rel="noopener noreferrer">Weyert de Boer</a></li><li><a href="https://github.com/gwhitney" target="_blank" rel="noopener noreferrer">Glen Whitney</a></li><li><a href="https://github.com/chengcyber" target="_blank" rel="noopener noreferrer">Cheng</a></li><li><a href="https://github.com/fireairforce" target="_blank" rel="noopener noreferrer">zoomdong</a></li><li><a href="https://github.com/ufec" target="_blank" rel="noopener noreferrer">thinkhalo</a></li><li><a href="https://github.com/LuciNyan" target="_blank" rel="noopener noreferrer">子瞻 Luci</a></li><li><a href="https://github.com/Spencer17x" target="_blank" rel="noopener noreferrer">spencer17x</a></li><li><a href="https://github.com/liuxingbaoyu" target="_blank" rel="noopener noreferrer">liuxingbaoyu</a></li><li><a href="https://github.com/WhiteKiwi" target="_blank" rel="noopener noreferrer">장지훈</a></li><li><a href="https://github.com/jondlm" target="_blank" rel="noopener noreferrer">Jon de la Motte</a></li><li><a href="https://github.com/Jack-Works" target="_blank" rel="noopener noreferrer">Jack Works</a></li><li><a href="https://github.com/milahu" target="_blank" rel="noopener noreferrer">milahu</a></li><li><a href="https://github.com/David-Collins" target="_blank" rel="noopener noreferrer">David Collins</a></li><li><a href="https://github.com/nikoladev" target="_blank" rel="noopener noreferrer">nikoladev</a></li><li><a href="https://github.com/ibezkrovnyi" target="_blank" rel="noopener noreferrer">Igor Bezkrovnyi</a></li><li><a href="https://github.com/illright" target="_blank" rel="noopener noreferrer">Lev Chelyadinov</a></li><li><a href="https://github.com/javier-garcia-meteologica" target="_blank" rel="noopener noreferrer">javier-garcia-meteologica</a></li></ul><h2 class="anchor anchorWithStickyNavbar_M9ON" id="feature-highlights">Feature Highlights<a href="#feature-highlights" class="hash-link" aria-label="Direct link to Feature Highlights" title="Direct link to Feature Highlights">​</a></h2><h3 class="anchor anchorWithStickyNavbar_M9ON" id="supporting-a-symlinkless-hoisted-node_modules-since-v6250">Supporting a symlinkless hoisted <code>node_modules</code> (since <a href="https://github.com/pnpm/pnpm/releases/tag/v6.25.0" target="_blank" rel="noopener noreferrer">v6.25.0</a>)<a href="#supporting-a-symlinkless-hoisted-node_modules-since-v6250" class="hash-link" aria-label="Direct link to supporting-a-symlinkless-hoisted-node_modules-since-v6250" title="Direct link to supporting-a-symlinkless-hoisted-node_modules-since-v6250">​</a></h3><p>Right at the beginning of 2022, we have added support for the "traditional" hoisted (a.k.a flat <code>node_modules</code>). We use Yarn's hoisting algorithm to create a proper hoisted <code>node_modules</code>. This new setting has basically made pnpm compatible with all Node.js stack that are compatible with npm CLI.</p><p>To use the hoisted <code>node_modules</code> directory structure, use the <code>node-linker=hoisted</code> setting in an <code>.npmrc</code> file.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="side-effects-cache-since-v700">Side effects cache (since <a href="https://github.com/pnpm/pnpm/releases/tag/v7.0.0" target="_blank" rel="noopener noreferrer">v7.0.0</a>)<a href="#side-effects-cache-since-v700" class="hash-link" aria-label="Direct link to side-effects-cache-since-v700" title="Direct link to side-effects-cache-since-v700">​</a></h3><p>Since v7, <a href="/pnpm/npmrc#side-effects-cache">side-effect-cache</a> is enabled by default, so dependencies that should be built are only built once on a machine. This improves installation speed by a lot in projects that have dependencies with build scripts.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="dependencies-patching-since-v740">Dependencies patching (since <a href="https://github.com/pnpm/pnpm/releases/tag/v7.4.0" target="_blank" rel="noopener noreferrer">v7.4.0</a>)<a href="#dependencies-patching-since-v740" class="hash-link" aria-label="Direct link to dependencies-patching-since-v740" title="Direct link to dependencies-patching-since-v740">​</a></h3><p>The <a href="/pnpm/cli/patch"><code>pnpm patch</code></a> command have been added for patching dependencies in your <code>node_modules</code>.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="time-based-resolution-strategy-since-v7100">Time-based resolution strategy (since <a href="https://github.com/pnpm/pnpm/releases/tag/v7.10.0" target="_blank" rel="noopener noreferrer">v7.10.0</a>)<a href="#time-based-resolution-strategy-since-v7100" class="hash-link" aria-label="Direct link to time-based-resolution-strategy-since-v7100" title="Direct link to time-based-resolution-strategy-since-v7100">​</a></h3><p>A new resolution mode was added to pnpm, which should make updating dependencies more secure. You can change the resolution mode with the <a href="https://pnpm.io/npmrc#resolution-mode" target="_blank" rel="noopener noreferrer">resolution-mode</a> setting.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="listing-licenses-of-dependencies-since-v7170">Listing licenses of dependencies (since <a href="https://github.com/pnpm/pnpm/releases/tag/v7.17.0" target="_blank" rel="noopener noreferrer">v7.17.0</a>)<a href="#listing-licenses-of-dependencies-since-v7170" class="hash-link" aria-label="Direct link to listing-licenses-of-dependencies-since-v7170" title="Direct link to listing-licenses-of-dependencies-since-v7170">​</a></h3><p>You may now use the <a href="/pnpm/cli/licenses"><code>pnpm licenses list</code></a> command to check the licenses of the installed packages.</p>]]></content>
        <author>
            <name>Zoltan Kochan</name>
            <uri>http://twitter.com/zoltankochan</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[The year 2021 for pnpm]]></title>
        <id>https://pnpm.io/pnpm/blog/2021/12/29/yearly-update</id>
        <link href="https://pnpm.io/pnpm/blog/2021/12/29/yearly-update"/>
        <updated>2021-12-29T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[It is the end of the year and it was a good year for pnpm, so let's see how it went.]]></summary>
        <content type="html"><![CDATA[<p>It is the end of the year and it was a good year for pnpm, so let's see how it went.</p><h2 class="anchor anchorWithStickyNavbar_M9ON" id="usage">Usage<a href="#usage" class="hash-link" aria-label="Direct link to Usage" title="Direct link to Usage">​</a></h2><h3 class="anchor anchorWithStickyNavbar_M9ON" id="download-stats">Download Stats<a href="#download-stats" class="hash-link" aria-label="Direct link to Download Stats" title="Direct link to Download Stats">​</a></h3><p>My goal this year was to beat Bower by the number of downloads. We were able to achieve this goal <a href="https://npm-stat.com/charts.html?package=pnpm&amp;package=bower&amp;from=2021-01-01&amp;to=2021-12-29" target="_blank" rel="noopener noreferrer">in November</a>:</p><p><img loading="lazy" src="/pnpm/assets/images/pnpm-vs-bower-stats-6ec69a7308f5fbc1433420b1b2f7457f.png" width="976" height="389" class="img_XicP"></p><p>pnpm was downloaded about <a href="https://npm-stat.com/charts.html?package=pnpm&amp;from=2016-12-01&amp;to=2021-12-29" target="_blank" rel="noopener noreferrer">3 times more</a> in 2021 than in 2020:</p><p><img loading="lazy" src="/pnpm/assets/images/download-stats-2021-1418562cb03abd558c4a6b4b17155227.png" width="983" height="394" class="img_XicP"></p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_qn3S"><div class="admonitionHeading_ueQW"><span class="admonitionIcon_N0Kn"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_JsRk"><p>These stats don't even measure all the different ways that pnpm may be installed!
They only measure the downloads of the <a href="https://www.npmjs.com/package/pnpm" target="_blank" rel="noopener noreferrer">pnpm npm package</a>. This year we also added compiled binary versions of pnpm, which are shipped differently.</p></div></div><h3 class="anchor anchorWithStickyNavbar_M9ON" id="docs-visits">Docs visits<a href="#docs-visits" class="hash-link" aria-label="Direct link to Docs visits" title="Direct link to Docs visits">​</a></h3><p>We collect some unpersonalized stats from our docs using Google Analytics.
In 2021, sometimes we had more than 2,000 unique visitors a week.</p><p><img loading="lazy" src="/pnpm/assets/images/ga-unique-visits-2021-b8bc3649f680565127696c85bdd4b701.png" width="665" height="509" class="img_XicP"></p><p>Most of our users are from the United States and China.</p><p><img loading="lazy" src="/pnpm/assets/images/countries-2021-8eb9625e1798649ee04451dfb10ac851.png" width="585" height="498" class="img_XicP"></p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="github-stars">GitHub stars<a href="#github-stars" class="hash-link" aria-label="Direct link to GitHub stars" title="Direct link to GitHub stars">​</a></h3><p>Our <a href="https://github.com/pnpm/pnpm" target="_blank" rel="noopener noreferrer">main GitHub repository</a> received +5,000 stars this year.</p><p><img loading="lazy" src="/pnpm/assets/images/stars-2021-0061c16f424e33ba0db224d82bcb53f3.png" width="913" height="800" class="img_XicP"></p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="new-users">New users<a href="#new-users" class="hash-link" aria-label="Direct link to New users" title="Direct link to New users">​</a></h3><p>Our biggest new user this year is <a href="https://github.com/pnpm/pnpm.github.io/pull/89" target="_blank" rel="noopener noreferrer">Bytedance</a> (the company behind TikTok).</p><p>Also, many great open-source projects started to use pnpm. Some switched to pnpm because of its great support of monorepos:</p><ul><li><a href="https://github.com/vuejs/vue-next" target="_blank" rel="noopener noreferrer">Vue</a></li><li><a href="https://github.com/vitejs/vite" target="_blank" rel="noopener noreferrer">Vite</a></li><li>and <a href="https://pnpm.io/workspaces#usage-examples" target="_blank" rel="noopener noreferrer">others</a></li></ul><p>Some switched because they like how efficient, fast, and beautiful pnpm is:</p><ul><li><a href="https://twitter.com/Autoprefixer/status/1476226146488692736" target="_blank" rel="noopener noreferrer">Autoprefixer</a></li><li><a href="https://twitter.com/PostCSS/status/1470438664006258701" target="_blank" rel="noopener noreferrer">PostCSS</a></li><li><a href="https://twitter.com/Browserslist/status/1468264308308156419" target="_blank" rel="noopener noreferrer">Browserslist</a></li></ul><h2 class="anchor anchorWithStickyNavbar_M9ON" id="feature-highlights">Feature Highlights<a href="#feature-highlights" class="hash-link" aria-label="Direct link to Feature Highlights" title="Direct link to Feature Highlights">​</a></h2><h3 class="anchor anchorWithStickyNavbar_M9ON" id="new-lockfile-format-since-v600">New lockfile format (since <a href="https://github.com/pnpm/pnpm/releases/tag/v6.0.0" target="_blank" rel="noopener noreferrer">v6.0.0</a>)<a href="#new-lockfile-format-since-v600" class="hash-link" aria-label="Direct link to new-lockfile-format-since-v600" title="Direct link to new-lockfile-format-since-v600">​</a></h3><p>One of the first and most important changes this year was the new <code>pnpm-lock.yaml</code> 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.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="managing-nodejs-versions-since-v6120">Managing Node.js versions (since <a href="https://github.com/pnpm/pnpm/releases/tag/v6.12.0" target="_blank" rel="noopener noreferrer">v6.12.0</a>)<a href="#managing-nodejs-versions-since-v6120" class="hash-link" aria-label="Direct link to managing-nodejs-versions-since-v6120" title="Direct link to managing-nodejs-versions-since-v6120">​</a></h3><p>We shipped a new command (<code>pnpm env</code>) that allows to manage Node.js versions. So you may use pnpm instead of Node.js version managers like nvm or Volta.</p><p>Also, pnpm is shipped as a standalone executable, so you can run it even with no Node.js preinstalled on the system.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="injecting-local-dependencies-since-v6200">Injecting local dependencies (since <a href="https://github.com/pnpm/pnpm/releases/tag/v6.20.0" target="_blank" rel="noopener noreferrer">v6.20.0</a>)<a href="#injecting-local-dependencies-since-v6200" class="hash-link" aria-label="Direct link to injecting-local-dependencies-since-v6200" title="Direct link to injecting-local-dependencies-since-v6200">​</a></h3><p>You may "inject" a local dependency. By default, local dependencies are symlinked to <code>node_modules</code> but with this new feature you may instruct pnpm to hard link the files of the package instead.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="improved-reporting-of-peer-dependency-issues-since-v6240">Improved reporting of peer dependency issues (since <a href="https://github.com/pnpm/pnpm/releases/tag/v6.24.0" target="_blank" rel="noopener noreferrer">v6.24.0</a>)<a href="#improved-reporting-of-peer-dependency-issues-since-v6240" class="hash-link" aria-label="Direct link to improved-reporting-of-peer-dependency-issues-since-v6240" title="Direct link to improved-reporting-of-peer-dependency-issues-since-v6240">​</a></h3><p>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.</p><h2 class="anchor anchorWithStickyNavbar_M9ON" id="the-competition">The Competition<a href="#the-competition" class="hash-link" aria-label="Direct link to The Competition" title="Direct link to The Competition">​</a></h2><h3 class="anchor anchorWithStickyNavbar_M9ON" id="yarn">Yarn<a href="#yarn" class="hash-link" aria-label="Direct link to Yarn" title="Direct link to Yarn">​</a></h3><p>Yarn added a pnpm linker in <a href="https://dev.to/arcanis/yarn-31-corepack-esm-pnpm-optional-packages--3hak#new-install-mode-raw-pnpm-endraw-" target="_blank" rel="noopener noreferrer">v3.1</a>. So Yarn can create a similar node-modules directory structure to the one that pnpm creates.</p><p>Also, the Yarn team plans to implement a content-addressable storage to be more disk space efficient.</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="npm">npm<a href="#npm" class="hash-link" aria-label="Direct link to npm" title="Direct link to npm">​</a></h3><p>The npm team decided to also adopt the symlinked node-modules directory structure that pnpm uses (related <a href="https://github.com/npm/rfcs/blob/main/accepted/0042-isolated-mode.md" target="_blank" rel="noopener noreferrer">RFC</a>).</p><h3 class="anchor anchorWithStickyNavbar_M9ON" id="others">Others<a href="#others" class="hash-link" aria-label="Direct link to Others" title="Direct link to Others">​</a></h3><p><a href="https://twitter.com/jarredsumner/status/1473416431291174912/photo/1" target="_blank" rel="noopener noreferrer">Bun</a> written in Zig and <a href="https://github.com/voltpkg/volt" target="_blank" rel="noopener noreferrer">Volt</a> written in Rust both claim to be faster than npm/Yarn/pnpm. I did not benchmark these new package managers yet.</p><h2 class="anchor anchorWithStickyNavbar_M9ON" id="future-plans">Future Plans<a href="#future-plans" class="hash-link" aria-label="Direct link to Future Plans" title="Direct link to Future Plans">​</a></h2><p>Faster, better, best.</p>]]></content>
        <author>
            <name>Zoltan Kochan</name>
            <uri>http://twitter.com/zoltankochan</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Node-Modules configuration options with pnpm]]></title>
        <id>https://pnpm.io/pnpm/blog/2020/10/17/node-modules-configuration-options-with-pnpm</id>
        <link href="https://pnpm.io/pnpm/blog/2020/10/17/node-modules-configuration-options-with-pnpm"/>
        <updated>2020-10-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[There are many ways to create a node_modules directory.]]></summary>
        <content type="html"><![CDATA[<p>There are many ways to create a node_modules directory.
Your goal must be to create the most strict one but if that is not possible,
there are options to make a loose node_modules as well.</p><h2 class="anchor anchorWithStickyNavbar_M9ON" id="the-default-setup">The default setup<a href="#the-default-setup" class="hash-link" aria-label="Direct link to The default setup" title="Direct link to The default setup">​</a></h2><p>By default, pnpm v5 will create a semi-strict node_modules. Semi-strict means that your application will only be able to require packages that are added as dependencies to <code>package.json</code> (with a few exceptions). However, your dependencies will be able to access any packages.</p><p>The default configuration looks like this:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">; All packages are hoisted to node_modules/.pnpm/node_modules</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">hoist-pattern[]=*</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">; All types are hoisted to the root in order to make TypeScript happy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public-hoist-pattern[]=*types*</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">; All ESLint-related packages are hoisted to the root as well</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">public-hoist-pattern[]=*eslint*</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_M9ON" id="plugnplay-the-strictest-configuration">Plug'n'Play. The strictest configuration<a href="#plugnplay-the-strictest-configuration" class="hash-link" aria-label="Direct link to Plug'n'Play. The strictest configuration" title="Direct link to Plug'n'Play. The strictest configuration">​</a></h2><p>pnpm supports <a href="https://yarnpkg.com/features/pnp" target="_blank" rel="noopener noreferrer">Yarn's Plug'n'Play</a> since v5.9. With PnP, both your application and the dependencies of your application will have access only to their declared dependencies. This is even stricter then setting <code>hoist=false</code> because inside a monorepo, your application will not be able to access even the dependencies of the root project.</p><p>To use Plug'n'Play, set these settings:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">node-linker=pnp</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">symlink=false</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithStickyNavbar_M9ON" id="a-strict-traditional-modules-directory">A strict, traditional modules directory<a href="#a-strict-traditional-modules-directory" class="hash-link" aria-label="Direct link to A strict, traditional modules directory" title="Direct link to A strict, traditional modules directory">​</a></h2><p>If you are not ready to use PnP yet, you can still be strict and only allow packages to access their own dependencies by setting the hoist configuration to false:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">hoist=false</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>However, if some of your dependencies are trying to access packages that they don't have in dependencies, you have two options:</p><ol><li><p>Create a <code>pnpmfile.js</code> and use a <a href="/pnpm/pnpmfile">hook</a> to add the missing dependency to the package's manifest.</p></li><li><p>Add a pattern to the <code>hoist-pattern</code> setting. For instance, if the not found module is <code>babel-core</code>, add the following setting to <code>.npmrc</code>:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">hoist-pattern[]=babel-core</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></li></ol><h2 class="anchor anchorWithStickyNavbar_M9ON" id="the-worst-case---hoisting-to-the-root">The worst case - hoisting to the root<a href="#the-worst-case---hoisting-to-the-root" class="hash-link" aria-label="Direct link to The worst case - hoisting to the root" title="Direct link to The worst case - hoisting to the root">​</a></h2><p>Some tools might not work even with the default configuration of pnpm, which hoists everything to the root of the virtual store and some packages to the root. In this case, you can hoist either everything or a subset of dependencies to the root of the modules directory.</p><p>Hoisting everything to the root of node_modules:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">shamefully-hoist=true</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Hoisting only packages that match a pattern:</p><div class="language-ini codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-ini codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">public-hoist-pattern[]=babel-*</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content>
        <author>
            <name>Zoltan Kochan</name>
            <uri>http://twitter.com/zoltankochan</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[Flat node_modules is not the only way]]></title>
        <id>https://pnpm.io/pnpm/blog/2020/05/27/flat-node-modules-is-not-the-only-way</id>
        <link href="https://pnpm.io/pnpm/blog/2020/05/27/flat-node-modules-is-not-the-only-way"/>
        <updated>2020-05-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[New users of pnpm frequently ask me about the weird structure of node_modules that pnpm creates. Why is it not flat? Where are all the sub-dependencies?]]></summary>
        <content type="html"><![CDATA[<p>New users of pnpm frequently ask me about the weird structure of <code>node_modules</code> that pnpm creates. Why is it not flat? Where are all the sub-dependencies?</p><blockquote><p>I am going to assume that readers of the article are already familiar with flat <code>node_modules</code> created by npm and Yarn. If you don't understand why npm 3 had to start using flat <code>node_modules</code> in v3, you can find some prehistory in <a href="https://www.kochan.io/nodejs/why-should-we-use-pnpm.html" target="_blank" rel="noopener noreferrer">Why should we use pnpm?</a>.</p></blockquote><p>So why is pnpm's <code>node_modules</code> unusual? Let's create two directories and run <code>npm add express</code> in one of them and <code>pnpm add express</code> in the other one. Here's the top of what you get in the first directory's <code>node_modules</code>:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">.bin</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">accepts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">array-flatten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">body-parser</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">bytes</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">content-disposition</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cookie-signature</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">cookie</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">debug</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">depd</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">destroy</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">ee-first</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">encodeurl</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">escape-html</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">etag</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">express</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You can see the whole directory <a href="https://github.com/zkochan/comparing-node-modules/tree/master/npm-example/node_modules" target="_blank" rel="noopener noreferrer">here</a>.</p><p>And this is what you get in the <code>node_modules</code> created by pnpm:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">.pnpm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">.modules.yaml</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">express</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>You can check it <a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm5-example/node_modules" target="_blank" rel="noopener noreferrer">here</a>.</p><p>So where are all the dependencies? There is only one folder in the <code>node_modules</code> called <code>.pnpm</code> and a symlink called <code>express</code>. Well, we installed only <code>express</code>, so that is the only package that your application has to have access to </p><blockquote><p>Read more about why pnpm's strictness is a good thing <a href="https://medium.com/pnpm/pnpms-strictness-helps-to-avoid-silly-bugs-9a15fb306308" target="_blank" rel="noopener noreferrer">here</a></p></blockquote><p>Let's see what is inside <code>express</code>:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">▾ node_modules</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ▸ .pnpm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ▾ express</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ▸ lib</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      History.md</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      index.js</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      LICENSE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      package.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      Readme.md</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  .modules.yaml</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>express</code> has no <code>node_modules</code>? Where are all the dependencies of <code>express</code>?</p><p>The trick is that <code>express</code> 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 <code>express</code>, you might ask?</p><p>Here: <a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm5-example/node_modules/.pnpm/express@4.17.1/node_modules/express" target="_blank" rel="noopener noreferrer">node_modules/.pnpm/express@4.17.1/node_modules/express</a>.</p><p>OK, so now we know the purpose of the <code>.pnpm/</code> folder. <code>.pnpm/</code> stores all the packages in a flat folder structure, so every package can be found in a folder named by this pattern:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">.pnpm/&lt;name&gt;@&lt;version&gt;/node_modules/&lt;name&gt;</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>We call it the virtual store directory.</p><p>This flat structure avoids the long path issues that were caused by the nested <code>node_modules</code> created by npm v2 but keeps packages isolated unlike the flat <code>node_modules</code> created by npm v3,4,5,6 or Yarn v1.</p><p>Now let's look into the real location of <code>express</code>:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">  ▾ express</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ▸ lib</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      History.md</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      index.js</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      LICENSE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      package.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      Readme.md</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>Is it a scam? It still lacks <code>node_modules</code>! The second trick of pnpm's <code>node_modules</code> 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 <code>express</code> are not in <code>.pnpm/express@4.17.1/node_modules/express/node_modules/</code> but in <a href="https://github.com/zkochan/comparing-node-modules/tree/master/pnpm5-example/node_modules/.pnpm/express@4.17.1/node_modules" target="_blank" rel="noopener noreferrer">.pnpm/express@4.17.1/node_modules/</a>:</p><div class="language-text codeBlockContainer_PfM4 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_sVD5"><pre tabindex="0" class="prism-code language-text codeBlock_IFdB thin-scrollbar"><code class="codeBlockLines__UdX"><span class="token-line" style="color:#393A34"><span class="token plain">▾ node_modules</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  ▾ .pnpm</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ▸ accepts@1.3.5</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ▸ array-flatten@1.1.1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    ▾ express@4.16.3</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">      ▾ node_modules</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▸ accepts</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▸ array-flatten</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▸ body-parser</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▸ content-disposition</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ...</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▸ etag</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">        ▾ express</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">          ▸ lib</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            History.md</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            index.js</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            LICENSE</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            package.json</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">            Readme.md</span><br></span></code></pre><div class="buttonGroup_W9z0"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_U9Tg" aria-hidden="true"><svg class="copyButtonIcon_jN4X" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_ajRE" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>All the dependencies of <code>express</code> are symlinks to appropriate directories in <code>node_modules/.pnpm/</code>. Placing dependencies of <code>express</code> one level up allows avoiding circular symlinks.</p><p>So as you can see, even though pnpm's <code>node_modules</code> structure seems unusual at first:</p><ol><li>it is completely Node.js compatible</li><li>packages are nicely grouped with their dependencies</li></ol><p>The structure is a little bit <a href="/pnpm/how-peers-are-resolved">more complex</a> for packages with peer dependencies but the idea is the same: using symlinks to create a nesting with a flat directory structure.</p>]]></content>
        <author>
            <name>Zoltan Kochan</name>
            <uri>http://twitter.com/zoltankochan</uri>
        </author>
    </entry>
</feed>