Skip to content
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
281e753
refactor: Extract JS dependency management into shared module
github-actions[bot] Sep 24, 2025
3896f80
fix: Address code review issues and optimize package_json gem usage
github-actions[bot] Sep 24, 2025
3c7c49e
fix: Fix failing generator tests in message_deduplication_spec
github-actions[bot] Sep 24, 2025
f6931de
fix: Fix failing generator tests in PR #1812
ihabadham Sep 24, 2025
8fdff7f
fix: Fix RuboCop violations and remove accidental dependency
ihabadham Sep 24, 2025
24d8b2c
refactor: Extract dependency arrays as frozen constants and add modul…
ihabadham Sep 24, 2025
6324ff1
perf: Optimize add_react_on_rails_package to eliminate redundant arra…
ihabadham Sep 24, 2025
3f3841b
fix: Always run final install to prevent edge cases
ihabadham Sep 24, 2025
861caa1
refactor: Simplify JS dependency manager by removing redundant packag…
github-actions[bot] Sep 24, 2025
83765cb
fix: Address code review issues in JS dependency manager
justin808 Nov 16, 2025
f14c980
fix: Add Rspack and TypeScript support to shared JS dependency manager
justin808 Nov 17, 2025
62d06f0
fix: Use SWC as default and remove Babel dependencies managed by Shak…
justin808 Nov 17, 2025
29f2b61
fix: Address code review issues in JS dependency manager
justin808 Nov 17, 2025
ce98bed
Replace scss-lint with stylelint (#1825)
ihabadham Nov 17, 2025
4e1dd18
Fix spec/dummy bin/dev to use correct route (#2029)
justin808 Nov 17, 2025
a1e80bb
Bump version to 16.2.0.beta.5
justin808 Nov 17, 2025
a642b66
fix: Update shakapacker config to use javascript_transpiler instead o…
justin808 Nov 17, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 3 additions & 118 deletions lib/generators/react_on_rails/base_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
require "fileutils"
require_relative "generator_messages"
require_relative "generator_helper"
require_relative "js_dependency_manager"
module ReactOnRails
module Generators
class BaseGenerator < Rails::Generators::Base
include GeneratorHelper
include JsDependencyManager

Rails::Generators.hide_namespace(namespace)
source_root(File.expand_path("templates", __dir__))
Expand Down Expand Up @@ -107,7 +109,7 @@ def add_base_gems_to_gemfile
run "bundle"
end

def update_gitignore_for_generated_bundles
def update_gitignore_for_auto_registration
gitignore_path = File.join(destination_root, ".gitignore")
return unless File.exist?(gitignore_path)

Expand Down Expand Up @@ -146,123 +148,6 @@ def append_to_spec_rails_helper

private

def setup_js_dependencies
add_js_dependencies
install_js_dependencies
end

def add_js_dependencies
add_react_on_rails_package
add_react_dependencies
add_css_dependencies
add_dev_dependencies
end

def add_react_on_rails_package
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/

# Try to use package_json gem first, fall back to direct npm commands
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
["react-on-rails@#{ReactOnRails::VERSION}"]
else
puts "Adding the latest react-on-rails NPM module. " \
"Double check this is correct in package.json"
["react-on-rails"]
end

puts "Installing React on Rails package..."
return if add_npm_dependencies(react_on_rails_pkg)

puts "Using direct npm commands as fallback"
success = system("npm", "install", *react_on_rails_pkg)
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
end

def add_react_dependencies
puts "Installing React dependencies..."
react_deps = %w[
react
react-dom
@babel/preset-react
prop-types
babel-plugin-transform-react-remove-prop-types
babel-plugin-macros
]
return if add_npm_dependencies(react_deps)

success = system("npm", "install", *react_deps)
handle_npm_failure("React dependencies", react_deps) unless success
end

def add_css_dependencies
puts "Installing CSS handling dependencies..."
css_deps = %w[
css-loader
css-minimizer-webpack-plugin
mini-css-extract-plugin
style-loader
]
return if add_npm_dependencies(css_deps)

success = system("npm", "install", *css_deps)
handle_npm_failure("CSS dependencies", css_deps) unless success
end

def add_dev_dependencies
puts "Installing development dependencies..."
dev_deps = %w[
@pmmmwh/react-refresh-webpack-plugin
react-refresh
]
return if add_npm_dependencies(dev_deps, dev: true)

success = system("npm", "install", "--save-dev", *dev_deps)
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
end

def install_js_dependencies
# Detect which package manager to use
success = if File.exist?(File.join(destination_root, "yarn.lock"))
system("yarn", "install")
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
system("pnpm", "install")
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
File.exist?(File.join(destination_root, "package.json"))
# Use npm for package-lock.json or as default fallback
system("npm", "install")
else
true # No package manager detected, skip
end

unless success
GeneratorMessages.add_warning(<<~MSG.strip)
⚠️ JavaScript dependencies installation failed.

This could be due to network issues or missing package manager.
You can install dependencies manually later by running:
• npm install (if using npm)
• yarn install (if using yarn)
• pnpm install (if using pnpm)
MSG
end

success
end

def handle_npm_failure(dependency_type, packages, dev: false)
install_command = dev ? "npm install --save-dev" : "npm install"
GeneratorMessages.add_warning(<<~MSG.strip)
⚠️ Failed to install #{dependency_type}.

The following packages could not be installed automatically:
#{packages.map { |pkg| " • #{pkg}" }.join("\n")}

This could be due to network issues or missing package manager.
You can install them manually later by running:
#{install_command} #{packages.join(' ')}
MSG
end

def copy_webpack_main_config(base_path, config)
webpack_config_path = "config/webpack/webpack.config.js"

Expand Down
185 changes: 5 additions & 180 deletions lib/generators/react_on_rails/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
require "json"
require_relative "generator_helper"
require_relative "generator_messages"
require_relative "js_dependency_manager"

module ReactOnRails
module Generators
# rubocop:disable Metrics/ClassLength
class InstallGenerator < Rails::Generators::Base
include GeneratorHelper
include JsDependencyManager

# fetch USAGE file for details generator description
source_root(File.expand_path(__dir__))
Expand Down Expand Up @@ -113,10 +115,7 @@ def invoke_generators
end

def setup_react_dependencies
@added_dependencies_to_package_json ||= false
@ran_direct_installs ||= false
add_js_dependencies
install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs
setup_js_dependencies
end

# NOTE: other requirements for existing files such as .gitignore or application.
Expand Down Expand Up @@ -366,29 +365,8 @@ def missing_package_manager?

def install_typescript_dependencies
puts Rainbow("📝 Installing TypeScript dependencies...").yellow

# Install TypeScript and React type definitions
typescript_packages = %w[
typescript
@types/react
@types/react-dom
@babel/preset-typescript
]

# Try using GeneratorHelper first (package manager agnostic)
return if add_npm_dependencies(typescript_packages, dev: true)

# Fallback to npm if GeneratorHelper fails
success = system("npm", "install", "--save-dev", *typescript_packages)
return if success

warning = <<~MSG.strip
⚠️ Failed to install TypeScript dependencies automatically.

Please run manually:
npm install --save-dev #{typescript_packages.join(' ')}
MSG
GeneratorMessages.add_warning(warning)
# Delegate to shared module for consistent dependency management
add_typescript_dependencies
end

def create_css_module_types
Expand Down Expand Up @@ -450,159 +428,6 @@ def create_typescript_config
puts Rainbow("✅ Created tsconfig.json").green
end

def add_js_dependencies
add_react_on_rails_package
add_react_dependencies
add_css_dependencies
add_rspack_dependencies if options.rspack?
add_dev_dependencies
end

def add_react_on_rails_package
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/

# Try to use package_json gem first, fall back to direct npm commands
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
["react-on-rails@#{ReactOnRails::VERSION}"]
else
puts "Adding the latest react-on-rails NPM module. " \
"Double check this is correct in package.json"
["react-on-rails"]
end

puts "Installing React on Rails package..."
if add_npm_dependencies(react_on_rails_pkg)
@added_dependencies_to_package_json = true
return
end

puts "Using direct npm commands as fallback"
success = system("npm", "install", *react_on_rails_pkg)
@ran_direct_installs = true if success
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
end

def add_react_dependencies
puts "Installing React dependencies..."
react_deps = %w[
react
react-dom
@babel/preset-react
prop-types
babel-plugin-transform-react-remove-prop-types
babel-plugin-macros
]
if add_npm_dependencies(react_deps)
@added_dependencies_to_package_json = true
return
end

success = system("npm", "install", *react_deps)
@ran_direct_installs = true if success
handle_npm_failure("React dependencies", react_deps) unless success
end

def add_css_dependencies
puts "Installing CSS handling dependencies..."
css_deps = %w[
css-loader
css-minimizer-webpack-plugin
mini-css-extract-plugin
style-loader
]
if add_npm_dependencies(css_deps)
@added_dependencies_to_package_json = true
return
end

success = system("npm", "install", *css_deps)
@ran_direct_installs = true if success
handle_npm_failure("CSS dependencies", css_deps) unless success
end

def add_rspack_dependencies
puts "Installing Rspack core dependencies..."
rspack_deps = %w[
@rspack/core
rspack-manifest-plugin
]
if add_npm_dependencies(rspack_deps)
@added_dependencies_to_package_json = true
return
end

success = system("npm", "install", *rspack_deps)
@ran_direct_installs = true if success
handle_npm_failure("Rspack dependencies", rspack_deps) unless success
end

def add_dev_dependencies
puts "Installing development dependencies..."
dev_deps = if options.rspack?
%w[
@rspack/cli
@rspack/plugin-react-refresh
react-refresh
]
else
%w[
@pmmmwh/react-refresh-webpack-plugin
react-refresh
]
end
if add_npm_dependencies(dev_deps, dev: true)
@added_dependencies_to_package_json = true
return
end

success = system("npm", "install", "--save-dev", *dev_deps)
@ran_direct_installs = true if success
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
end

def install_js_dependencies
# Detect which package manager to use
success = if File.exist?(File.join(destination_root, "yarn.lock"))
system("yarn", "install")
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
system("pnpm", "install")
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
File.exist?(File.join(destination_root, "package.json"))
# Use npm for package-lock.json or as default fallback
system("npm", "install")
else
true # No package manager detected, skip
end

unless success
GeneratorMessages.add_warning(<<~MSG.strip)
⚠️ JavaScript dependencies installation failed.

This could be due to network issues or missing package manager.
You can install dependencies manually later by running:
• npm install (if using npm)
• yarn install (if using yarn)
• pnpm install (if using pnpm)
MSG
end

success
end

def handle_npm_failure(dependency_type, packages, dev: false)
install_command = dev ? "npm install --save-dev" : "npm install"
GeneratorMessages.add_warning(<<~MSG.strip)
⚠️ Failed to install #{dependency_type}.

The following packages could not be installed automatically:
#{packages.map { |pkg| " • #{pkg}" }.join("\n")}

This could be due to network issues or missing package manager.
You can install them manually later by running:
#{install_command} #{packages.join(' ')}
MSG
end

# Removed: Shakapacker auto-installation logic (now explicit dependency)

# Removed: Shakapacker 8+ is now required as explicit dependency
Expand Down
Loading
Loading