From 25a2d6e5ca3a982ce066764af272eedda1862932 Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 22 Aug 2021 20:16:19 +0300 Subject: [PATCH] feat(env): link npm and npx as well, when installing Node.js (#3696) --- .changeset/blue-cougars-visit.md | 5 +++++ packages/plugin-commands-env/src/env.ts | 15 +++++++++++-- packages/plugin-commands-env/src/node.ts | 7 +++++- packages/plugin-commands-env/test/env.test.ts | 22 +++++++++++++++---- packages/pnpm/src/main.ts | 2 +- 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 .changeset/blue-cougars-visit.md diff --git a/.changeset/blue-cougars-visit.md b/.changeset/blue-cougars-visit.md new file mode 100644 index 0000000000..94b42aff0c --- /dev/null +++ b/.changeset/blue-cougars-visit.md @@ -0,0 +1,5 @@ +--- +"@pnpm/plugin-commands-env": major +--- + +When installing Node.js, also link the npm CLI that is bundled with Node.js. diff --git a/packages/plugin-commands-env/src/env.ts b/packages/plugin-commands-env/src/env.ts index c31a4673a9..db6235312e 100644 --- a/packages/plugin-commands-env/src/env.ts +++ b/packages/plugin-commands-env/src/env.ts @@ -22,7 +22,7 @@ export const commandNames = ['env'] export function help () { return renderHelp({ - description: 'Install and use the specified version of Node.js', + description: 'Install and use the specified version of Node.js. The npm CLI bundled with the given Node.js version gets installed as well.', descriptionLists: [ { title: 'Options', @@ -63,9 +63,20 @@ export async function handler (opts: NvmNodeCommandOptions, params: string[]) { ...opts, useNodeVersion: nodeVersion, }) - const src = path.join(nodeDir, process.platform === 'win32' ? 'node.exe' : 'node') + const src = path.join(nodeDir, process.platform === 'win32' ? 'node.exe' : 'bin/node') const dest = path.join(opts.bin, 'node') await cmdShim(src, dest) + try { + let npmDir = nodeDir + if (process.platform !== 'win32') { + npmDir = path.join(npmDir, 'lib') + } + npmDir = path.join(npmDir, 'node_modules/npm/bin') + await cmdShim(path.join(npmDir, 'npm-cli.js'), path.join(opts.bin, 'npm')) + await cmdShim(path.join(npmDir, 'npx-cli.js'), path.join(opts.bin, 'npx')) + } catch (err) { + // ignore + } return `Node.js ${nodeVersion} is activated ${dest} -> ${src}` } diff --git a/packages/plugin-commands-env/src/node.ts b/packages/plugin-commands-env/src/node.ts index f2b176f23f..c3eea3e9f9 100644 --- a/packages/plugin-commands-env/src/node.ts +++ b/packages/plugin-commands-env/src/node.ts @@ -35,6 +35,11 @@ export type NvmNodeCommandOptions = Pick +export async function getNodeBinDir (opts: NvmNodeCommandOptions) { + const nodeDir = await getNodeDir(opts) + return process.platform === 'win32' ? nodeDir : path.join(nodeDir, 'bin') +} + export async function getNodeDir (opts: NvmNodeCommandOptions) { const nodesDir = path.join(opts.pnpmHomeDir, 'nodejs') let wantedNodeVersion = opts.useNodeVersion ?? (await readNodeVersionsManifest(nodesDir))?.default @@ -53,7 +58,7 @@ export async function getNodeDir (opts: NvmNodeCommandOptions) { if (!fs.existsSync(versionDir)) { await installNode(wantedNodeVersion, versionDir, opts) } - return process.platform === 'win32' ? versionDir : path.join(versionDir, 'bin') + return versionDir } async function installNode (wantedNodeVersion: string, versionDir: string, opts: NvmNodeCommandOptions) { diff --git a/packages/plugin-commands-env/test/env.test.ts b/packages/plugin-commands-env/test/env.test.ts index 6fcad7b0a8..6f484265d2 100644 --- a/packages/plugin-commands-env/test/env.test.ts +++ b/packages/plugin-commands-env/test/env.test.ts @@ -6,7 +6,7 @@ import { env } from '@pnpm/plugin-commands-env' import execa from 'execa' import PATH from 'path-name' -test('install Node by exact version', async () => { +test('install Node (and npm, npx) by exact version of Node.js', async () => { tempDir() await env.handler({ @@ -16,12 +16,26 @@ test('install Node by exact version', async () => { rawConfig: {}, }, ['use', '16.4.0']) - const { stdout } = execa.sync('node', ['-v'], { + const opts = { env: { [PATH]: `${process.cwd()}${path.delimiter}${process.env[PATH] as string}`, }, - }) - expect(stdout.toString()).toBe('v16.4.0') + } + + { + const { stdout } = execa.sync('node', ['-v'], opts) + expect(stdout.toString()).toBe('v16.4.0') + } + + { + const { stdout } = execa.sync('npm', ['-v'], opts) + expect(stdout.toString()).toBe('7.18.1') + } + + { + const { stdout } = execa.sync('npx', ['-v'], opts) + expect(stdout.toString()).toBe('7.18.1') + } const dirs = fs.readdirSync(path.resolve('nodejs')) expect(dirs).toEqual(['16.4.0']) diff --git a/packages/pnpm/src/main.ts b/packages/pnpm/src/main.ts index dc4095922b..08bd8790a7 100644 --- a/packages/pnpm/src/main.ts +++ b/packages/pnpm/src/main.ts @@ -233,7 +233,7 @@ export default async function run (inputArgv: string[]) { }) if (config.useNodeVersion != null) { - const nodePath = await node.getNodeDir(config) + const nodePath = await node.getNodeBinDir(config) config.extraBinPaths.push(nodePath) } let result = pnpmCmds[cmd ?? 'help'](