In the past, I've written how I prefer Yarn over NPM not just for SharePoint Framework (SPFx) projects, but also for all my Node.js based projects that leverage the NPM package registry: https://www.npmjs.org. I wrote that post in December 2016 and things have changed quite a bit since then. Last week Microsoft released SPFx v1.5.0 & the associated Yeoman generator that added support for changing the package manager the generator ran after creating the project scaffolding. Even without this new
--package-manager switch introduced in v1.5.0, the SPFx generator had the command line switch
--skip-install that we could add, telling it to not run the package install step, thus allowing us to run our own package manager.
I thought this would be a good time to do a deeper comparison between the three most popular options that the SPFx generator supports: NPM, Yarn & PNPM. In doing so, I think I've made a switch in my preference. Out with Yarn, in with PNPM!
There is nothing special about any of the three package managers discussed in this post with respect to SPFx. I'm just focusing on SPFx as the scenario for this post.
First, let's look at our options:
NPM - Node Package Manager
Technically NPM doesn't stand for "Node Package Manager", but that's what everyone thinks for all practical purposes.
NPM was the first package manager used to pull packages down from the NPM package registry at **https://www.npmjs.org. This registry is the primary registry all Node.js projects and most client-side packages are pulled from. It's replaced other registries such as Bower.
NPM maintained its hold on the package management space for a while, leaving developers to address it's shortcomings around speed, consistency and version locking. Since competing package managers were introduced, specifically Yarn, NPM has stepped up its game and is on par for the most part with the others out there.
To use NPM with an SPFx project, simply run the Yeoman SPFx generator with no command line switches as NPM is the default:
Yarn was created as a collaboration between Facebook and Google to address the shortcomings of NPM. The two biggest things it added was the concept of a lockfile and package cache.
The package cache helped eliminate the issue where each time you installed packages in a new project, instead of pulling a new copy from the NPM registry, Yarn would first check to see if you had already downloaded it in the past. If you had, it would skip the download process and instead just copy the package from the local cache into your project folder.
The lockfile would ensure that each time packages were installed with yarn, it the same version you got last time would be downloaded. Before this concept was introduced, if you ran installed packages on a Monday with NPM, and someone installed them on the same project on Wednesday, there was no guarentee you would get the same versions of the packages because someone may have shipped an update between the two days.
In the early days of SPFx, this happened a few times and even bit me one day: Troubleshooting and Fixing the "Out of the Blue, My SharePoint Framework Projects Won't Build!"
To use Yarn with an SPFx project, add the
--package-manager flag to the end of the command:
yo @microsoft/sharepoint --package-manager yarn
This is the newest one on the scene. It does everything the other two generators do in the sense of lockfiles and a package cache. However, it has one different characteristic...
Instead of copying the packages from the cache to the project, it creates a hard link from the project's node_modules folder to the folder in the package cache. This means your project folders are much smaller!
To use PNPM with an SPFx project, add the
--package-manager flag to the end of the command:
yo @microsoft/sharepoint --package-manager pnpm
Comparing the package managers
I set out to see which was the best one for my use and the results weren't at all surprising. First, let's make sure you have some context. Here's what my test looked like:
- macOS High Sierra (v10.13.5)
- Intel Kaybe Lake i7 quad core 3.1Ghz
- 16GB RAM
- Node.js v8.11.2
Broadband internet connection
I ran a series of tests. As far as time goes, I wanted to compare three specific scenarios:
- Execute install for each package manager for the first time - this would get no benefit of the package cache
- Execute install on a brand new project after one was already created - this would get the benefit of package cache
- Execute install on an existing project that has a lockfile / shrinkwrap file present - this would be the experience of cloning a project from source control and get the benefit of not having to determine the dependency tree of packages needed by the project.
Let's look at the results...
From my point of view, these package managers are all on par with each other. The difference in how long each one takes to run it's install command in the different scenarios doesn't differ all that much.
The first run is the biggest difference where NPM is 21% faster than Yarn and 11% faster than PNPM.
For the second run, PNPM edges the other two out just a bit, but not enough to make an impact from my point of view. The same is true for the last test.
Comparing Disk Usage
This is where we see the most significant impact.
Now let me explain this a bit as that first set of results on the first project in that chart above does not fully represent what's going on.
For NPM and Yarn, that is the total size of the project itself. However, if you recall from above when I explained how PNPM works, the packages aren't stored in the node_modules folder within the project. With PNPM it creates a hard link to the package folder within the cache.
So... if I were to truly compare the first project for all three package managers against each other, I should have duped the size of the node_modules folder for each and If I did that, you'd have to almost double the size of the NPM and Yarn projects.
I did find it interesting that the combined size and number of files for each project differed. Check this out... this is the total file count for each project, excluding the package cache (no, that last one is not a typo).
- NPM: total files = 67,709
- Yarn: total files = 57,460
- PNPM: total files = 39
The real benefit we see is when you look at that second project created. Check it out... if you leverage PNPM, the impact to your disk is only 64MB compared to over 500MB for each of the other two!
This is seen when you delete a project too. If I was to delete each project created by NPM, Yarn, and PNPM:
- NPM: 14 seconds
- Yarn: 9 seconds
- PNPM: 8 seconds
Deleting the projects does not impact the cache in any way... it only deletes the project.
I checked the disk size and number of files using the popular du tool. Each run used the
For the last one, I passed in the folders for the two pairs of projects (I had a pair for NPM, Yarn & PNPM). This utility only counts hard links one time, not twice, hence why I had to explain the last results above.
Bonus: setup command line aliases!
I don't know about you, but I hate having to type out
yo @microsoft/sharepoint --package-manager pnpm every time I create a new project. What I did was create an alias so now I just type
spfx-new and it will run the above command for me.
Create aliases on MacOS
If you are using MacOS, you can create an alias that will run the Yeoman SPFx generator for you with the special command line switch. If you use Bash, add the following line to the end of your ~/.bashrc file, or if you use ZSH, add it to the end of your ~/.zshrc file:
alias spfx-new=yo @microsoft/sharepoint --package-manager pnpm
Create aliases on Windows
If you're on Windows, you have a bit more work to do with the default command prompt.
First open up the registry editor, locate the key HKCU\Software\Microsoft\Command Processor and add a new string AutoRun with a value of
Then create a new text file named aliases.cmd with the following line that defines an alias using the DOSKEY Windows utility: