How to force package installs to use yarn not npm
January 18, 2019
Leaving aside arguments over which node package manager is better, one thing that should be clear is that it’s a bad idea to switch between them in the same project, as conflicting lockfiles can leave the project in an unpredictable state. If you run yarn in a project that has a package-lock.json
from npm then it does warn you about this, but npm doesn’t do the reverse. If you run npm install
in a project with a yarn.lock
it will happily install the packages and create a package-lock.json for yarn to complain about next time. This is my solution.
If you add a "preinstall"
script to your package.json
it is run before any install by npm or yarn. If it exits with an error code then the install is aborted. This means it’s the perfect place to check. During script execution, the environment variable $npm_execpath
is set to the path of the npm or yarn executable, so we can use this to check what the install is using. You could use node to check this, but that seems like overkill, so I’m going to use shell commands directly inside the script. I echo the contents of the variable, pipe it to grep
, and if it doesn’t match yarn then it exits with an error. (I ❤️ emojis in shell scripts):
echo "$npm_execpath" | grep -q "yarn\.js$" || (echo '⚠️ Use yarn not npm! ⚠️' && exit 1)
This works great, but it can look confusing as it displays the full command when it’s run, so looks like there’s an error even when all is well. The way around this is to make it a separate script, which is run with the --quiet
flag. We can use $npm_execpath
again to be sure we’re running it with the same script:
"scripts": {
"preinstall": "$npm_execpath --silent run checkyarn",
"checkyarn": "echo \"$npm_execpath\" | grep -q \"yarn\\.js$\" || (echo '⚠️ Use yarn not npm! ⚠️ ' && echo && exit 1)"
}
If you run npm install
you get the error:
example git:(master) ✗ npm i
> example@0.0.1 preinstall /Users/matt/Documents/repos/example
> $npm_execpath --silent run checkyarn
⚠️ Use yarn not npm! ⚠️
npm ERR! code ELIFECYCLE
errno 1
…but if you run yarn
:
➜ example git:(master) ✗ yarn
yarn install v1.12.3
$ $npm_execpath --silent run checkyarn
[1/4] 🔍 Resolving packages...
success Already up-to-date.
✨ Done in 1.35s.
Happy installing!