npm / rfcs

Public change requests/proposals & ideation
Other
730 stars 240 forks source link

[RRFC] Add a Warning Message When Installing Packages into Home Directory #753

Open stevenmhunt opened 10 months ago

stevenmhunt commented 10 months ago

Motivation ("The Why")

When new and inexperienced users are installing packages with npm, they may accidentally open a new terminal to their home directory and then run npm install. This can occur if they are installing a package globally and forget to add -g or it can be the case that they weren't aware of their present working directory. In either case, the result is a ~/node_modules directory which can cause unexpected behaviors in other node projects on their machine.

Example

$ cd ~
$ npm install lodash

added 1 package in 943ms

How

Current Behaviour

At this time, there is no warning regarding this situation so when the user performs this action accidentally it occurs silently only to cause problems in the future. Let's consider the following scenario:

$ cd ~
$ node -v
v18.13.0
$ npm install node@12

added 2 packages, and audited 422 packages in 10s

52 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

The current terminal environment is running NodeJS 18.13.0 and NPM 9.2.0 and the user has now asked NPM to install the node version 12 package in their home directory. Realistically this scenario more likely to occur if installing a package which references node as a dependency. Now, running ~/node_modules/.bin/node -v in this example will output "v12.22.12".

What will happen now is if the user makes any reference to node or npm within the npm-run-script section of any package.json file located within a subdirectory of the home directory (which will typically be the case for most people), NPM will use the other version of NodeJS because ./node_modules/.bin of the current directory as well as all parent directories is added to PATH by NPM when running script commands:

~/projects/some_node_app/package.json:

{
    ...
    "scripts": {
        "which": "which node",
        "test": "jest",
        "lint": "eslint \"**/*.js\"",
        "build": "npm run lint && npm test"
    }
    ...
}
$ cd ~/projects/some_node_app
$ npm run which

/home/user/node_modules/.bin/node

Because NPM is sensitive to the specific version of NodeJS being used, this specific situation will produce an error because the currently running version of NPM is incompatible with the hidden version of NodeJS:

$ npm run build

> build
> npm run lint && npm test

ERROR: npm v9.2.0 is known not to run on Node.js v12.22.12. You'll need to
upgrade to a newer Node.js version in order to use this version of npm. This
version of npm supports the following node versions: `^14.17.0 || ^16.13.0 ||
>=18.0.0`. You can find the latest version at https://nodejs.org/.

ERROR:
/usr/share/nodejs/npm/lib/utils/exit-handler.js:22
  const hasLoadedNpm = npm?.config.loaded
                           ^

SyntaxError: Unexpected token '.'
    at wrapSafe (internal/modules/cjs/loader.js:915:16)
    at Module._compile (internal/modules/cjs/loader.js:963:27)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
    at Module.load (internal/modules/cjs/loader.js:863:32)
    at Function.Module._load (internal/modules/cjs/loader.js:708:14)
    at Module.require (internal/modules/cjs/loader.js:887:19)
    at require (internal/modules/cjs/helpers.js:74:18)
    at module.exports (/usr/share/nodejs/npm/lib/cli.js:76:23)
    at Object.<anonymous> (/usr/share/nodejs/npm/bin/npm-cli.js:2:25)
    at Module._compile (internal/modules/cjs/loader.js:999:30)

Throughout this entire scenario NPM has been working as intended and the root cause of this error is the user mis-configuring their environment. However, I believe that since this is detectable situation that has been reported by users it is worth adding a warning message to bring attention to a potentially confusing issue.

Desired Behaviour

It would be ideal to present the user with some sort of warning about installing packages in their home directory so that way they are made aware of the fact that they may be introducing unexpected behaviors in the future.

$ cd ~
$ npm install lodash
WARNING: Installing NPM packages in your home directory can have unexpected consequences.
added 1 package in 943ms

References

ljharb commented 10 months ago

Maybe npm could go a step farther and just refuse to work in the home directory entirely?

stevenmhunt commented 10 months ago

I would be hesitant to suggest that, I'm not sure if someone out there has a legitimate reason to do this such as installing scripts in a Docker container for instance. I also think that from a political standpoint it's going to be much easier for the community to agree to adding a warning message than on implementing a behavior change. In the real world situation I just dealt with which prompted me to write this post, I believe that a warning message would have been sufficient to avoid further complications.

wesleytodd commented 10 months ago

Maybe npm could go a step farther and just refuse to work in the home directory entirely?

Preferably not. I do not install packages globally, and I do have a few packages I install in my home directory and I handle setting up my path correctly for that. These are tools I use outside of specific projects. Frankly I think that refusing to do global installs is better than refusing to do home directory installs but both are anti-patterns if you are using the tools in a project where they should be installed as dev deps. But I also dont think that is a change worth the effort from npm.