Preventing npm commands in favor of pnpm
Asked Answered
S

7

12

I would like to switch to using PNPM over NPM for the usual reasons. Unfortunately cut and paste, or muscle memory takes over sometimes and I will accidentally use NPM to install a package in a project that is using already using PNPM. Things do not go well for that project anymore.

I am hoping to block or alias NPM commands in favor of PNMP.

Things I have tried:

  1. Only Allow - although promoted on the PNPM site, it does not seem to work, at least not work for individual imports which is the most common use case.

  2. Since my terminal is Oh My ZSH, I found code to add to ~/.zshrc to block npm if in a directory containing a PNPM lockfile.

NPM_PATH=$(which npm)
npm () {
  if [ -e PNPM-lock.yaml ]
  then
    echo "Please use PNPM with this project"
  elif [ -e yarn.lock ]
  then
    echo "Please use Yarn with this project"
  else
    $NPM_PATH "$@"
  fi
}

This seems to work for my purposes, but does anyone have any cleaner / less zsh-specific alternatives?

And in the case where it does happen, what is the recommended steps to recover a PNMP projected tainted by an NPM install?

Sponge answered 13/3, 2022 at 17:11 Comment(1)
That's what I use as well. It could be a package-deal thing 😅 I tried pnpm env and it has npm bundled. $ pwd && ls produces /home/michael/.local/share/pnpm and global node nodejs npm npx pnpm pnpx store ```Kristynkrock
E
6

You've already mentioned the only-allow package.

NodeJS v16.9.0 and v14.19.0 support a new experimental packageManager field in the package.json file.

Type: <string>

{
  "packageManager": "<package manager name>@<version>"
}

The "packageManager" field defines which package manager is expected to be used when working on the current project. It can be set to any of the supported package managers, and will ensure that your teams use the exact same package manager versions without having to install anything else other than Node.js.

This field is currently experimental and needs to be opted-in; check the Corepack page for details about the procedure.

To recover a PNMP projected tainted by an NPM install, as long as you've specified your dependency versions as you'd really like them to work, you could just delete the node_modules folder and the package-lock.json file. But you could also take a look at PNPM's import subcommand

pnpm import generates a pnpm-lock.yaml from another package manager's lockfile [...]

Exhilarate answered 14/2, 2023 at 21:3 Comment(0)
L
4

When it's project-specific you could use this https://www.freecodecamp.org/news/how-to-force-use-yarn-or-npm/

I've been using it because we switched to PNPM, and I was still constantly using yarn for some reason.

Leg answered 21/10, 2022 at 7:10 Comment(1)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From ReviewOdense
S
2

According to these articles it is enough to add to your package.json:

"scripts": {
  "preinstall": "npx only-allow pnpm", 
  ...
}

I assume that you first need to install the only-allow package for that, even though such a step is missing from both tutorials.

2.

Alternatively, this article was written for Yarn, but should apply to pnpm equally:
You can create/edit a .npmrc file with the following

engine-strict = true

And then in package.json

"engines": {
   "npm": "please-use-pnpm",
   "pnpm": ">= 2.0.0"
},

Finally, it should be pointed out that Node v16+ supports a expected package manager with the experimental Corepack

corepack prepare pnpm@latest --activate

I have not tested any of the above, but they should all prevent running npm instead of pnpm.

Smokestack answered 21/8, 2023 at 12:23 Comment(0)
H
1

I have added the following function called npm in my .zshrc file


npm () {
    bash -c "if grep -sq 'pnpm' package.json; then pnpm $@; else npm $@; fi"
}

This function tests if you have mentioned pnpm as your "packageManager" in which case it uses pnpm, otherwise defaults to npm

Halpern answered 13/2, 2023 at 10:15 Comment(0)
P
0

edit package.json file, add this:

"engines": {
    "npm": "please-use-pnpm",
    "yarn": "please-use-pnpm",
    "pnpm": ">= 8.0.0"
},

create .npmrc

engine-strict = true
Pea answered 26/3 at 8:14 Comment(0)
R
0

You can use only-allow

"scripts": {
  "preinstall": "npx --yes only-allow pnpm",
  "preupdate": "npx --yes only-allow pnpm",
  ...
}

preinstall pre-executes when doing an install

preupdate pre-executes when doing an update

You will get this error when installing or updating a package using any package manager other than pnpm

Use "pnpm install" for installation in this project.

enter image description here

Rectilinear answered 28/4 at 10:30 Comment(0)
S
0

I came here looking for a good answer to your same question; what I really wanted was a single alias that would just use whatever the project is already using. I found this article really matched my need*, and thought it might fit yours too.

But I wanted mine to work a bit differently. My main use case is I want to be able to type run dev and have it know either pnpm dev or npm run dev.

run() {
  if [[ -f pnpm-lock.yaml ]]; then
    command pnpm "$@"
  elif [[ -f bun.lockb ]]; then
    command bun "$@"
  elif [[ -f yarn.lock ]]; then
    command yarn "$@"
  elif [[ -f package-lock.json ]]; then
    command npm "run $@"
  else
    command pnpm "$@"
  fi
}

FYI This should work for any commands in your scripts object for all the package managers; and it works for base commands like run install on most of the package managers too. It only fails when you are trying to use run install or other non-script commands with NPM. (Because it tries to do npm run install, which fails.)

Schreibe answered 17/7 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.