yarn
yarn copied to clipboard
[Question] How to prevent people from using `npm install <package name>`
By digging the issues I found
"scripts": {
"preinstall": "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\""
},
to prevent people from running npm install
But this line fails to prevent people from running npm install <package name>
Is there any way to prevent people from running npm install <package name>
?
Thanks! You are right, npm install <package> --save
still works, which is a bummer. And I couldn't find any trick (life-cycle callback, npmrc, ...) to convice npm
to disallow installation of new packages; but a git pre-commit hooks might be a solution.
I've made this small change to have a "cleaner" package.json file:
package.json:
"scripts": {
"preinstall": "node tools/preinstall-script.js"
}
tools/preinstall-script.js:
/**
* Do NOT allow using `npm` as package manager.
*/
if (process.env.npm_execpath.indexOf('yarn') === -1) {
console.error('You must use Yarn to install dependencies:');
console.error(' $ yarn install');
process.exit(1);
}
EDIT: Just found this in AMP: https://github.com/ampproject/amphtml/blob/master/build-system/check-package-manager.js
@SchnWalter I believe the preinstall trick above would also make it impossible for a user to install your package with npm, no?
As a dependency? I'm not sure. I'm not using this for public projects/libraries that someone would require as a dependency.
Hi. There's a way to do this already. You add a fake engine version like so in package.json:
"engines": {
"npm": "please-use-yarn",
"yarn": ">= 1.17.3",
"node": ">= 12.5.0"
}
Then you add an .npmrc
file to the project root with this:
engine-strict = true
Running NPM then raises an error:
npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for root@: wanted: {"npm":"please-use-yarn","yarn":">= 1.17.3","node":">= 12.5.0"} (current: {"node":"12.9.1","npm":"6.10.2"})
npm ERR! notsup Not compatible with your version of node/npm: root@
Hi. There's a way to do this already. You add a fake engine version like so in package.json:
"engines": { "npm": "please-use-yarn", "yarn": ">= 1.17.3", "node": ">= 12.5.0" }
Then you add an
.npmrc
file to the project root with this:engine-strict = true
Running NPM then raises an error:
npm ERR! code ENOTSUP npm ERR! notsup Unsupported engine for root@: wanted: {"npm":"please-use-yarn","yarn":">= 1.17.3","node":">= 12.5.0"} (current: {"node":"12.9.1","npm":"6.10.2"}) npm ERR! notsup Not compatible with your version of node/npm: root@
It doesn't worked here.
$ npm --version
6.12.0
$ node --version
v12.13.0
Accordingly with npm website engineStrict
was removed.
engineStrict This feature was removed in npm 3.0.0 Prior to npm 3.0.0, this feature was used to treat this package as if the user had set engine-strict. It is no longer used.
@rafaelfesi, that's for package.json
, not for the npmrc
files, which are used to configure NPM.
- https://docs.npmjs.com/files/npmrc
- https://docs.npmjs.com/misc/config#engine-strict
And the configuration works for me:
$ cat .npmrc
engine-strict=true
$ npm install
npm ERR! code ENOTSUP
npm ERR! notsup Unsupported engine for [email protected]: wanted: {"node":"^10.16","npm":"please-use-yarn"} (current: {"node":"10.16.3","npm":"6.13.0"})
...
I think pnpm has released the suitable package for this: only-allow
@hckhanh Neither only-allow nor any other solutions posted here prevent npm install <package-name>
unfortunately...
@hckhanh Neither only-allow nor any other solutions posted here prevent
npm install <package-name>
unfortunately...
You're right actually. My solution doesn't prevent that (though hopefully, the devs suspicions that you should use yarn would already be aroused if they previously tried to do a plain old npm install
). I would suggest this is actually a bug in NPM. That operation modifies the lock and package json, so it should check the engine. We should potentially raise that separately.
I would suggest this is actually a bug in NPM. That operation modifies the lock and package json, so it should check the engine. We should potentially raise that separately.
An RFC for having npm install X
run the preinstall script is here: https://github.com/npm/rfcs/issues/325
I don't know if there's one yet for the engine check you mention.
Do you guys have an update on this topic?
This might be helpful - https://www.freecodecamp.org/news/how-to-force-use-yarn-or-npm/.
This might be helpful - https://www.freecodecamp.org/news/how-to-force-use-yarn-or-npm/.
I'm actually the author of that article and here I am looking for a fix/workaround lmao
The right way going forward would be the packageManager
field, but npm doesn't support it yet.
Hi team, is there a way to adding constraints to package.json for preventing installing packages for certain users kind of access previlige
"engines": { "npm": "please-use-yarn", "yarn": ">= 1.17.3", "node": ">= 12.5.0" }
@adamscybot thanks for the approach, unfortunately Heroku does not like it 😞 it throws an error when trying to push to a remote to deploy.
remote: -----> Installing binaries
remote: engines.node (package.json): ^12.18
remote: engines.npm (package.json): please-use-yarn
remote: engines.yarn (package.json): ^1.17
remote:
remote: Resolving node version ^12.18...
remote: Downloading and installing node 12.22.10...
remote: Bootstrapping npm please-use-yarn (replacing 6.14.16)...
remote: Unable to install npm please-use-yarn; does it exist?
Too bad because it was working perfectly! I'll stick to the preinstall
script.
For those looking for an alternative solution, I've just published a tiny package that does the job: enforcepm
You don't need to install it, but you need to create a Git pre-commit hook and put this command inside of it:
npx enforcepm yarn
By the way you can take the "creating a pre-commit hook" thing as an excuse for using tools such as husky or lint-staged.
If you are already using such tool, then enforcing yarn is just a matter of copy/pasting the command above.
Hope it helps.
Some hosting providers will attempt to parse package.json and eventually fail when they encounter a key like
"yarn" : "Please use npm"
In order to bypass this issue you can maximize the version of the package manager you would like to exclude from the list, so for example:
"engines": {
"npm": ">= 8.0.0",
"yarn": "9999.9.9",
}
The above solution worked for Railway which parses package.json. I haven't tried with Heroku but I can imagine it will work as well.
This makes the assumption [email protected] won't happen in at least a million years but if you are skeptical just raise that number even more
I'm trying to do the reverse just using npm and not yarn but yarn 3
doesn't care about anything is like a Honey Badger
"engines": {
"npm": "please-use-yarn",
"yarn": ">= 1.17.3",
"node": ">= 12.5.0"
}
Works like a charm for my project, deploying only on netlify and vercel 😎
I added this to package.json
"engines": {
"npm": "please-use-yarn",
"node": "12.x - 16.x"
},
and
engine-strict = true
to .npmrc
It worked just fine. Thanks folks :)
I would note that you should only do this on your projects. If you do this on a package that is intended to be a dependency of another project (outside your control), I found that it forced the consumer to use my manager of choice instead of theirs.