public

Speed up npm install with pnpm

Reduce your npm install time from minutes to seconds with pnpm.

Latest Post Speed kills software engineering. by Matthew Davis public

Using npm has it's advantages, albeit only a few other than being already installed in most cases. But pnpm has far more!

In this exercise we'll cover only the install phase and assume we are building in docker and using pnpm.

Install pnpm via npm i -g pnpm or use the inline script at Installation | pnpm.

The package.json

I'm using the following package.json. Notice the usage of both public and private packages.

There is a peerDependency of bcrypt which will require compilation during the install. This should further increase our install time.

{
    "name": "@servicecatalog.io/api",
    "version": "0.0.0",
    "main": "dist/main.js",
    "types": "dist/main.d.ts",
    "license": "MIT",
    "preversion": "rm -rf dist && tsc",
    "postversion": "npm publish",
    "scripts": {
        "start:dev": "concurrently --handle-input \"wait-on dist/main.js && nodemon\" \"tsc -w -p tsconfig.json\" ",
        "release": "rm -rf dist && tsc && npm version patch && npm publish --access=private",
        "build": "tsc"
    },
    "dependencies": {
        "@nestjs-plus/rabbitmq": "^1.4.4",
        "@nestjs.pro/common": "1.0.95",
        "@nestjs.pro/logger-elasticsearch": "^0.1.7",
        "@nestjs/common": "^7.6.12",
        "@nestjs/core": "^7.6.12",
        "@nestjs/swagger": "^4.7.13",
        "@nestjs/typeorm": "^7.1.5",
        "@servicecatalog/models": "^0.0.3",
        "@servicecatalog/rbac": "^0.0.3",
        "@types/node": "^14.14.30",
        "amqplib": "^0.6.0",
        "class-validator": "0.13.1",
        "dotenv": "^8.2.0",
        "mysql": "^2.18.1",
        "nodemon": "^2.0.7",
        "typeorm": "^0.2.31",
        "typescript": "^4.1.5"
    },
    "devDependencies": {
        "ts-node-dev": "^1.1.6",
        "concurrently": "^5.3.0",
        "wait-on": "^5.2.1"
    }
}
package.json

The Dockerfile

FROM node:alpine AS builder

#
# Needed for bcrypt node module.
#
RUN apk add --virtual builds-deps build-base python3

#
# Install the pnpm.
#
RUN curl -f https://get.pnpm.io/v6.js | node - add --global pnpm

WORKDIR /app

COPY .npmrc /root/.npmrc

COPY package.json .

RUN time pnpm install --network-concurrency=32 --prod

RUN rm -rf ~/.npmrc

COPY src src

RUN npm run build

RUN rm -rf src

ENTRYPOINT ["node", "/app/dist/main.js"]

Build times

We'll compare using npm install vs. pnpm install --network-concurrency=32 --prod.

Notice how we've increased our concurrency using --network-concurrency. The default is 16. Increasing this number to 32 shaved off 6-10 seconds on average.

Running a straight npm install resulted in build times averaging 3+ minutes whereas running a pnpm install --network-concurrency=32 --prod completed under an average of 45 seconds.

dependencies:
+ @nestjs-plus/rabbitmq 1.4.4
+ @nestjs.pro/common 1.0.95
+ @nestjs.pro/logger-elasticsearch 0.1.25
+ @nestjs/common 7.6.15
+ @nestjs/core 7.6.15
+ @nestjs/swagger 4.8.0
+ @nestjs/typeorm 7.1.5
+ @servicecatalog/models 0.0.39
+ @servicecatalog/rbac 0.0.3
+ @types/node 14.14.37
+ amqplib 0.6.0 (0.7.1 is available)
+ class-validator 0.13.1
+ dotenv 8.2.0
+ mysql 2.18.1
+ nodemon 2.0.7
+ typeorm 0.2.32
+ typescript 4.2.4

real    0m 43.37s
user    0m 46.24s
sys     0m 18.20s
time pnpm install --network-concurrency=32 --prod
..
added 729 packages, and audited 729 packages in 3m
..
npm install
Using --prod will prevent your devDependencies from being installed. Use it! See pnpm install | pnpm for the full list of options.

This time saving command can increase your productivity and reduce your build time, CI/CD costs, and quality of life.

Matthew Davis

Published 3 years ago