asdf-nodejs: yarn global installs don't get shimmed

Steps to reproduce:

asdf plugin-install nodejs https://github.com/asdf-vm/asdf-nodejs
asdf install nodejs 7.10.0
asdf global nodejs 7.10.0
npm -g install yarn
yarn global add eslint
# eslint is not shimmed, so I cannot execute eslint without an absolute path

npm -g install eslint
# eslint is shimmed now in ~/.asdf/shims
# eslint works

Looking at the source, it seems that npm is the only package manager that’s managed in this plugin for postinstall hooks for shimming.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 49
  • Comments: 24 (8 by maintainers)

Most upvoted comments

@gipcompany I think that’s slightly different. If you run asdf reshim nodejs you’ll probably find your global shim now. See #47 and #56

You can fix this by configuring yarn to use a custom global prefix path.

You can run yarn config set prefix ~/.yarn, which will add the following line to your ~/.yarnrc:

prefix "/home/maddy/.yarn"

Then, just add ~/.yarn/bin to your PATH in your shell rc file, e.g. ~/.zshrc:

# Yarn bin
export PATH="$PATH:$HOME/.yarn/bin"

See https://github.com/yarnpkg/yarn/issues/630 for some more info.


Working example to show that installing global binary packages with yarn works as expected:

$ which yarn # yarn is installed via `npm` managed by `asdf`
/home/maddy/.asdf/shims/yarn

$ which grunt # grunt isn't installed yet
grunt not found

$ yarn global add grunt # globally install grunt with yarn 
yarn global v1.6.0
[1/4] Resolving packages...
[2/4] Fetching packages...
info fsevents@1.2.3: The platform "linux" is incompatible with this module.
info "fsevents@1.2.3" is an optional dependency and failed compatibility check. Excluding it from installation.
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "grunt@1.0.2" with binaries:
      - grunt
Done in 2.28s.

$ which grunt # grunt should now be installed and available in your `PATH`
/home/maddy/.yarn/bin/grunt

$ grunt --version # verify that we can successfully call grunt
grunt-cli v1.2.0

http://blog.scottlogic.com/2017/06/06/does-npm5-deprecate-yarn.html npm 5 is better, but still not as good as yarn… I’d like first-class support for yarn in this plugin as well.

Ya, I believe it’s still present. Even though I opened the issue, I don’t think this should be fixed.

Yarn doesn’t recommend npm install -g yarn as an installation method anyway (https://yarnpkg.com/lang/en/docs/install), and I don’t think it’s ever been recommended to install via npm. image

If you’re on a mac and install it via brew, or another system packager, you don’t need asdf to shim packages that’re installed via yarn since yarn is installed somewhere else on your system, and caches in different locations, and works independently of the nodejs version. asdf-nodejs only needs to worry about the nodejs version at this point, which in my book is 👍

Or, you could use npm which asdf-nodejs does shim bins for. Sometimes you have to run asdf reshim nodejs to make those npm install -g mypackage to be recognized, but it works. And ever since npm@5 supported lock files, it’s been suitable for use again.

Maybe there are compelling reasons for asdf-nodejs to support shimming yarn global installs, but I haven’t found any yet. Let me know if you know of any.

My comments above about Yarn are 2+ yrs old and about Yarn 1. I haven’t used Yarn 2 yet, but looks like it should be treated differently so perhaps this can be fixed now?

I’m not familiar with Yarn 2, but I’m sure the maintainers will accept PRs to make asdf-nodejs better. Since I don’t use Yarn 2 I’m not well-suited to contribute at this point.

I think this issue is not only about yarn, but also all the packages installed globally are involved!

e.g.) npm-check-updates is the same as below.

$ npm install -g npm-check-updates
$ which npm-check-updates
$ npm-check-updates -u
bash: npm-check-updates: command not found

So, this issue should be fixed.

