Schniz / fnm

🚀 Fast and simple Node.js version manager, built in Rust
https://fnm.vercel.app
GNU General Public License v3.0
17.81k stars 454 forks source link

[Request] Automatically install default packages #139

Open chocolateboy opened 5 years ago

chocolateboy commented 5 years ago

(There are some similar-sounding issues, but they're talking about sharing global packages across different versions rather than installing them per-version.)

It'd be nice to be able to automatically (re-)install a list of global packages when a new version is installed as can be done via the default-packages file in nvm:

If you have a list of default packages you want installed every time you install a new version we support that too. You can add anything npm would accept as a package argument on the command line.

e.g.:

$ cat $NVM_DIR/default-packages
jay-repl
tmpin
web-ext

Or, failing that, some kind of post-install hook?

Schniz commented 5 years ago

Edit: this comment is very poisonous and I'm sorry for what it says. There are clear usages of using global installations. A well-defined and easy-to-use solution can probably be developed to help users use their favorite tools without all the hassle, like downloading them every time with npx my-tool.

As I don't use global packages, I don't have this kind of problems. I think that using global packages that are linked to the current Node version is mostly a user configuration smell. It is exactly like global variables. Most packages should be installed as a devDependency or a direct dependency to the project you're working on. It's easier to manage, and if you need an escape hatch, we have tools like npx.

Anyway, thanks for opening the issue. It keeps showing me that my way of using the computing machine is not the only way to do so, and things need to get better. However, I don't think we should allow bad practices.

It'd be nice to be able to automatically (re-)install a list of global packages when a new version is installed as can be done via the default-packages file in nvm

This is an interesting idea but would make installation much, much slower. Also, it will produce inconsistencies and I'm not sure this will be used eventually, because you can have multiple versions (node 6 will have tsc@2, node 8 will have tsc@3.5, node 10 will have tsc@3.6 etc).

This comment suggests a different solution: having a new binary that will work like gnpm install tmpin will install tmpin using the current node version, and add a small bash script that fixes the current node version into $FNM_DIR/global-packages/tmpin or any binary listed in package.json#bin. Maybe gnpm isn't a good name. Maybe fnmpm? idk. I'm bad with naming!

I'd be happy to develop that, but I don't have the time right now. I think this is a wonderful idea for an open-source, and if someone needs any help (by providing help with Reason or providing an API for fnm), I'd be glad to assist.

Or, failing that, some kind of post-install hook?

I also had the same thought. This is an interesting idea but opens up security holes. What if something calls sudo fnm ...? Should the post-hook call it?

I think you can manage by having an executable file called fnm that will have precedence, and hook it yourself:

#!/bin/bash

$FNM=/usr/bin/local/fnm

/usr/bin/local/fnm $*

FNM_STATUS_CODE=$?

if [ "$1" == "install" && "$FNM_STATUS_CODE" == "0" ]; then
  do_my_thing
fi

instead of having hooks, you can compose your solution with simple scripting.

chocolateboy commented 5 years ago

As I don't use global packages, I don't have this kind of problems.

I think that using global packages that are linked to the current Node version is mostly a user configuration smell. It is exactly like global variables. Most packages should be installed as a devDependency or a direct dependency to the project you're working on. It's easier to manage, and if you need an escape hatch, we have tools like npx.

I don't think we should allow bad practices.

:confused: None of the packages I mentioned (and none of the other packages I have in default-packages) are project-specific. They're just general-purpose command-line tools I want to bring with me across upgrades. I use them for various tasks, not just "node projects". Here are some more:

I suppose if they were available via a package manager, I'd install most of them that way, but that's unlikely to happen in most cases just as e.g. most commands available as gems or CPAN modules (including my own) aren't packaged. Either way, I'd love to be able to discuss (or close) this without it turning into a sermon about how evil it is to use node the same way I use bash, perl, python, ruby, and every other interpreter on my system :-)

(Also, it sounds like you do use global packages, just in a different (shared) directory, with all the risks of breakage/incompatibility that entails).

instead of having hooks, you can compose your solution with simple scripting.

Yes, that's pretty much what I'm doing, e.g.:

