# `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