Yarn doesn’t recommend npm install -g yarn as an installation method anyway (https://yarnpkg.com/lang/en/docs/install), and I don’t think it’s ever been recommended to install via npm. image

Things have changed with yarn 2. They now recommend to install yarn globally with npm and then spawn a per-project installation with the globally installed version.

If I understand correctly, this means that there is no need for multiple yarn installations anymore and installation via <your OS-specific tool> is more suitable.

Couldn’t yarn decome a first class citizen on asdf-nodejs like it is in the docker node containers?

asdf v0.7.0 (installed via homebrew) node v10.15.3 (installed via asdf)

$ brew install yarn --ignore-dependencies
🍺  /usr/local/Cellar/yarn/1.13.0: 14 files, 4.7MB, built in 8 seconds

$ yarn global bin
/Users/username/.asdf/installs/nodejs/10.15.3/.npm/bin

$ yarn global add grunt
yarn global v1.13.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Installed "grunt@1.0.3" with binaries:
      - grunt
✨  Done in 4.92s.

$ which grunt
$ asdf reshim
$ which grunt
/Users/username/.asdf/shims/grunt

$ grunt --version
grunt-cli v1.2.0

I found the below behavior a little strange. I think I’d rather just have the shim not exist if not installed for a given version.

Due to one unfortunate nature of Yarn (one global install for all), after performing a global add <package> while set to a particular node version all installed bins will be symlinked.

This can seem a bit odd. If you switch to another node version, and are expecting this behavior, you’ll need to run yarn global add, and then run asdf reshim before the bins will be available to you.

It might be best to have yarn use a private bin folder – often defaulted to /usr/local/bin for MacOS, for example as occurs naturally when using nvm (nvm is not compatible with npm’s prefix config, and screams loudly about it if it is set).

$ asdf global nodejs 8.10.0
$ which grunt
/Users/username/.asdf/shims/grunt
$ grunt --version
asdf: No version set for command grunt
you might want to add one of the following in your .tool-versions file:

nodejs 10.15.3

# yarn hasn't yet symlinked bins for this version in my case, so naturally this won't work.
$ asdf reshim
$ which grunt
/Users/username/.asdf/shims/grunt
$ grunt --version
asdf: No version set for command grunt
you might want to add one of the following in your .tool-versions file:

nodejs 10.15.3

$ asdf global nodejs 10.15.3
$ which grunt
/Users/username/.asdf/shims/grunt
$ grunt --version
grunt-cli v1.2.0

It certainly would be nice if shims could be recreated after yarn global add. There doesn’t appear to be a way to configure yarn to do this – no apparent post-global add hook.

I’m coming to the conclusion that it may be best to manage global packages using NPM. I’ve had some trouble in the past with global packages that require node-gyp when installing with yarn, using a version manager, and needing those packages to be available for multiple versions of node.

@squarism https://yarnpkg.com/en/docs/install#mac-stable brew install yarn --without-node might be what you’re looking for

yarn config set prefix doesn’t work for me for some reason. But I end up with use yarn global dir to find where yarn install the global modules, then put ~/.local/share/yarn/global/node_modules/.bin in my $PATH.

I don’t see why this would be a worse problem in yarn v2 as system-wide installations have been removed. Apparently, since its inception (more on this github issue). And I agree with this direction. The best recommendation for using commands from packages is by using either npx or yarn dlx, as it solves a lot of problems that might arise from having different installations of the same package in different node versions/prefixes.

If you are sure about installing global commands (there are some fair points to do it), the recommended way would be not to run yarn global add at all and stick to using npm install -g. Because they are global installs, there’s no practical difference between using npm or yarn for it (aside from performance, that by itself is questionable as npm is getting faster as it’s being actively updated, differently from yarn v1)

As this was a decision made by the yarn team itself, I’m marking this issue as wontfix. We are already support auto-reshimming of npm global installs, that should be on all occasions virtually the same as yarn global installs. If you are adamant about using yarn instead of npm, you can implement a wrapper on your own. Just adding a function like this to your .bashrc/.zshrc should suffice for the most cases:

yarn() {
  command yarn "$@"
  if [ "$1" = global ]; then
    asdf reshim nodejs
  fi
}

Unfortunelly the problem persists.

In fact, it becomes more problematic due to changes on yarn installation instructions.

As @dbernheisel mentioned, using npm install -g yarn was not recommend. But now, the new recommendation (since Node version 16.10.0) is use embedded yarn (if I understood correctly) boarded on new nodejs versions.

Using the command corepack enable the user will able to use yarn binaries delivered with Node (it means no more need to use homebrew, for example).

Well, this new method doesn’t work with ‘asdf’ too. You need to manually reshim nodejs to allow you call this embedded yarn after run corepack enable.

And, of course, any subsequent call of yarn global add <package-name> stills require another reshim to allow user interact with new global packages.

About change yarn configurations (like yarn config set prefix) or even change PATH environment variable, I believe it cannot be an user task, it must be automated in someway. The suggestion from @brewster1134 whom created a catching .tool-versions loading script and react changing $PATH seems a good idea to me, but I’m not sure it solve all scenarios (at least the corepack enable use case isn’t covered).

… Even though I opened the issue, I don’t think this should be fixed.

Yarn doesn’t recommend npm install -g yarn as an installation method anyway (yarnpkg.com/lang/en/docs/install), and I don’t think it’s ever been recommended to install via npm.

@dbernheisel: @cbows is correct above. Yarn 2 behaves differently now. asdf reshim nodejs works for me, but I’d rather not have to run that every time I install a package via yarn global add xyz.

If I have to I will uninstall my npm version of yarn and instead use brew install yarn --without-node, but the reason I switched to asdf in the first place was to manage all language and tooling installs on my machine with a single tool.

(I don’t mind either way; this is just my personal preference.)

yarn config set prefix doesn’t work for me for some reason. But I end up with use yarn global dir to find where yarn install the global modules, then put ~/.local/share/yarn/global/node_modules/.bin in my $PATH.

For me, this works. The prefix doesn’t work and I do not know why. By the way, I think that is a better way to fix this issue.

@dbernheisel Yes, I installed yarn via apt and this was solved. Also other issues have been resolved by asdf reshim too. Also there is a PR to throttle postinstall so it only runs after the last package. I guess we can close this issue as it can be misleading to new users trying out asdf.