Skip to content

Commit

Permalink
fix: lib/helpers/install.ts to better support pnpm and properly res…
Browse files Browse the repository at this point in the history
…pect `root` argument (#64418)

This fixes and improves the `lib/helpers/install.ts` file (`install()`)
method to better support pnpm and properly respect the `root` argument.

I encountered an issue where by running `next <command> <project-dir>`,
and the `<command>` involved installing missing dependencies (like
`lint` or my upcoming `experimental-test`), it was not executing pnpm in
my `<project-dir>` because pnpm doesn't have a `--cwd` flag.



Closes NEXT-3092

Co-authored-by: Zack Tanner <1939140+ztanner@users.noreply.github.com>
  • Loading branch information
Ethan-Arrowood and ztanner authored Apr 15, 2024
1 parent 03b7a0f commit 64da71c
Showing 1 changed file with 36 additions and 66 deletions.
102 changes: 36 additions & 66 deletions packages/next/src/lib/helpers/install.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { yellow } from '../picocolors'
import spawn from 'next/dist/compiled/cross-spawn'

export type PackageManager = 'npm' | 'pnpm' | 'yarn'
import type { PackageManager } from './get-pkg-manager'

interface InstallArgs {
/**
* Indicate whether to install packages using npm, pnpm or Yarn.
* Indicate whether to install packages using npm, pnpm, or yarn.
*/
packageManager: PackageManager
/**
* Indicate whether there is an active Internet connection.
* Indicate whether there is an active internet connection.
*/
isOnline: boolean
/**
Expand All @@ -19,81 +18,52 @@ interface InstallArgs {
}

/**
* Spawn a package manager installation with either Yarn or NPM.
* Spawn a package manager installation with either npm, pnpm, or yarn.
*
* @returns A Promise that resolves once the installation is finished.
*/
export function install(
root: string,
dependencies: string[] | null,
dependencies: string[],
{ packageManager, isOnline, devDependencies }: InstallArgs
): Promise<void> {
/**
* (p)npm-specific command-line flags.
*/
const npmFlags: string[] = []
/**
* Yarn-specific command-line flags.
*/
const yarnFlags: string[] = []
/**
* Return a Promise that resolves once the installation is finished.
*/
return new Promise((resolve, reject) => {
let args: string[]
let command = packageManager
const useYarn = packageManager === 'yarn'
let args: string[] = []

if (dependencies && dependencies.length) {
/**
* If there are dependencies, run a variation of `{packageManager} add`.
*/
if (useYarn) {
/**
* Call `yarn add --exact (--offline)? (-D)? ...`.
*/
args = ['add', '--exact']
if (!isOnline) args.push('--offline')
args.push('--cwd', root)
if (devDependencies) args.push('--dev')
args.push(...dependencies)
} else {
/**
* Call `(p)npm install [--save|--save-dev] ...`.
*/
args = ['install', '--save-exact']
args.push(devDependencies ? '--save-dev' : '--save')
args.push(...dependencies)
}
if (dependencies.length > 0) {
if (packageManager === 'yarn') {
args = ['add', '--exact']
if (devDependencies) args.push('--dev')
} else if (packageManager === 'pnpm') {
args = ['add', '--save-exact']
args.push(devDependencies ? '--save-dev' : '--save-prod')
} else {
/**
* If there are no dependencies, run a variation of `{packageManager}
* install`.
*/
args = ['install']
if (!isOnline) {
console.log(yellow('You appear to be offline.'))
if (useYarn) {
console.log(yellow('Falling back to the local Yarn cache.'))
console.log()
args.push('--offline')
} else {
console.log()
}
}
// npm
args = ['install', '--save-exact']
args.push(devDependencies ? '--save-dev' : '--save')
}
/**
* Add any package manager-specific flags.
*/
if (useYarn) {
args.push(...yarnFlags)
} else {
args.push(...npmFlags)

args.push(...dependencies)
} else {
args = ['install'] // npm, pnpm, and yarn all support `install`

if (!isOnline) {
args.push('--offline')
console.log(yellow('You appear to be offline.'))
if (packageManager !== 'npm') {
console.log(
yellow(`Falling back to the local ${packageManager} cache.`)
)
}
console.log()
}
}

return new Promise((resolve, reject) => {
/**
* Spawn the installation process.
*/
const child = spawn(command, args, {
const child = spawn(packageManager, args, {
cwd: root,
stdio: 'inherit',
env: {
...process.env,
Expand All @@ -106,7 +76,7 @@ export function install(
})
child.on('close', (code) => {
if (code !== 0) {
reject({ command: `${command} ${args.join(' ')}` })
reject({ command: `${packageManager} ${args.join(' ')}` })
return
}
resolve()
Expand Down

1 comment on commit 64da71c

@ijjk
Copy link
Member

@ijjk ijjk commented on 64da71c Apr 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stats from current release

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary v14.2.1 vercel/next.js canary Change
buildDuration 14s 24.7s ⚠️ +10.7s
buildDurationCached 7.6s 6.9s N/A
nodeModulesSize 199 MB 199 MB ⚠️ +53.6 kB
nextStartRea..uration (ms) 402ms 407ms N/A
Client Bundles (main, webpack)
vercel/next.js canary v14.2.1 vercel/next.js canary Change
2453-HASH.js gzip 31.4 kB 31.4 kB N/A
3304.HASH.js gzip 181 B 181 B
3f784ff6-HASH.js gzip 53.7 kB 53.7 kB
8299-HASH.js gzip 5.1 kB 5.1 kB N/A
framework-HASH.js gzip 45.2 kB 45.2 kB
main-app-HASH.js gzip 242 B 243 B N/A
main-HASH.js gzip 32.2 kB 29.6 kB N/A
webpack-HASH.js gzip 1.68 kB 1.68 kB N/A
Overall change 99 kB 99 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary v14.2.1 vercel/next.js canary Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary v14.2.1 vercel/next.js canary Change
_app-HASH.js gzip 196 B 197 B N/A
_error-HASH.js gzip 184 B 184 B
amp-HASH.js gzip 505 B 505 B
css-HASH.js gzip 324 B 325 B N/A
dynamic-HASH.js gzip 2.5 kB 2.5 kB N/A
edge-ssr-HASH.js gzip 258 B 258 B
head-HASH.js gzip 352 B 352 B
hooks-HASH.js gzip 370 B 371 B N/A
image-HASH.js gzip 4.27 kB 4.27 kB
index-HASH.js gzip 259 B 259 B
link-HASH.js gzip 2.67 kB 2.67 kB N/A
routerDirect..HASH.js gzip 314 B 312 B N/A
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 309 B 309 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 6.63 kB 6.63 kB
Client Build Manifests
vercel/next.js canary v14.2.1 vercel/next.js canary Change
_buildManifest.js gzip 483 B 485 B N/A
Overall change 0 B 0 B
Rendered Page Sizes
vercel/next.js canary v14.2.1 vercel/next.js canary Change
index.html gzip 530 B 529 B N/A
link.html gzip 542 B 542 B
withRouter.html gzip 525 B 523 B N/A
Overall change 542 B 542 B
Edge SSR bundle Size
vercel/next.js canary v14.2.1 vercel/next.js canary Change
edge-ssr.js gzip 95.6 kB 95.6 kB N/A
page.js gzip 3.06 kB 3.05 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary v14.2.1 vercel/next.js canary Change
middleware-b..fest.js gzip 624 B 626 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 25.5 kB 25.5 kB N/A
edge-runtime..pack.js gzip 839 B 839 B
Overall change 839 B 839 B
Next Runtimes
vercel/next.js canary v14.2.1 vercel/next.js canary Change
app-page-exp...dev.js gzip 171 kB 171 kB N/A
app-page-exp..prod.js gzip 97.4 kB 97.5 kB N/A
app-page-tur..prod.js gzip 99.2 kB 99.2 kB N/A
app-page-tur..prod.js gzip 93.4 kB 93.5 kB N/A
app-page.run...dev.js gzip 144 kB 145 kB N/A
app-page.run..prod.js gzip 91.9 kB 92 kB N/A
app-route-ex...dev.js gzip 21.5 kB 21.5 kB N/A
app-route-ex..prod.js gzip 15.2 kB 15.2 kB N/A
app-route-tu..prod.js gzip 15.2 kB 15.2 kB N/A
app-route-tu..prod.js gzip 14.9 kB 14.9 kB N/A
app-route.ru...dev.js gzip 21.1 kB 21.1 kB N/A
app-route.ru..prod.js gzip 14.9 kB 14.9 kB N/A
pages-api-tu..prod.js gzip 9.55 kB 9.55 kB
pages-api.ru...dev.js gzip 9.82 kB 9.82 kB
pages-api.ru..prod.js gzip 9.55 kB 9.55 kB
pages-turbo...prod.js gzip 22.5 kB 22.5 kB N/A
pages.runtim...dev.js gzip 23.1 kB 23.1 kB N/A
pages.runtim..prod.js gzip 22.5 kB 22.5 kB N/A
server.runti..prod.js gzip 51.3 kB 51.4 kB N/A
Overall change 28.9 kB 28.9 kB
build cache Overall increase ⚠️
vercel/next.js canary v14.2.1 vercel/next.js canary Change
0.pack gzip 1.58 MB 1.58 MB ⚠️ +1.23 kB
index.pack gzip 106 kB 107 kB ⚠️ +551 B
Overall change 1.69 MB 1.69 MB ⚠️ +1.78 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for 2453-HASH.js

Diff too large to display

Diff for main-HASH.js

Diff too large to display

Diff for app-page-exp..ntime.dev.js

Diff too large to display

Diff for app-page-exp..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Diff for app-page.runtime.dev.js

Diff too large to display

Diff for app-page.runtime.prod.js

Diff too large to display

Diff for app-route-ex..ntime.dev.js

Diff too large to display

Diff for app-route-ex..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route-tu..time.prod.js

Diff too large to display

Diff for app-route.runtime.dev.js

Diff too large to display

Diff for app-route.ru..time.prod.js

Diff too large to display

Diff for pages-turbo...time.prod.js

Diff too large to display

Diff for pages.runtime.dev.js

Diff too large to display

Diff for pages.runtime.prod.js

Diff too large to display

Diff for server.runtime.prod.js

Diff too large to display

Please sign in to comment.