Skip to content

Conversation

juanpprieto
Copy link
Contributor

WHY are these changes introduced?

The installNodeModules function in cli-kit hardcoded the ['install'] command for all package managers, including yarn. This caused build failures when using Yarn Berry (v2/v3+) because:

  • Yarn v1 (Classic): Uses yarn install command
  • Yarn v2/v3+ (Berry): Uses yarn add command for dependencies

This incompatibility blocked the Hydrogen CLI upgrade command and other cli-kit consumers from working with modern yarn versions, forcing users to stay on legacy yarn v1 or face broken installations.

WHAT is this pull request doing?

Enhanced installNodeModules with yarn version-aware command selection:

New Function: getYarnInstallCommand(directory: string)

  • Multi-tier version detection strategy with intelligent fallbacks
  • Comprehensive error handling for system availability issues

Enhanced installNodeModules Function

  • Zero breaking changes - npm/pnpm/bun behavior unchanged
  • Yarn-specific logic - detects version and uses appropriate command
  • Maintains all existing interfaces and stream options

Detection Strategy (Priority Order)

  1. packageManager field in package.json (modern standard)
  2. yarn --version command execution and parsing
  3. .yarnrc.yml file presence (Berry project indicator)
  4. Fallback to install (maximum backward compatibility)

How to test your changes?

Post-release steps

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
  • Existing analytics will cater for this addition
  • PR includes analytics changes to measure impact

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

Copy link
Contributor

github-actions bot commented Jul 31, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
78.3% (+0.03% 🔼)
13182/16835
🟡 Branches
72.37% (+0.11% 🔼)
6447/8908
🟡 Functions
78.35% (+0% 🔼)
3410/4352
🟡 Lines
78.68% (+0.03% 🔼)
12479/15860
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / node-package-manager.ts
86.72% (-0.16% 🔻)
83.44% (-2.58% 🔻)
89.47% (+0.58% 🔼)
86.61% (-0.13% 🔻)

Test suite run success

3135 tests passing in 1328 suites.

Report generated by 🧪jest coverage report action from 11b6da3

@juanpprieto juanpprieto requested a review from Copilot August 1, 2025 01:19
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for Yarn Berry (v2+) to the installNodeModules function by implementing version-aware command selection. Previously, the function hardcoded the 'install' command for all package managers, causing build failures with modern Yarn versions that use the 'add' command.

  • Implements a new determineYarnInstallCommand function with multi-tier version detection strategy
  • Updates installNodeModules to use yarn-specific logic while maintaining backward compatibility
  • Adds comprehensive test coverage for all detection scenarios and fallback mechanisms

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
packages/cli-kit/src/public/node/node-package-manager.ts Adds yarn version detection logic and updates installNodeModules function
packages/cli-kit/src/public/node/node-package-manager.test.ts Comprehensive test suite for yarn version detection and install command selection
.changeset/gold-needles-kiss.md Changeset documenting the yarn berry compatibility addition
Comments suppressed due to low confidence (1)

packages/cli-kit/src/public/node/node-package-manager.ts:193

  • The function name 'determineYarnInstallCommand' is misleading - it returns both 'install' and 'add' commands, not just install commands. Consider renaming to 'getYarnCommand' or 'determineYarnCommand'.
export async function determineYarnInstallCommand(directory: string): Promise<string[]> {

Copy link
Contributor

github-actions bot commented Aug 1, 2025

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/node-package-manager.d.ts
@@ -87,6 +87,7 @@ interface InstallNPMDependenciesRecursivelyOptions {
  * @param options - Options to install dependencies recursively.
  */
 export declare function installNPMDependenciesRecursively(options: InstallNPMDependenciesRecursivelyOptions): Promise<void>;
+export declare function determineYarnInstallCommand(directory: string): Promise<string[]>;
 interface InstallNodeModulesOptions {
     directory: string;
     args?: string[];
@@ -219,6 +220,11 @@ export interface PackageJson {
      * https://docs.npmjs.com/cli/v9/configuring-npm/package-json#private
      */
     private?: boolean;
+    /**
+     * The packageManager attribute of the package.json.
+     * https://docs.npmjs.com/cli/v9/configuring-npm/package-json#packagemanager
+     */
+    packageManager?: string;
 }
 /**
  * Reads and parses a package.json

@juanpprieto juanpprieto requested a review from kdaviduik August 1, 2025 01:42
@juanpprieto juanpprieto marked this pull request as ready for review August 1, 2025 01:42
@juanpprieto juanpprieto requested review from a team as code owners August 1, 2025 01:42

let args: string[]
if (options.packageManager === 'yarn') {
args = await determineYarnInstallCommand(options.directory)
Copy link
Contributor

@kdaviduik kdaviduik Aug 7, 2025

Choose a reason for hiding this comment

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

I don't think this approach works, because it looks like it would break cases where installNodeModules is called with just flags but no dependencies to add (eg: yarn install --force). From my understanding:

  • both yarn v1 and yarn berry use yarn install to just install dependencies (ie: not add, just install)
  • To ADD dependencies:
    • yarn v1 supports yarn install <package> OR yarn add <package>
    • yarn berry ONLY supports yarn add <package>

So this seems like a much cleaner and simpler solution:

  let args: string[]
  // Are all of the args just flags (like `--force`)? Or are any of them actual packages to ADD?
  const hasPackageArgs = args?.some(arg => !arg.startsWith('-'))

  if (hasPackageArgs && options.packageManager === 'yarn') {
    args = ['add']
  } else {
    args = ['install']
  }

  if (options.args) {
    args = args.concat(options.args)
  }

Copy link
Contributor

github-actions bot commented Sep 7, 2025

This PR seems inactive. If it's still relevant, please add a comment saying so. Otherwise, take no action.
→ If there's no activity within a week, then a bot will automatically close this.
Thanks for helping to improve Shopify's dev tooling and experience.

@juanpprieto juanpprieto marked this pull request as draft September 12, 2025 14:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants