use-yarn-instead
use-yarn-instead copied to clipboard
Is there a good way to force developers to use yarn instead of npm?
This experimental module came from the discussion in https://github.com/yarnpkg/yarn/issues/1732, where the question was how to prohibit the use of npm on a project and point developers to using yarn instead.
This module doesn't really solve that problem, but merely logs things that are easy to miss. @farisj tried a couple of other things, but none did work.
So the question is, is there a way or hack to for instance hijack npm install? Should this even be necessary?
Isn’t this a little bit rude?
Seriously, suggesting yarn is one thing, forcing it is another. There’s a contract that both are respecting, and that npm carefully crafted in years. Also you are incorrectly inferring that there’s just npm and yarn, but actually there are tons of other package managers for completely unexpected environments — from atom to Java platforms.
So my question is, why would you ever want to force it?
My own use case for this is such: I am working on a medium size team and we are considering moving one of our applications to yarn over npm. However, I'd want to ensure everyone on my team is using yarn commands over npm. Yes, I can tell everyone to use yarn run over npm run, but I want to correct for human error and force that behavior.
With Rails and Bundler, for instance, bundler will prevent me from booting my rails server if I don't prepend my commands with bundle exec in scenarios where I'm working with the wrong versions of gems. This behavior ensures we're using all of the gems specified in the Gemfile.lock, even if people have global gems installed elsewhere, etc.
It would greatly ease the transition of my coworkers remembering to use yarn on our app if they had no choice about the matter. For me, this feature is about managing a team and ensuring that everyone has the same setup. Just having the yarn.lock file is pointless if I can't get my fellow employees to use it.
@yuchi , your comment about this issue being rude is unnecessary. I agree that I wouldn't want to force other developers to use it outside of my own company, but internally we are trying to optimize our workflow across the team, so having a way to force the use of yarn is very desirable to me.
@farisj it‘s totally understandable then, but I’m scared by the possibility of this practice becoming widespread. We’ve seen this on the iojs/node debate—and while this one is not an issue on political ground, I’m a little disenchanted on people by now.
To support my question, I got to this repo by because someone I follow stargazed it. But the rationale you explained was nowhere to be found. A little warning «don’t use it on modules—for enterprise use only!» would help a lot in communicating the goal of this project.
I agree the README does not explain the purpose of this – almost entirely experimental – repo very well. I'll add a clearer description!
I disagree that the enforcing of a certain tool is any more rude than choosing a database or linting code. Like @farisj said, it's about assuring quality and shipping software that works.
https://github.com/alexanderwallin/use-yarn-instead/commit/b4740bcd60f13fed3c2d468ecc565b1991a96871
Thank you!! Looks great :)
By the way probably I will be using it in a project or two, so thanks twice!
Ah, cool! Please come back with any feedback you might have.
I have the exact same situation as @farisj explained above. What's the point of using yarn if I can't make sure that yarn.lock doesn't get out of sync? Want to avoid other to run npm i or modifying directly package.json without using yarn
npm and yarn seem to both extend the process.env when executing scripts ... https://github.com/npm/npm/blob/5d17fc945bcf48b69bc0dc4741028762f6bca02c/lib/utils/lifecycle.js#L76 and https://github.com/yarnpkg/yarn/blob/508c959080c52183697602f52ebb95b086b6b3d3/src/util/execute-lifecycle-script.js#L33 ...
So I just went full dictator and this is what I got:
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
It does the job.
Holy moly! That's some impressive digging. Feel free to fire away a PR if you want.
Just released a module that includes a CLI to do this (useful for preinstall scripts): https://github.com/AndersDJohnson/use-yarn
Stay tuned, as I may have more ideas coming, especially around CI.
FYI @alexanderwallin @Sinewyk @farisj @rafayepes
I've also just released a helper for Danger to check for missing yarn.lock changes on CI:
https://github.com/AndersDJohnson/danger-yarn-lock
FYI @alexanderwallin @Sinewyk @farisj @rafayepes
I solve that with husky and lint-staged and adding the following to package.json:
{
"scripts": {
"precommit": "lint-staged"
},
"lint-staged": {
"+(package.json|yarn.lock)": [
"node ./scripts/yarn-check.js"
]
},
"devDependencies": {
"husky": "^0.13.2",
"lint-staged": "^3.4.0"
}
}
And then, that yarn-check.js script is
'use strict';
const execSync = require('child_process').execSync;
const chalk = require('chalk');
try {
execSync('yarn check').toString();
} catch (error) {
console.log(
'\n' +
chalk.red(` This project uses ${chalk.underline.bold('yarn')} to install all JavaScript dependencies.\n`) +
chalk.red(` Please don't modify the dependencies manually in package.json nor use npm install to update them.\n`) +
chalk.dim(' Please run ') +
chalk.reset('yarn add [package-name]') +
chalk.dim(' to install any new dependency\n') +
chalk.dim(' or') +
chalk.reset(' yarn upgrade [package@version]') +
chalk.dim(' to upgrade a dependency to a specific version.\n') +
chalk.dim(
' Ensure you commit both the package.json and the yarn.lock files together.\n'
) +
chalk.dim(' Check out ') +
chalk.underline.blue('https://yarnpkg.com/en/docs/cli/') +
chalk.dim(' for more information.') +
`\n`
);
process.exit(1);
throw error;
}
FYI @alexanderwallin @Sinewyk @farisj @adjohnson916
@rafayepes Nice! That works on local machines, but yarn check could be run on CI too.
@AndersDJohnson on CI you can install dependencies using yarn install --frozen-lockfile --non-interactive, which will fail if yarn.lock was not properly updated.
@alexanderwallin I've found that running yarn check on precommit and yarn install --frozen-lockfile --non-interactive to install dependencies on CI ensures that yarn is used instead of npm. Does that answer your initial question?
As extra info, we are also running now yarn install --pure-lockfile --non-interactive on both postcheckout and postmerge, to ensure everyone has always latest dependencies installed
npm install packageName how hook
@rafayepes It seems you've got some nice solutions going here. I think I'll leave this issue open indefinitely to allow different solutions to be published, but big thanks for sharing!
(Not a yarn user myself, so won't evaluate specific solutions.)
🎈
The above helps for plain npm installs, but doesn't work when installing/adding a package to an app. To solve for this, I intentionally create a broken package-lock.json file with the following inside it
See_package-lock.json
Please don't use npm within this repo; please use yarn instead.
This makes it so when I npm i or npm i --save-dev typescript, this occurs:

This does create a warning when yarn installing/adding, but I think that's fine as this definitively prevents using npm.
- add script
package.json
"preinstall": "node ./scripts/checkYarn.js",
npm will auto-execute the script.
- checkYarn.js
if (!/yarn\.js$/.test(process.env.npm_execpath || '')) {
console.warn(
'\u001b[33mThis repository requires Yarn 1.x for scripts to work properly.\u001b[39m\n'
)
process.exit(1)
}
when you execute npm install, it will error

Set engines in package.json
{
...
"engines": {
"npm": "use yarn instead of npm."
}
}
When you use npm i
npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for {project-name}@{version}: wanted: {"npm":"use yarn instead of npm."} (current: {"node":"14.5.0","npm":"6.14.5"})
npm ERR! notsup Not compatible with your version of node/npm: {project-name}@{version}
npm ERR! notsup Not compatible with your version of node/npm: {project-name}@{version}
npm ERR! notsup Required: {"npm":"use yarn instead of npm."}
npm ERR! notsup Actual: {"npm":"6.14.5","node":"14.5.0"}
@tktcorporation Do you put that in the project's package.json? Or in this package which you install as a dependency?
@alexanderwallin
@tktcorporation Do you put that in the project's package.json? Or in this package which you install as a dependency?
I put it like this.
{
"name": "sample",
"version": "1",
"description": "",
"author": "tktcorporation",
"engines": {
"npm": "use yarn instead of npm."
},
"scripts": {
"build": "tsc",
},
"dependencies": {},
"devDependencies": {}
}
and write engine-strict=true on a file .npmrc
ref: https://qiita.com/suin/items/a7bf214f48eb9b2d9afc
Another
I found another way to do that.
{
"name": "sample",
"version": "1",
"description": "",
"author": "tktcorporation",
"scripts": {
"preinstall": "npx only-allow yarn"
},
"dependencies": {},
"devDependencies": {}
}
It is needed to put "preinstall": "npx only-allow yarn" to scripts.
And it is not needed to install only-allow
ref: https://qiita.com/suin/items/e0fbdd9af1150138a65c