# `node` versioning w/ `npm`
## Goals & Action Items
- globally installed package binarys have some safe-guards/reasonable way to determine which one wins when there's duplicate names
- [x] help transfer `node` package/namespace on `npmjs.com` to the Node.js Project
- [x] ask Node.js Project to begin distributing releases on `npmjs.com` using dist-tags as mutable references for things like `LTS` versions
- benefit: support policies, version management & updates come out-of-the-box with the `npm` CLI or any other tool/package manager that interfaces with `npmjs.com` (not really different then using canonical git tags/releases on `github.com` or hosting distributions on `nodejs.org` - these can continue to exist)
- there should be no need for third-party tools (ie. `npm` comes with `node`, you should be able to use _that_ to update/upgrade your system `node` without the need for a third-party tool)
- [x] remove references to node version managers in `npm/cli`'s `README.md`
- [ ] add reference to upgrading/updating `node` using `npm` in `npm/cli` `README.md`
- [x] investigate `nvm` & missing features of `npm i node`
- https://github.com/nvm-sh/nvm#migrating-global-packages-while-installing `nvm install node --reinstall-packages-from=node`
- [x] investigate `volta` & whether it is doing something unkosher license-wise (re. similar to `corepack`)
- [x] make `npm i node -g -f && npm outdated -g` work (currentlty fails because of expected paths not existing)
## Example Use Cases & Usage
### Install & Manage `node` System-wide
```bash=
npm i node -g
npm i node@14 -g
npm i node@19 -g
```
> Note: this currently requires the `--force` flag to install `node` if you already have it installed to overwrite the `bin`
### Execute `node` in an individual process
```bash=
npx node@14 -e "console.log(process.version)"
```
### Check for outdated `node` version
```bash=
npm outdated -g
Package Current Wanted Latest Location Depended by
node 10.0.1 10.9.2 19.0.1 node_modules/node global
```
> Note: this currently fails after `npm i node -g` since there are paths we expect to exist, that don't, under `{prefix}/lib/node_modules`
### Updating `node` to a specific version
```bash=
npm update node@19 -g
```
### Project-specific
```bash=
npm i node
```
```json=
// package.json
{
"dependencies": {
"node": "*"
},
"engines": {
"node": ">=14"
}
}
```
### Set Project-specific `node` versions with `engines`
```bash=
npm pkg set engines.node="^14.17.0||^16.13.0||>=18.0.0"
```
### Enforce `node` specific versions
```bash=
# command specific
npm install --engines-strict
npm ci --engines-strict
# project-specific config
npm config set engines-strict=true --location=project
# user-specific config
npm config set engines-strict=true --location=user
# global config
npm config set engines-strict=true -g
```
### Add Net-new Config for Maintaining Packages across Version Updates
`node` & `npm` become unique package names where we are able to provide unique flags/context when doing an `install` or `update`.
```bash=
npm i node@14 -g -f -k
# -k | --keep-installed-packages
# maybe `--keep-installed-packages=node@12` to allow only copying/reinstalling deps from a previous spec of node
```
> Note: consider
> Note: switching `npm` or `node` bins may loose context of previously installed packages; adding this flag should resolve this use-case of retaining packages across these package versions at the system-level
> Note: two (or more?) types of node installations:
> - "main" node - the version that all your globally installed packages are linked
> - "test/project" nodes - the versions that are used on specific projects. when those are installed as set as the primary `node`, you should not lose access to your globally installed packages. those should be callable and will use the "main" node
### Net-new Global Manifest & Improved Linking
#### `npm link`
```bash=
# current:
cd ./pkg && npm link . && cd ../project && npm link <pkg>
# future: interfaces with the global `package.json`
npm link <get|set|list>
npm link set <name>=<path>
npm link set lodash=.
npm link <path> # is equivalent to...
npm link <pkg>=<path>
npm link ls # returns all project deps that are symlinked
npm link ls -g # returns all globally available links
npm link get <pkg> # returns path to project linked package
npm link get <pkg> -g # returns path to globally linked package
```
#### Global `package.json`
```json=
// {global prefix}package.json
{
"linkedDependencies": {
"node": ["json", "diff-so-fancy"],
},
"dependencies": {
"json": "*",
"diff-so-fancy": "^3.0.0",
"node-19": "npm:node@19",
"node-18": "npm:node@18",
"node-12": "npm:node@12",
"node-current": "npm:node@current",
"node": "node@lts"
},
"node": "12"
}
```
```
npm update|install node -g
# will update and save `json` and `diff-so-fancy` (if necessary?) and update global/package.json
# due to them being listed in linkedDependencies#node
```
**Questions**
- how does the name of a bin on disk get inferred when multiple packages have the name and bin?
- eg, `node`
**Global + Project Example**
```json=
// root/package.json
{
"dependencies": {
"json": "1"
}
}
```
```json=
// root/project/package.json
{
"dependencies": {
"json": "2"
},
"scripts": {
"run-json": "json"
}
}
```
```sh=
cd /root
json --version # 1.0.0
cd /root/project
npm run run-json -- --version # 2.0.0
json --version # 1.0.0
npx json --version # 2.0.0
cd /root
npx json --version # 1.0.0
```
### Net-new Command to manage `PATH`
```bash=
npm path <get|set|list>
```
> Note: this is a global operation by default (aka. `--global=true`)
## Questions
- how to manage multiple installed versions and have one aliases to `node`?
- `--install-strategy=linked -g` could create a global store where multiple versions of `node` can co-exist (_hypothetically_)
- how to ensure compatability between other globally installed npm packages and npm installed version of node?
## Links & References
- Add `node` version checker to core: https://github.com/nodejs/node/issues/44942
- `node` package: https://www.npmjs.com/package/node