Skip to content

Avoid duplicate Pro and RSC dependency installation #4618

Description

@ihabadham

Why

react_on_rails:install --rsc processes both the Pro and RSC npm dependency groups twice.

The repeated package-manager operations are normally idempotent and complete successfully, but they add avoidable install time and output noise. The RSC pass also queues the temporary package-pin explanation twice, so the final message is duplicated.

Reproduction

cd /tmp
rm -rf ror-duplicate-generator-deps
npx --yes create-react-on-rails-app@17.0.0-rc.9 ror-duplicate-generator-deps --rsc --package-manager npm --no-agent-files | tee create-app.log
grep -n "Installing React on Rails Pro dependencies" create-app.log
grep -n "Installing React Server Components dependencies" create-app.log
grep -n "React Server Components package pin:" create-app.log

Each grep returns two matches.

The same behavior occurs through the direct Ruby generator:

REACT_ON_RAILS_PACKAGE_MANAGER=npm bin/rails generate react_on_rails:install --rsc --no-agent-files

Exact call stack

Parent dependency pass

InstallGenerator#invoke_generators
→ setup_react_dependencies
→ JsDependencyManager#setup_js_dependencies
→ add_js_dependencies
→ add_pro_dependencies       # use_pro? is true
→ add_rsc_dependencies       # use_rsc? is true

Invoked standalone-generator passes

InstallGenerator#invoke_generators
→ invoke react_on_rails:pro, invoked_by_install: true
→ ProGenerator#run_generator
→ add_pro_npm_dependencies
→ add_pro_dependencies
InstallGenerator#invoke_generators
→ invoke react_on_rails:rsc, invoked_by_install: true
→ RscGenerator#run_generator
→ add_rsc_npm_dependencies
→ add_rsc_dependencies

History and intent

PR #2284 introduced the full-install flags, standalone upgrade generators, central Pro/RSC dependency additions, and the parent-to-child invocations together.

Each dependency path has an independent purpose:

  • the install generator centrally builds the selected full dependency stack;
  • standalone Pro/RSC generators must add their packages when upgrading existing applications.

The duplication happens only when those paths are composed. invoked_by_install already suppresses child prerequisite checks, standalone messages, and some migration behavior, but does not suppress the child dependency step. PR #2284 describes reruns as idempotent; it does not describe double package-manager work as intended, and no test asserts two dependency additions.

Expected behavior

  • Full install --rsc adds the Pro dependency group once and the RSC dependency group once.
  • Standalone react_on_rails:pro still adds Pro dependencies once.
  • Standalone react_on_rails:rsc still adds RSC dependencies once.
  • The RSC pin explanation prints once.

Suggested boundary

During parent-driven installation, keep the central dependency pass as owner and skip the standalone dependency methods when invoked_by_install is true:

add_pro_npm_dependencies unless options[:invoked_by_install]
add_rsc_npm_dependencies unless options[:invoked_by_install]

Equivalent ownership is acceptable if it preserves standalone-generator behavior and performs each dependency operation exactly once.

Acceptance criteria

  • Generator coverage asserts one Pro and one RSC dependency addition for install --rsc.
  • Standalone Pro and RSC generator coverage continues to assert one dependency addition each.
  • Published-style create-app output contains one Pro install heading, one RSC install heading, and one RSC pin explanation.

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions