Mathias Osterkamp

Specialist – focus development Microsoft technology stack

SPFX 2019 - speed up npm performance

How you can get rid of the slow npm installation

Problem

For current sharepoint projects we have huge node_modules folders. With every new project we have to download everything again. I started to look for a better solution and found pnpm.

Solution

pnpm is a complete custom package manager designed for better performance, but compatible with npm. Instead of heaving multiple packages it uses symlinks and reuses packages. They published a speed comparison, in some tests it is pretty fast, especial if you already have some projects.

Performance

So next steps are to prepare our existing solution for showcase.

Cleanup old node_modules

Fastest way to cleanup your node_modules folder is via npm rimraf. Install this global:

npm install rimraf -g

Now you can easy clean your folder:

PS C:\daten\git\spfx-2019-solution\spfx-2019> rimraf node_modules

Install pnpm

With npm we install a global version of pnpm. We need version 5 because we have node v12 for our sharepoint 2019 projects.

npm i pnpm@5.18.9 -g

Next step is to give pnpm a better storage folder. Edit your npm config.

npm config edit

You can set your folder here:

store-dir=C:\Daten\pnpm\store
optional=false

No we reinstall our packages with pnpm. We use the –shamefully-hoist because we need to recover our structure.

By default, pnpm creates a semistrict node_modules, meaning dependencies have access to undeclared dependencies but modules outside of node_modules do not. With this layout, most of the packages in the ecosystem work with no issues. However, if some tooling only works when the hoisted dependencies are in the root of node_modules, you can set this to true to hoist them for you.

PS C:\daten\git\spfx-2019-solution\spfx-2019> pnpm install --shamefully-hoist
 WARN  @microsoft/sp-build-web > @microsoft/sp-build-common > @microsoft/sp-tslint-rules: tslint-microsoft-contrib@5.0.3 requires a peer of typescript@^2.1.0 but version 3.6.4 was installed.pt/3.6.4: 6.22 MB/8.2 MB
Packages: +1580
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
Packages are hard linked from the content-addressable store to the virtual store.
  Content-addressable store is at: C:\daten\pnpm\store\v3
  Virtual store is at:             node_modules/.pnpm
Downloading registry.npmjs.org/typescript/3.6.4: 8.2 MB/8.2 MB, done
Downloading registry.npmjs.org/office-ui-fabric-react/5.21.0: 7.33 MB/7.33 MB, done
Progress: resolved 1599, reused 0, downloaded 1599, added 1580, done
 WARN  Failed to find "/watchpack-chokidar2/2.0.1" in lockfile during hoisting. Next aliases will not be hoisted: watchpack-chokidar2
 WARN  Failed to find "/fsevents/1.2.13" in lockfile during hoisting. Next aliases will not be hoisted: fsevents
 WARN  Failed to find "/uglify-to-browserify/1.0.2" in lockfile during hoisting. Next aliases will not be hoisted: uglify-to-browserify
node_modules/.pnpm/deasync@0.1.22/node_modules/deasync: Running install script, done in 1.7s
node_modules/.pnpm/core-js@2.6.12/node_modules/core-js: Running postinstall script, done in 876ms
node_modules/.pnpm/ejs@2.7.4/node_modules/ejs: Running postinstall script, done in 912ms
node_modules/.pnpm/@microsoft/sp-loader@1.4.1/node_modules/@microsoft/sp-loader: Running install script, done in 1s
node_modules/.pnpm/node-sass@4.14.1/node_modules/node-sass: Running install script, done in 2.4s
node_modules/.pnpm/spawn-sync@1.0.15/node_modules/spawn-sync: Running postinstall script, done in 811ms
node_modules/.pnpm/phantomjs-prebuilt@2.1.16/node_modules/phantomjs-prebuilt: Running install script, done in 6.9s
node_modules/.pnpm/node-sass@4.14.1/node_modules/node-sass: Running postinstall script, done in 1.9s
node_modules/.pnpm/uglifyjs-webpack-plugin@0.4.6_webpack@3.6.0/node_modules/uglifyjs-webpack-plugin: Running postinstall script, done in 322ms
Cannot link binary 'jest' of 'jest-cli' to 'C:\daten\git\spfx-2019-solution\spfx-2019\node_modules\.pnpm\@microsoft\gulp-core-build@3.2.7\node_modules\@microsoft\gulp-core-build\node_modules\.bin': binary of 'jest' is already linked

dependencies:
+ @custom/spfx-2019-lib 1.0.0 <- ..\spfx-2019-lib
+ @microsoft/decorators 1.4.1 (1.12.1 is available)
+ @microsoft/sp-application-base 1.4.1 (1.12.1 is available)
+ @microsoft/sp-core-library 1.4.1 (1.12.1 is available)
+ @microsoft/sp-dialog 1.4.1 (1.12.1 is available)
+ @microsoft/sp-lodash-subset 1.4.1 (1.12.1 is available)
+ @microsoft/sp-office-ui-fabric-core 1.4.1 (1.12.1 is available)
+ @microsoft/sp-webpart-base 1.4.1 (1.12.1 is available)
+ react 15.6.2 (17.0.2 is available)
+ react-dom 15.6.2 (17.0.2 is available)

devDependencies:
+ @microsoft/generator-sharepoint 1.9.1 (1.12.1 is available)
+ @microsoft/sp-build-web 1.4.1 (1.12.1 is available)
+ @microsoft/sp-module-interfaces 1.4.1 (1.12.1 is available)
+ @microsoft/sp-webpart-workbench 1.4.1 (1.12.1 is available)
+ @types/es6-promise 0.0.33 (3.3.0 is available)
+ @types/microsoft-ajax 0.0.33 (0.0.37 is available)
+ @types/react 15.6.6 (17.0.17 is available)
+ @types/react-dom 15.5.6 (17.0.9 is available)
+ @types/sharepoint 2016.1.2 (2016.1.10 is available)
+ ajv 5.2.5 (8.6.2 is available)
+ gulp 3.9.1 (4.0.2 is available)
+ typescript 3.6.4 (4.3.5 is available)

Thats all! We can add finally a preinstall to our package.json to prevent from using npm again.

“preinstall”: “npx only-allow pnpm”

Bonus create spfx packages

Our yeoman generator for sharepoint also supports this package manager:

yo @microsoft/sharepoint --package-manager pnpm