statusboard
statusboard copied to clipboard
BREAKING CHANGE(bin): remove command
Why is this being removed?
npm bin currently does not accurately represent everywhere npm looks for a bin when one is asked for. Providing it as a command invites folks to add it to their $PATH which is discouraged: npm should be finding those, not your os. The bin discovery of npm is more than just looking in the one folder, it actually walks up from whatever folder the package is in, looking for a .bin folder in any node_modules it finds. This is how scripts that call npm run can get the version of a given package they asked for, instead of whichever one "wins" by being hoisted.
In global mode, bin is simply where node is.
If the command is going to be removed, it would be great if the algorithm itself was documented.
(Posting here for visibility.) There is a discussion at https://github.com/npm/feedback/discussions/807 to find an alternative for a use case broken by this change.
If npm run behaved more like yarn run then I would think this change was acceptable. However npm run still does not execute ./node_modules/.bin it appears.
Looks like $(npm root)/.bin is the closest you can get to this now?
@nmccready that's what npx is for.
Thank you I will look into this.
There's a lot of discussion of npm bin here but there's a slightly different use case for npm bin -g. What is the replacement for npm bin -g to find the folder where npm installs globally-available executables?
Providing it as a command invites folks to add it to their
$PATHwhich is discouraged: npm should be finding those, not your os.
Surely the global install path should be in your $PATH variable, right? This was one thing npm bin -g checked for.
Surely the global install path should be in your $PATH variable, right? This was one thing npm bin -g checked for.
The global install path should already be in your path because that is where node itself is. npm is installed into a given version of node alongside the node binary, the assumption being that if you can run node, npm can link bins into the same directory to have them also available to the end user without an extra $PATH entry.
The nuance here comes from the fact that Windows installs node/npm into a different directory structure than osx and linux. There is no bin directory in Windows. There is also no lib in Windows, the node_modules is also an immediate subdirectory of the one in which the node binary lives.
The npm bin command kind of put the cart before the horse and introduced a bit of bad "discovery" of this path based on npm, instead of node.
So for instance in fish shell this would be a more appropriate way of knowing where those bins lived
$ dirname (which node)
/Users/wraithgar/.nvm/versions/node/v18.12.0/bin
They really have nothing to do with npm, but with node itself.
In the Windows Node installer, it's more than just the different directory structure, the global packages are installed in a completely separate directory from the node installation. Being able to run node does not necessarily mean that the user is also able to run the globally installed packages. Taken from the installer, updating the PATH variable is split into two different "features".
* Add to PATH
* Node.js and npm - Add Node.js and npm (if installed) to the PATH environment variable
* npm modules - Add modules that are installed globally by npm to the PATH environment variable. This option works for the current user only.
With a clean install of node on Windows with these two features selected, it will add two separate locations to the PATH:
C:\Program Files\nodejs
C:\Users\<username>\AppData\Roaming\npm
This is because of the value of prefix decided by the builtin config, which is set to %APPDATA%\npm by default:
$ npm config ls
; "builtin" config from C:\Program Files\nodejs\node_modules\npm\npmrc
prefix = "C:\\Users\\<username>\\AppData\\Roaming\\npm"
If I then install a package (ex: typescript) with npm i -g typescript, this installs tsc to C:\Users\<username>\AppData\Roaming\npm\tsc which I'm only able to invoke successfully because of the second new entry in my PATH variable. This logic is entirely custom to npm, as it's derived from npm's prefix config value.
This all works seamlessly in the ideal case, but speaking as someone that handles troubleshooting for a large population of developers that are not always primarily doing Node/npm/JS development, incomplete or inaccurate PATH variables have been an uncommon yet consistent issue. It was useful for us to have npm bin -g as that could prompt the user to add the global package location to their PATH if it wasn't already set (as it would warn with (not in PATH env variable)).
Given the nature of Windows' two-location installation, this does seem like a Windows-only problem. As such, I'm not sure what the cleanest fix would be. For this use case we do not need any of the "non-global" functionality of npm bin without -g that allowed for the aforementioned bad behavior, so I'm not suggesting that this command be added back as it was. If the functionality to check the global install location (and also if that was in the PATH variable) could be added to an existing command (maybe npm prefix -g) or even a new command, that would work well for us. I'd be happy to contribute such a feature (whatever it may look like) if that sounds like a good idea to all involved.
This is very good feedback @molisani thank you for laying it out so clearly. Can you open a new issue in https://github.com/npm/rfcs suggesting we reintroduce a global only bin command? Your last comment can be copy/pasted there as a starting point I think. This closed issue definitely has no greater visibility w/in the org so discussion here is unlikely to result in any npm change.