Skip to content

Commit 5219afe

Browse files
ihabadhamclaude
andcommitted
Fix duplicate dependency installation in install generator
Root cause: JavaScript dependency methods in BaseGenerator were public, causing automatic execution when generators were invoked. This led to dependencies being installed twice when using --redux option. Changes: - Move dependency installation methods to private in BaseGenerator - Add explicit dependency management in InstallGenerator - Make Redux generator's success message method public - Ensure success messages appear correctly for all installation types Fixes duplicate installations while maintaining all existing functionality. All 51 generator tests pass. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent aa76bc8 commit 5219afe

File tree

3 files changed

+174
-54
lines changed

3 files changed

+174
-54
lines changed

lib/generators/react_on_rails/base_generator.rb

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -95,45 +95,6 @@ def add_base_gems_to_gemfile
9595
run "bundle"
9696
end
9797

98-
def add_js_dependencies
99-
add_react_on_rails_package
100-
add_react_dependencies
101-
add_css_dependencies
102-
add_dev_dependencies
103-
install_js_dependencies
104-
end
105-
106-
private
107-
108-
def install_js_dependencies
109-
# Detect which package manager to use
110-
success = if File.exist?(File.join(destination_root, "yarn.lock"))
111-
system("yarn", "install")
112-
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
113-
system("pnpm", "install")
114-
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
115-
File.exist?(File.join(destination_root, "package.json"))
116-
# Use npm for package-lock.json or as default fallback
117-
system("npm", "install")
118-
else
119-
true # No package manager detected, skip
120-
end
121-
122-
unless success
123-
GeneratorMessages.add_warning(<<~MSG.strip)
124-
⚠️ JavaScript dependencies installation failed.
125-
126-
This could be due to network issues or missing package manager.
127-
You can install dependencies manually later by running:
128-
• npm install (if using npm)
129-
• yarn install (if using yarn)
130-
• pnpm install (if using pnpm)
131-
MSG
132-
end
133-
134-
success
135-
end
136-
13798
def update_gitignore_for_auto_registration
13899
gitignore_path = File.join(destination_root, ".gitignore")
139100
return unless File.exist?(gitignore_path)
@@ -160,6 +121,28 @@ def append_to_spec_rails_helper
160121
end
161122
end
162123

124+
CONFIGURE_RSPEC_TO_COMPILE_ASSETS = <<-STR.strip_heredoc
125+
RSpec.configure do |config|
126+
# Ensure that if we are running js tests, we are using latest webpack assets
127+
# This will use the defaults of :js and :server_rendering meta tags
128+
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
129+
end
130+
STR
131+
132+
private
133+
134+
def setup_js_dependencies
135+
add_js_dependencies
136+
install_js_dependencies
137+
end
138+
139+
def add_js_dependencies
140+
add_react_on_rails_package
141+
add_react_dependencies
142+
add_css_dependencies
143+
add_dev_dependencies
144+
end
145+
163146
def add_react_on_rails_package
164147
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
165148

@@ -222,15 +205,34 @@ def add_dev_dependencies
222205
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
223206
end
224207

225-
CONFIGURE_RSPEC_TO_COMPILE_ASSETS = <<-STR.strip_heredoc
226-
RSpec.configure do |config|
227-
# Ensure that if we are running js tests, we are using latest webpack assets
228-
# This will use the defaults of :js and :server_rendering meta tags
229-
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
208+
def install_js_dependencies
209+
# Detect which package manager to use
210+
success = if File.exist?(File.join(destination_root, "yarn.lock"))
211+
system("yarn", "install")
212+
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
213+
system("pnpm", "install")
214+
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
215+
File.exist?(File.join(destination_root, "package.json"))
216+
# Use npm for package-lock.json or as default fallback
217+
system("npm", "install")
218+
else
219+
true # No package manager detected, skip
220+
end
221+
222+
unless success
223+
GeneratorMessages.add_warning(<<~MSG.strip)
224+
⚠️ JavaScript dependencies installation failed.
225+
226+
This could be due to network issues or missing package manager.
227+
You can install dependencies manually later by running:
228+
• npm install (if using npm)
229+
• yarn install (if using yarn)
230+
• pnpm install (if using pnpm)
231+
MSG
230232
end
231-
STR
232233

233-
private
234+
success
235+
end
234236

235237
def handle_npm_failure(dependency_type, packages, dev: false)
236238
install_command = dev ? "npm install --save-dev" : "npm install"

lib/generators/react_on_rails/install_generator.rb

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ def invoke_generators
7979
else
8080
invoke "react_on_rails:react_no_redux", [], { typescript: options.typescript? }
8181
end
82+
setup_react_dependencies
83+
end
84+
85+
def setup_react_dependencies
86+
add_js_dependencies
87+
install_js_dependencies
8288
end
8389

8490
# NOTE: other requirements for existing files such as .gitignore or application.
@@ -412,6 +418,118 @@ def create_typescript_config
412418
puts Rainbow("✅ Created tsconfig.json").green
413419
end
414420

