- [#839](https://github.com/Schniz/fnm/pull/839) [`97be792`](https://github.com/Schniz/fnm/commit/97be792a4410d8f121e03a1f81f60c48cbfdee2c) Thanks [@amitdahan](https://github.com/amitdahan)! - Support resolving `engines.node` field via experimental `--resolve-engines` flag
> :rocket: Fast and simple Node.js version manager, built in Rust
> 🚀 Fast and simple Node.js version manager, built in Rust
<divalign="center">
<divalign="center">
<imgsrc="./docs/fnm.svg"alt="Blazing fast!">
<imgsrc="./docs/fnm.svg"alt="Blazing fast!">
@ -12,13 +12,13 @@
## Features
## Features
:earth_americas: Cross-platform support (macOS, Windows, Linux)
🌎 Cross-platform support (macOS, Windows, Linux)
:sparkles: Single file, easy installation, instant startup
✨ Single file, easy installation, instant startup
:rocket: Built with speed in mind
🚀 Built with speed in mind
:open_file_folder: Works with `.node-version` and `.nvmrc` files
📂 Works with `.node-version` and `.nvmrc` files
## Installation
## Installation
@ -42,7 +42,7 @@ On other operating systems, upgrading `fnm` is almost the same as installing it.
`--install-dir`
`--install-dir`
Set a custom directory for fnm to be installed. The default is `$HOME/.fnm`.
Set a custom directory for fnm to be installed. The default is `$XDG_DATA_HOME/fnm` (if `$XDG_DATA_HOME` is not defined it falls back to `$HOME/.local/share/fnm` on linux and `$HOME/Library/Application Support/fnm` on MacOS).
`--skip-shell`
`--skip-shell`
@ -68,6 +68,12 @@ brew install fnm
Then, [set up your shell for fnm](#shell-setup)
Then, [set up your shell for fnm](#shell-setup)
#### Using Winget (Windows)
```sh
winget install Schniz.fnm
```
#### Using Scoop (Windows)
#### Using Scoop (Windows)
```sh
```sh
@ -96,9 +102,10 @@ Then, [set up your shell for fnm](#shell-setup)
- Download the [latest release binary](https://github.com/Schniz/fnm/releases) for your system
- Download the [latest release binary](https://github.com/Schniz/fnm/releases) for your system
- Make it available globally on `PATH` environment variable
- Make it available globally on `PATH` environment variable
- Configure your shell profile:
- [Set up your shell for fnm](#shell-setup)
### Removing
### Removing
To remove fnm (😢), just delete the `.fnm` folder in your home directory. You should also edit your shell configuration to remove any references to fnm (ie. read [Shell Setup](#shell-setup), and do the opposite).
To remove fnm (😢), just delete the `.fnm` folder in your home directory. You should also edit your shell configuration to remove any references to fnm (ie. read [Shell Setup](#shell-setup), and do the opposite).
## Completions
## Completions
@ -114,7 +121,7 @@ Where `<SHELL>` can be one of the supported shells:
- `bash`
- `bash`
- `zsh`
- `zsh`
- `fish`
- `fish`
- `powershell`
- `power-shell`
Please follow your shell instructions to install them.
Please follow your shell instructions to install them.
@ -122,9 +129,13 @@ Please follow your shell instructions to install them.
Environment variables need to be setup before you can start using fnm.
Environment variables need to be setup before you can start using fnm.
This is done by evaluating the output of `fnm env`.
This is done by evaluating the output of `fnm env`.
To automatically run `fnm use` when a directory contains a `.node-version` or `.nvmrc` file, add the `--use-on-cd` option to your shell setup.
> [!NOTE]
> Check out the [Configuration](./docs/configuration.md) section to enable highly
> recommended features, like automatic version switching.
Adding a `.node-version` to your project is as simple as:
Adding a `.node-version` to your project is as simple as:
```bash
```bash
$ node --version
$ node --version
v14.18.3
v14.18.3
@ -165,17 +176,24 @@ Add the following to the end of your profile file:
- On Windows, the profile is located at `~\Documents\PowerShell\Microsoft.PowerShell_profile.ps1` or `$PROFILE`
- For macOS/Linux, the profile is located at `~/.config/powershell/Microsoft.PowerShell_profile.ps1`
- For macOS/Linux, the profile is located at `~/.config/powershell/Microsoft.PowerShell_profile.ps1`
- On Windows to edit your profile you can run this in a PowerShell
```powershell
notepad $profile
```
#### Windows Command Prompt aka Batch aka WinCMD
#### Windows Command Prompt aka Batch aka WinCMD
fnm is also supported but is not entirely covered. [You can set up a startup script](https://superuser.com/a/144348) and append the following line:
fnm is also supported but is not entirely covered. [You can set up a startup script](https://superuser.com/a/144348) and append the following lines:
```batch
```batch
FOR /f "tokens=*" %i IN ('fnm env --use-on-cd') DO CALL %i
@echo off
:: for /F will launch a new instance of cmd so we create a guard to prevent an infnite loop
if not defined FNM_AUTORUN_GUARD (
set "FNM_AUTORUN_GUARD=AutorunGuard"
FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
)
```
```
⚠️ If you get the error `i was unexpected at this time`, please make a .cmd file as suggested by the first step in the Usage with Cmder secton add it's path to the `AutoRun` registry key.
#### Usage with Cmder
#### Usage with Cmder
@ -183,18 +201,26 @@ Usage is very similar to the normal WinCMD install, apart for a few tweaks to al
Then you can do something like this:
Then you can do something like this:
- Make a .cmd file to invoke it
- Make a .cmd file to invoke it
```batch
```batch
:: %CMDER_ROOT%\bin\fnm_init.cmd
:: %CMDER_ROOT%\bin\fnm_init.cmd
@echo off
@echo off
FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
FOR /f "tokens=*" %%z IN ('fnm env --use-on-cd') DO CALL %%z
```
```
- Add it to the startup script
- Add it to the startup script
```batch
```batch
:: %CMDER_ROOT%\config\user_profile.cmd
:: %CMDER_ROOT%\config\user_profile.cmd
call "%CMDER_ROOT%\bin\fnm_init.cmd"
call "%CMDER_ROOT%\bin\fnm_init.cmd"
```
```
You can replace `%CMDER_ROOT%` with any other convenient path too.
You can replace `%CMDER_ROOT%` with any other convenient path too.
## [Configuration](./docs/configuration.md)
[See the available configuration options for an extended configuration documentation](./docs/configuration.md)
## [Usage](./docs/commands.md)
## [Usage](./docs/commands.md)
[See the available commands for an extended usage documentation](./docs/commands.md)
[See the available commands for an extended usage documentation](./docs/commands.md)
fnm comes with many features out of the box. Some of them are not activated by default as they’re changing your shell default behavior, and some are just a feature flag to avoid breaking changes or just experimental until we decide it is worthwhile to introduce them.
All these features can be configured by adding flags to the `fnm env` call when initializing the shell. For instance, if your shell set up looks like `eval "$(fnm env)"` then you can add a flag to it by changing it to `eval "$(fnm env --my-flag=value)"`
Here’s a list of these features and capabilities:
### `--use-on-cd`
**✅ Highly recommended**
`--use-on-cd` appends output to `fnm env`'s output that will hook into your shell upon changing directories, and will switch the Node.js version based on the requirements of the current directory, based on `.node-version` or `.nvmrc` (or `packages.json#engines#node` if `--resolve-engines` was enabled).
This allows you do avoid thinking about `fnm use`, and only `cd <DIR>` to make it work.
### `--version-file-strategy=recursive`
**✅ Highly recommended**
Makes `fnm use` and `fnm install` take parent directories into account when looking for a version file ("dotfile")--when no argument was given.
So, let's say we have the following directory structure:
```
repo/
├── package.json
├── .node-version <-withcontent:`20.0.0`
└── packages/
└── my-package/ <-Iamhere
└── package.json
```
And I'm running the following command:
```sh-session
repo/packages/my-package$ fnm use
```
Then fnm will switch to Node.js v20.0.0.
Without the explicit flag, the value is set to `local`, which will not traverse the directory tree and therefore will print:
```sh-session
repo/packages/my-package$ fnm use
error: Can't find version in dotfiles. Please provide a version manually to the command.
```
### `--enable-corepack`
**🧪 Experimental**
Runs [`corepack enable`](https://nodejs.org/api/corepack.html#enabling-the-feature) when a new version of Node.js is installed. Experimental due to the fact Corepack itself is experimental.
### `--resolve-engines`
**🧪 Experimental**
Treats `package.json#engines#node` as a valid Node.js version file ("dotfile"). So, if you have a package.json with the following content:
```json
{
"engines": {
"node": ">=20 <21"
}
}
```
Then:
- `fnm install` will install the latest satisfying Node.js 20.x version available in the Node.js dist server
- `fnm use` will use the latest satisfying Node.js 20.x version available on your system, or prompt to install if no version matched.