DEV Community

Matt Kane
Matt Kane

Posted on

How to force package installs to use yarn not npm

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)
Enter fullscreen mode Exit fullscreen mode

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)"
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

...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.
Enter fullscreen mode Exit fullscreen mode

Happy installing!

Top comments (1)

Collapse
 
tonydehnke profile image
Tony Dehnke • Edited

Thanks.. Add this and I get a extra error and log file when I run npm. Have you run into this to?

npm ERR! Failed at the example@1.0.0 preinstall script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/example/.npm/_logs/2020-06-04T02_29_57_930Z-debug.log