A couple of days ago Facebook released Yarn, a new package manager for Javascript, with a focus on speed and consistent package dependency management across machines.
With Yarn, engineers still have access to the npm registry, so I thought it worth the try to test the claimed speed improvements between package installation using yarn and npm default installation process.
For my tests I used ng-lightning, a project for native Angular 2 components & directives for Lightning Design System I use lately for a project. Kudos to my friend tbekos, the main contributor of the project for his awesome work.
Project dependencies
Ng-lightning has the following dependencies
{ "name": "ng-lightning", "version": "0.27.1-0", "description": "Native Angular 2 components and directives for Lightning Design System", "repository": { "type": "git", "url": "git+https://github.com/ng-lightning/ng-lightning.git" }, "bugs": { "url": "https://github.com/ng-lightning/ng-lightning/issues" }, "main": "bundles/ng-lightning.umd.js", "module": "ng-lightning.js", "typings": "ng-lightning.d.ts", "scripts": { "test": "gulp test", "tdd": "gulp tdd", "lint": "gulp lint:ts --failOnError=true", "build": "gulp", "start": "npm run build && gulp build:watch", "demo": "webpack --config ./demo/webpack.config.js --watch", "demo:build": "npm run build && webpack --config ./demo/webpack.config.js", "demo:release": "npm run demo:build && node scripts/gh-pages", "prerelease": "npm run build && npm test", "release": "node scripts/release" }, "keywords": [ "angular", "angular2", "lightning", "lightning design system", "salesforce" ], "author": "Tasos Bekos <tbekos@gmail.com>", "license": "MIT", "peerDependencies": { "@angular/common": "^2.0.0", "@angular/core": "^2.0.0", "@angular/forms": "^2.0.0", "@salesforce-ux/design-system": "^2.0.1" }, "dependencies": { "tether": "^1.2.0" }, "devDependencies": { "@angular/common": "^2.1.2", "@angular/compiler": "^2.1.2", "@angular/compiler-cli": "^2.1.2", "@angular/core": "^2.1.2", "@angular/forms": "^2.1.2", "@angular/http": "^2.1.2", "@angular/platform-browser": "^2.1.2", "@angular/platform-browser-dynamic": "^2.1.2", "@angular/platform-server": "^2.1.2", "@angular/router": "^3.1.2", "@salesforce-ux/design-system": "^2.1.3", "@types/core-js": "^0.9.34", "@types/jasmine": "^2.5.36", "@types/node": "^6.0.46", "@types/tether": "^1.1.27", "app-root-path": "^2.0.1", "browser-sync": "^2.17.5", "browser-sync-webpack-plugin": "^1.1.3", "clean-webpack-plugin": "^0.1.13", "conventional-changelog-cli": "^1.2.0", "copy-webpack-plugin": "^4.0.0", "core-js": "^2.4.1", "dateformat": "^1.0.12", "del": "^2.2.2", "gh-pages": "^0.11.0", "glob": "^7.1.1", "gulp": "gulpjs/gulp#4.0", "gulp-cached": "^1.1.0", "gulp-inline-ng2-template": "^3.0.2", "gulp-tslint": "^6.1.2", "gulp-typescript": "^3.1.1", "html-loader": "^0.4.4", "html-webpack-plugin": "^2.24.0", "inquirer": "^1.2.2", "jade": "^1.11.0", "jade-loader": "^0.8.0", "jasmine-core": "^2.5.1", "jasmine-spec-reporter": "^2.7.0", "json-loader": "^0.5.3", "karma": "^1.3.0", "karma-chrome-launcher": "^2.0.0", "karma-coverage": "^1.1.1", "karma-firefox-launcher": "^1.0.0", "karma-ie-launcher": "^1.0.0", "karma-jasmine": "^1.0.2", "karma-safari-launcher": "^1.0.0", "karma-sauce-launcher": "^1.1.0", "karma-sourcemap-loader": "^0.3.6", "lazypipe": "^1.0.1", "markdown-loader": "^0.1.7", "prismjs": "^1.5.1", "prismjs-loader": "0.0.4", "q": "^1.4.1", "raw-loader": "^0.5.1", "replace": "^0.3.0", "request": "^2.76.0", "rxjs": "5.0.0-beta.12", "semver": "^5.3.0", "shelljs": "^0.7.5", "simple-git": "^1.57.0", "systemjs": "^0.19.40", "systemjs-builder": "^0.15.33", "tether": "^1.3.7", "ts-loader": "^0.9.5", "tslint": "^3.15.1", "typescript": "^2.0.6", "webpack": "^1.13.3", "yargs": "^6.3.0", "zone.js": "^0.6.26" } }
which results in a 153 MB node_modules
folder with 49.452 files and 4.103 folders.
Using NPM (3.10.3)
To measure the time it takes for the installation process to complete I use the measure-command cmdlet, in powershell, which enables you to measure the running time of a command or script down to the millisecond.
After cloning the project, I start the package installation using `npm install`.
> git clone https://github.com/ng-lightning/ng-lightning.git > cd ng-lightning > measure-command {npm i} | select @{n="time";e={$_.Minutes,"Minutes",$_.Seconds,"Seconds",$_.Milliseconds,"Milliseconds" -join " "}}
The package installation completed in 2 minutes 13 seconds 768 ms (00:02:13.768).
Using Yarn (0.16.1, no lock file)
We followed the same steps as before, and use the built-in timer yarn has.
The first time yarn install
is executed, a lock file is generated in order to resolve issues around versioning and non-determinism. These lockfiles lock the installed dependencies to a specific version, and ensure that every install results in the exact same file structure in node_modules
across all machines. The written lockfile uses a concise format with ordered keys to ensure that changes are minimal and review is simple.
> git clone https://github.com/ng-lightning/ng-lightning.git > cd ng-lightning > yarn instal
The package installation completed in 1 minute 46 seconds and 120 ms (00:01:46.120).
Using Yarn (with lock file)
I deleted the node_modules
folder and executed again the yarn install
command. Due to the lock file generated from the previous installation, I was expecting to see an even faster package installation.
The package installation completed in 1 minute 37 seconds and 140ms (00:01:37.140).
Conclusion
Package installation using yarn
is about 25% faster, compared to npm install
, the first time you use it, where no lock files are created, and about 37% faster after the lock files are created.