421+
def add_js_dependencies
422+
add_react_on_rails_package
423+
add_react_dependencies
424+
add_css_dependencies
425+
add_dev_dependencies
426+
end
427+
428+
def add_react_on_rails_package
429+
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
430+
431+
# Try to use package_json gem first, fall back to direct npm commands
432+
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
433+
["react-on-rails@#{ReactOnRails::VERSION}"]
434+
else
435+
puts "Adding the latest react-on-rails NPM module. " \
436+
"Double check this is correct in package.json"
437+
["react-on-rails"]
438+
end
439+
440+
puts "Installing React on Rails package..."
441+
return if add_npm_dependencies(react_on_rails_pkg)
442+
443+
puts "Using direct npm commands as fallback"
444+
success = system("npm", "install", *react_on_rails_pkg)
445+
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
446+
end
447+
448+
def add_react_dependencies
449+
puts "Installing React dependencies..."
450+
react_deps = %w[
451+
react
452+
react-dom
453+
@babel/preset-react
454+
prop-types
455+
babel-plugin-transform-react-remove-prop-types
456+
babel-plugin-macros
457+
]
458+
return if add_npm_dependencies(react_deps)
459+
460+
success = system("npm", "install", *react_deps)
461+
handle_npm_failure("React dependencies", react_deps) unless success
462+
end
463+
464+
def add_css_dependencies
465+
puts "Installing CSS handling dependencies..."
466+
css_deps = %w[
467+
css-loader
468+
css-minimizer-webpack-plugin
469+
mini-css-extract-plugin
470+
style-loader
471+
]
472+
return if add_npm_dependencies(css_deps)
473+
474+
success = system("npm", "install", *css_deps)
475+
handle_npm_failure("CSS dependencies", css_deps) unless success
476+
end
477+
478+
def add_dev_dependencies
479+
puts "Installing development dependencies..."
480+
dev_deps = %w[
481+
@pmmmwh/react-refresh-webpack-plugin
482+
react-refresh
483+
]
484+
return if add_npm_dependencies(dev_deps, dev: true)
485+
486+
success = system("npm", "install", "--save-dev", *dev_deps)
487+
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
488+
end
489+
490+
def install_js_dependencies
491+
# Detect which package manager to use
492+
success = if File.exist?(File.join(destination_root, "yarn.lock"))
493+
system("yarn", "install")
494+
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
495+
system("pnpm", "install")
496+
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
497+
File.exist?(File.join(destination_root, "package.json"))
498+
# Use npm for package-lock.json or as default fallback
499+
system("npm", "install")
500+
else
501+
true # No package manager detected, skip
502+
end
503+
504+
unless success
505+
GeneratorMessages.add_warning(<<~MSG.strip)
506+
⚠️ JavaScript dependencies installation failed.
507+
508+
This could be due to network issues or missing package manager.
509+
You can install dependencies manually later by running:
510+
• npm install (if using npm)
511+
• yarn install (if using yarn)
512+
• pnpm install (if using pnpm)
513+
MSG
514+
end
515+
516+
success
517+
end
518+
519+
def handle_npm_failure(dependency_type, packages, dev: false)
520+
install_command = dev ? "npm install --save-dev" : "npm install"
521+
GeneratorMessages.add_warning(<<~MSG.strip)
522+
⚠️ Failed to install #{dependency_type}.
523+
524+
The following packages could not be installed automatically:
525+
#{packages.map { |pkg| " • #{pkg}" }.join("\n")}
526+
527+
This could be due to network issues or missing package manager.
528+
You can install them manually later by running:
529+
#{install_command} #{packages.join(' ')}
530+
MSG
531+
end
532+
415533
# Removed: Shakapacker auto-installation logic (now explicit dependency)
416534

417535
# Removed: Shakapacker 8+ is now required as explicit dependency

lib/generators/react_on_rails/react_with_redux_generator.rb

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,14 @@ def add_redux_npm_dependencies
8989
install_packages_with_fallback(regular_packages, dev: false, package_manager: package_manager)
9090
end
9191

92+
def add_redux_specific_messages
93+
# Override the generic messages with Redux-specific instructions
94+
GeneratorMessages.output.clear
95+
GeneratorMessages.add_info(
96+
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world")
97+
)
98+
end
99+
92100
private
93101

94102
def install_packages_with_fallback(packages, dev:, package_manager:)
@@ -132,14 +140,6 @@ def dev_flag_for(package_manager)
132140
when "yarn", "bun" then "--dev"
133141
end
134142
end
135-
136-
def add_redux_specific_messages
137-
# Override the generic messages with Redux-specific instructions
138-
GeneratorMessages.output.clear
139-
GeneratorMessages.add_info(
140-
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world")
141-
)
142-
end
143143
end
144144
end
145145
end

0 commit comments

Comments
 (0)