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_modulesacross 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.