upgrade-node() {
    fnm install latest && xargs -a ~/.fnm/default-packages npm install -g
}

I can live with this. Just thought it might be worth considering at least facilitating a way to do this directly as it's a common requirement and there might be other uses for this kind of hook/plugin support.

Schniz commented 5 years ago

Hey! I just talked to @ronami about the same thing, and I first want to say I'm sorry. Didn't want to say that it's evil or something :) just that I wouldn't use global packages, however, I use a shared directory for like, 4 packages or something, that I'd really rather have installed using Homebrew, apt, etc, probably packaged with Zeit's pkg so if it works best with Node 6, it'll always run with Node 6, and don't force my computer to have a different Node installed.

😕 None of the packages I mentioned (and none of the other packages I have in default-packages) are project-specific. They're just general-purpose command-line tools I want to bring with me across upgrades. I use them for various tasks, not just "node projects".

You're right. I'm sorry for my last comment, which looks very poisonous when I reread it now.

I think that the best option for general-purpose command-line utilities that aren't distributed using the system's package manager is to have something like I suggested. A small wrapper around fnm and npm/yarn, if you'd like.

I can live with this. Just thought it might be worth considering at least facilitating a way to do this directly as it's a common requirement and there might be other uses for this kind of hook/plugin support.

Yeah, I agree but I think we should fix the underlying issue - supporting global packages, let's do this. Even if we'll add hooks, I think that simple users won't understand how to use them, and it'll be used by just a few. I think we can create a simple binary that fixes this huge issue. But maybe it won't be as simple as I think 😜

What do you think?

I hope I'll have time to sketch a simple POC in the next week or so

chocolateboy commented 5 years ago

No worries :-) Thanks for discussing it :+1:

I'd really rather have installed using Homebrew, apt, etc, probably packaged with Zeit's pkg so if it works best with Node 6, it'll always run with Node 6, and don't force my computer to have a different Node installed.

Yes, agreed. I'm hoping QuickJS (which can compile to native code) will become an option for this as well once a Node.js compatibility shim emerges.

I think we can create a simple binary that fixes this huge issue. ... What do you think?

Sounds great, thanks!

Schniz commented 5 years ago

Yes, agreed. I'm hoping QuickJS (which can compile to native code) will become an option for this as well once a Node.js compatibility shim emerges.

woooo QuickJS looks awesome!

sidoruk-sv commented 4 years ago

@Schniz, as I understood this feature request, it's about migrating global packages when upgrading from one Node.js version to another. And it would be cool to have such behavior in fnm, for example of that in nvm:

nvm install 13 --reinstall-packages-from=12

explained here: https://github.com/nvm-sh/nvm#migrating-global-packages-while-installing

Schniz commented 4 years ago

yeah, it makes sense. I will happily accept a PR that adds --reinstall-packages-from option to install. How can you know whether to use yarn or npm?

ljharb commented 4 years ago

You’d know because it’d be the one that ships with node.

Schniz commented 4 years ago

I started playing around with a solution for consistent global package installations — https://github.com/Schniz/gpkg

It'll always use the same Node version, no matter what version you currently use. So, if a binary needs Node 13, you can still use it if you're currently useing Node 12 :)

Immortalin commented 3 years ago

@Schniz any progress on this?

Schniz commented 3 years ago

@Schniz any progress on this?

Hmmm sure but regarding what? Adding —reinstall-packages-from=?

Schniz commented 3 years ago

@Schniz any progress on this?

Hmmm sure but regarding what? Adding —reinstall-packages-from=?

I’ll explain more to support async communication 😄 i haven’t implemented that yet. I’d be happy to receive a PR, if that’s what you’re after. 😸

libook commented 3 years ago

Is there anyone working on "—reinstall-packages-from" feature? Please reply so that I would wait for it instead of repeating the try(I am a noob in Rust).

libook commented 3 years ago

I have been trying to add —reinstall-packages-from= into fnm in these days. Unfortunately, I have failed. I realized that fnm can only call functions from itself. When I want to list packages of old version and install them into new versions. I have to call npm. It seems I can only call npm with a shell script.

There may be a better way that I don't know.

libook commented 3 years ago

I have sent a PR: https://github.com/Schniz/fnm/pull/510