Skip to content

Commit 6c6e1eb

Browse files
justin808claude
andcommitted
Add comprehensive test coverage and type signatures for JsDependencyManager
- Add RBS type signatures for JsDependencyManager module - Add comprehensive test suite covering all dependency installation scenarios - Improve error handling with better edge case coverage - Update tests to verify Rspack and TypeScript dependency flows - Document breaking changes in CHANGELOG for Babel dependency removal 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a7bada9 commit 6c6e1eb

File tree

5 files changed

+593
-66
lines changed

5 files changed

+593
-66
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ Changes since the last non-beta release.
5757

5858
- **Generator Configuration Modernization**: Updated the generator to enable recommended configurations by default for new applications. `config.build_test_command` is now uncommented and set to `"RAILS_ENV=test bin/shakapacker"` by default, enabling automatic asset building during tests for better integration test reliability. `config.auto_load_bundle = true` is now set by default, enabling automatic loading of component bundles. `config.components_subdirectory = "ror_components"` is now set by default, organizing React components in a dedicated subdirectory. **Note:** These changes only affect newly generated applications. Existing applications are unaffected and do not need to make any changes. If you want to adopt these settings in an existing app, you can manually add them to your `config/initializers/react_on_rails.rb` file. [PR 2039](https://github.com/shakacode/react_on_rails/pull/2039) by [justin808](https://github.com/justin808).
5959

60+
- **Removed Babel Dependency Installation**: The generator no longer installs `@babel/preset-react` or `@babel/preset-typescript` packages. Shakapacker handles JavaScript transpiler configuration (Babel, SWC, or esbuild) via the `javascript_transpiler` setting in `shakapacker.yml`. SWC is now the default transpiler and includes built-in support for React and TypeScript. Users who explicitly choose Babel will need to manually install and configure the required presets. This change reduces unnecessary dependencies and aligns with Shakapacker's modular transpiler approach. [PR <PLACEHOLDER>](https://github.com/shakacode/react_on_rails/pull/<PLACEHOLDER>) by [justin808](https://github.com/justin808).
61+
6062
#### Documentation
6163

6264
- **Simplified Configuration Files**: Improved configuration documentation and generator template for better clarity and usability. Reduced generator template from 67 to 42 lines (37% reduction). Added comprehensive testing configuration guide. Reorganized configuration docs into Essential vs Advanced sections. Enhanced Doctor program with diagnostics for server rendering and test compilation consistency. [PR #2011](https://github.com/shakacode/react_on_rails/pull/2011) by [justin808](https://github.com/justin808).

lib/generators/react_on_rails/js_dependency_manager.rb

Lines changed: 115 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
require_relative "generator_messages"
44

5+
# rubocop:disable Metrics/ModuleLength
56
module ReactOnRails
67
module Generators
78
# Shared module for managing JavaScript dependencies across generators
@@ -11,11 +12,6 @@ module Generators
1112
# Since react_on_rails requires shakapacker, and shakapacker includes
1213
# package_json as a dependency, the package_json gem is always available.
1314
#
14-
# == Instance Variables
15-
# The module initializes and manages these instance variables:
16-
# - @added_dependencies_to_package_json: Boolean tracking if package_json gem was used
17-
# (initialized by setup_js_dependencies using `unless defined?` pattern)
18-
#
1915
# == Required Methods
2016
# Including classes must include GeneratorHelper module which provides:
2117
# - add_npm_dependencies(packages, dev: false): Add packages via package_json gem
@@ -29,10 +25,19 @@ module Generators
2925
#
3026
# == Installation Behavior
3127
# The module ALWAYS runs package manager install after adding dependencies.
32-
# This is safe because package_json gem's install is idempotent - it only
28+
# This is safe because package_json gem's install method is idempotent - it only
3329
# installs what's actually needed from package.json. This prevents edge cases
3430
# where package.json was modified but dependencies weren't installed.
3531
#
32+
# == Error Handling
33+
# All dependency addition methods use a tolerant error handling approach:
34+
# - Return false on failure instead of raising exceptions
35+
# - Catch StandardError and add warnings to GeneratorMessages
36+
# - Provide clear manual installation instructions in warnings
37+
# This provides better UX - the generator completes successfully even if
38+
# dependency installation fails (e.g., network issues), and users can
39+
# manually install dependencies afterward.
40+
#
3641
# == Usage
3742
# Include this module in generator classes and call setup_js_dependencies
3843
# to handle all JS dependency installation via package_json gem.
@@ -91,9 +96,6 @@ module JsDependencyManager
9196
private
9297

9398
def setup_js_dependencies
94-
# Initialize instance variable if not already defined by including class
95-
# This ensures safe operation when the module is first included
96-
@added_dependencies_to_package_json = false unless defined?(@added_dependencies_to_package_json)
9799
add_js_dependencies
98100

99101
# Always run install to ensure all dependencies are properly installed.
@@ -109,7 +111,7 @@ def add_js_dependencies
109111
add_react_dependencies
110112
add_css_dependencies
111113
# Rspack dependencies are only added when --rspack flag is used
112-
add_rspack_dependencies if respond_to?(:options) && options.rspack?
114+
add_rspack_dependencies if respond_to?(:options) && options&.rspack?
113115
# Dev dependencies vary based on bundler choice
114116
add_dev_dependencies
115117
end
@@ -128,92 +130,148 @@ def add_react_on_rails_package
128130
end
129131

130132
puts "Installing React on Rails package..."
131-
if add_js_dependency(react_on_rails_pkg)
132-
@added_dependencies_to_package_json = true
133-
else
134-
# This should not happen since package_json is always available via shakapacker
135-
raise "Failed to add react-on-rails package via package_json gem. " \
136-
"This indicates shakapacker dependency may not be properly installed."
137-
end
133+
return if add_package(react_on_rails_pkg)
134+
135+
# This should not happen since package_json is always available via shakapacker
136+
GeneratorMessages.add_warning(<<~MSG.strip)
137+
⚠️ Failed to add react-on-rails package via package_json gem.
138+
139+
This indicates shakapacker dependency may not be properly installed.
140+
You can install it manually by running:
141+
npm install #{react_on_rails_pkg}
142+
MSG
143+
rescue StandardError => e
144+
GeneratorMessages.add_warning(<<~MSG.strip)
145+
⚠️ Error adding react-on-rails package: #{e.message}
146+
147+
You can install it manually by running:
148+
npm install #{react_on_rails_pkg}
149+
MSG
138150
end
139151

140152
def add_react_dependencies
141153
puts "Installing React dependencies..."
154+
return if add_packages(REACT_DEPENDENCIES)
142155

143-
if add_js_dependencies_batch(REACT_DEPENDENCIES)
144-
@added_dependencies_to_package_json = true
145-
else
146-
# This should not happen since package_json is always available via shakapacker
147-
raise "Failed to add React dependencies (#{REACT_DEPENDENCIES.join(', ')}) via package_json gem. " \
148-
"This indicates shakapacker dependency may not be properly installed."
149-
end
156+
# This should not happen since package_json is always available via shakapacker
157+
GeneratorMessages.add_warning(<<~MSG.strip)
158+
⚠️ Failed to add React dependencies via package_json gem.
159+
160+
This indicates shakapacker dependency may not be properly installed.
161+
You can install them manually by running:
162+
npm install #{REACT_DEPENDENCIES.join(' ')}
163+
MSG
164+
rescue StandardError => e
165+
GeneratorMessages.add_warning(<<~MSG.strip)
166+
⚠️ Error adding React dependencies: #{e.message}
167+
168+
You can install them manually by running:
169+
npm install #{REACT_DEPENDENCIES.join(' ')}
170+
MSG
150171
end
151172

152173
def add_css_dependencies
153174
puts "Installing CSS handling dependencies..."
175+
return if add_packages(CSS_DEPENDENCIES)
154176

155-
if add_js_dependencies_batch(CSS_DEPENDENCIES)
156-
@added_dependencies_to_package_json = true
157-
else
158-
# This should not happen since package_json is always available via shakapacker
159-
raise "Failed to add CSS dependencies (#{CSS_DEPENDENCIES.join(', ')}) via package_json gem. " \
160-
"This indicates shakapacker dependency may not be properly installed."
161-
end
177+
# This should not happen since package_json is always available via shakapacker
178+
GeneratorMessages.add_warning(<<~MSG.strip)
179+
⚠️ Failed to add CSS dependencies via package_json gem.
180+
181+
This indicates shakapacker dependency may not be properly installed.
182+
You can install them manually by running:
183+
npm install #{CSS_DEPENDENCIES.join(' ')}
184+
MSG
185+
rescue StandardError => e
186+
GeneratorMessages.add_warning(<<~MSG.strip)
187+
⚠️ Error adding CSS dependencies: #{e.message}
188+
189+
You can install them manually by running:
190+
npm install #{CSS_DEPENDENCIES.join(' ')}
191+
MSG
162192
end
163193

164194
def add_rspack_dependencies
165195
puts "Installing Rspack core dependencies..."
196+
return if add_packages(RSPACK_DEPENDENCIES)
166197

167-
if add_js_dependencies_batch(RSPACK_DEPENDENCIES)
168-
@added_dependencies_to_package_json = true
169-
else
170-
# This should not happen since package_json is always available via shakapacker
171-
raise "Failed to add Rspack dependencies (#{RSPACK_DEPENDENCIES.join(', ')}) via package_json gem. " \
172-
"This indicates shakapacker dependency may not be properly installed."
173-
end
198+
# This should not happen since package_json is always available via shakapacker
199+
GeneratorMessages.add_warning(<<~MSG.strip)
200+
⚠️ Failed to add Rspack dependencies via package_json gem.
201+
202+
This indicates shakapacker dependency may not be properly installed.
203+
You can install them manually by running:
204+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
205+
MSG
206+
rescue StandardError => e
207+
GeneratorMessages.add_warning(<<~MSG.strip)
208+
⚠️ Error adding Rspack dependencies: #{e.message}
209+
210+
You can install them manually by running:
211+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
212+
MSG
174213
end
175214

176215
def add_typescript_dependencies
177216
puts "Installing TypeScript dependencies..."
217+
return if add_packages(TYPESCRIPT_DEPENDENCIES, dev: true)
178218

179-
if add_js_dependencies_batch(TYPESCRIPT_DEPENDENCIES, dev: true)
180-
@added_dependencies_to_package_json = true
181-
else
182-
# This should not happen since package_json is always available via shakapacker
183-
raise "Failed to add TypeScript dependencies (#{TYPESCRIPT_DEPENDENCIES.join(', ')}) via package_json gem. " \
184-
"This indicates shakapacker dependency may not be properly installed."
185-
end
219+
# This should not happen since package_json is always available via shakapacker
220+
GeneratorMessages.add_warning(<<~MSG.strip)
221+
⚠️ Failed to add TypeScript dependencies via package_json gem.
222+
223+
This indicates shakapacker dependency may not be properly installed.
224+
You can install them manually by running:
225+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
226+
MSG
227+
rescue StandardError => e
228+
GeneratorMessages.add_warning(<<~MSG.strip)
229+
⚠️ Error adding TypeScript dependencies: #{e.message}
230+
231+
You can install them manually by running:
232+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
233+
MSG
186234
end
187235

188236
def add_dev_dependencies
189237
puts "Installing development dependencies..."
190238

191239
# Use Rspack-specific dev dependencies if --rspack flag is set
192-
dev_deps = if respond_to?(:options) && options.rspack?
240+
dev_deps = if respond_to?(:options) && options&.rspack?
193241
RSPACK_DEV_DEPENDENCIES
194242
else
195243
DEV_DEPENDENCIES
196244
end
197245

198-
if add_js_dependencies_batch(dev_deps, dev: true)
199-
@added_dependencies_to_package_json = true
200-
else
201-
# This should not happen since package_json is always available via shakapacker
202-
raise "Failed to add development dependencies (#{dev_deps.join(', ')}) via package_json gem. " \
203-
"This indicates shakapacker dependency may not be properly installed."
204-
end
246+
return if add_packages(dev_deps, dev: true)
247+
248+
# This should not happen since package_json is always available via shakapacker
249+
GeneratorMessages.add_warning(<<~MSG.strip)
250+
⚠️ Failed to add development dependencies via package_json gem.
251+
252+
This indicates shakapacker dependency may not be properly installed.
253+
You can install them manually by running:
254+
npm install --save-dev #{dev_deps.join(' ')}
255+
MSG
256+
rescue StandardError => e
257+
GeneratorMessages.add_warning(<<~MSG.strip)
258+
⚠️ Error adding development dependencies: #{e.message}
259+
260+
You can install them manually by running:
261+
npm install --save-dev #{dev_deps.join(' ')}
262+
MSG
205263
end
206264

207265
# Add a single dependency using package_json gem
208266
#
209267
# This method is used internally for adding the react-on-rails package
210268
# with version-specific handling (react-on-rails@VERSION).
211-
# For batch operations, use add_js_dependencies_batch instead.
269+
# For batch operations, use add_packages instead.
212270
#
213271
# @param package [String] Package specifier (e.g., "react-on-rails@16.0.0")
214272
# @param dev [Boolean] Whether to add as dev dependency
215273
# @return [Boolean] true if successful, false otherwise
216-
def add_js_dependency(package, dev: false)
274+
def add_package(package, dev: false)
217275
pj = package_json
218276
return false unless pj
219277

@@ -240,7 +298,7 @@ def add_js_dependency(package, dev: false)
240298
# @param packages [Array<String>] Package names to add
241299
# @param dev [Boolean] Whether to add as dev dependencies
242300
# @return [Boolean] true if successful, false otherwise
243-
def add_js_dependencies_batch(packages, dev: false)
301+
def add_packages(packages, dev: false)
244302
# Use the add_npm_dependencies helper from GeneratorHelper
245303
add_npm_dependencies(packages, dev: dev)
246304
end
@@ -270,3 +328,4 @@ def install_js_dependencies
270328
end
271329
end
272330
end
331+
# rubocop:enable Metrics/ModuleLength

0 commit comments

Comments
 (0)