Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: In npm v9, packages are always installed globally #6

Open
sounisi5011 opened this issue May 29, 2023 · 0 comments
Open

BUG: In npm v9, packages are always installed globally #6

sounisi5011 opened this issue May 29, 2023 · 0 comments

Comments

@sounisi5011
Copy link
Collaborator

sounisi5011 commented May 29, 2023

As reported in go-task/task#1081, local installation with npm v9 or later always installs binaries in the global directory.

This is because @go-task/go-npm always uses the environment variable npm_config_prefix to get the installation directory instead when the npm bin command fails.
In npm v9 and later, the npm bin command has been removed.

go-npm/src/common.js

Lines 25 to 49 in b3015da

// `npm bin` will output the path where binary files should be installed
exec('npm bin', (err, stdout, stderr) => {
let dir = null;
if (err || stderr || !stdout || stdout.length === 0) {
// We couldn't infer path from `npm bin`. Let's try to get it from
// Environment variables set by NPM when it runs.
// npm_config_prefix points to NPM's installation directory where `bin` folder is available
// Ex: /Users/foo/.nvm/versions/node/v4.3.0
const env = process.env;
// Get the package manager who is running the script
// This is needed since PNPM works in a different way than NPM or YARN.
const packageManager = usedPM();
if (env && env.npm_config_prefix) {
if (process.platform === 'win32') {
// On Windows, use the installation directory itself instead of the `bin` folder.
// See: https://docs.npmjs.com/cli/v6/configuring-npm/folders#executables
dir = env.npm_config_prefix;
} else {
dir = join(env.npm_config_prefix, 'bin');
}
} else if (env && env.npm_config_local_prefix) {

@go-task/go-npm should only use the npm_config_prefix environment variable when in global mode.
In the case of npm and pnpm, global mode can be detected by reading the npm_config_global environment variable.

process.env.npm_config_global === 'true'

However, in the case of Yarn V1, the npm_config_global environment variable does not exist, so the npm_config_argv environment variable should be parsed to determine this instead. I am still investigating the correct logic, but it is still buggy 1.

Note
This needs to be released as a breaking change.
When @go-task/go-npm is upgraded, the user's environment will no longer remove binaries that were previously installed by mistake.

For example, the following version range is specified in @go-task/cli:

"@go-task/go-npm": "^0.1.17"

--- https://github.com/go-task/task/blob/e0d3e33c32cfa0c99afd95b74086852983603a51/package.json#L32

In this case, when @go-task/go-npm is updated to a version such as 0.1.19, the @go-task/cli dependency is implicitly updated. Since postuninstall is not run at this time, task binaries that were incorrectly installed by @go-task/go-npm before this bug was fixed will not be removed.

Therefore, it is necessary to upgrade to a version out of this range (e.g. 0.3.0, 1.0.0).

Footnotes

  1. Currently it compares the order of the global and add arguments in the original property. However, from reading the Yarn v1 source code, it should probably be enough to check that the value of the cooked property is not ["add"]. But I haven't been able to test it with the old Yarn yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant