react_on_rails 15.0.0.rc.2 → 16.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +65 -36
- data/CLAUDE.md +90 -0
- data/CODING_AGENTS.md +312 -0
- data/CONTRIBUTING.md +378 -3
- data/Gemfile.lock +2 -1
- data/LICENSE.md +16 -4
- data/LICENSES/README.md +14 -0
- data/REACT-ON-RAILS-PRO-LICENSE.md +129 -0
- data/README.md +2 -2
- data/TODO.md +135 -0
- data/eslint.config.ts +2 -0
- data/lib/generators/USAGE +4 -5
- data/lib/generators/react_on_rails/base_generator.rb +263 -57
- data/lib/generators/react_on_rails/bin/dev +38 -22
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -0
- data/lib/generators/react_on_rails/generator_helper.rb +31 -1
- data/lib/generators/react_on_rails/generator_messages.rb +138 -17
- data/lib/generators/react_on_rails/install_generator.rb +222 -20
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +6 -5
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +37 -13
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +5 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-prod-assets +8 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static-assets +2 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js +1 -8
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx +21 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.server.jsx +5 -0
- data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/views/layouts/hello_world.html.erb +4 -2
- data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +5 -2
- data/lib/generators/react_on_rails/templates/base/base/bin/dev +46 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +3 -3
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +76 -7
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +8 -8
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb +0 -2
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -6
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.jsx +5 -0
- data/lib/react_on_rails/configuration.rb +5 -5
- data/lib/react_on_rails/controller.rb +5 -3
- data/lib/react_on_rails/dev/file_manager.rb +78 -0
- data/lib/react_on_rails/dev/pack_generator.rb +27 -0
- data/lib/react_on_rails/dev/process_manager.rb +61 -0
- data/lib/react_on_rails/dev/server_manager.rb +330 -0
- data/lib/react_on_rails/dev.rb +20 -0
- data/lib/react_on_rails/engine.rb +6 -0
- data/lib/react_on_rails/git_utils.rb +12 -2
- data/lib/react_on_rails/helper.rb +61 -17
- data/lib/react_on_rails/packer_utils.rb +4 -18
- data/lib/react_on_rails/packs_generator.rb +134 -8
- data/lib/react_on_rails/react_component/render_options.rb +2 -2
- data/lib/react_on_rails/server_rendering_js_code.rb +0 -1
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +1 -0
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +1 -0
- data/lib/react_on_rails/utils.rb +16 -1
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_syntax_converter.rb +1 -1
- data/lib/react_on_rails.rb +1 -0
- data/lib/tasks/generate_packs.rake +20 -0
- data/react_on_rails.gemspec +1 -0
- metadata +40 -11
- data/REACT-ON-RAILS-PRO-LICENSE +0 -95
- data/lib/generators/react_on_rails/adapt_for_older_shakapacker_generator.rb +0 -41
- data/lib/generators/react_on_rails/bin/dev-static +0 -30
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static.tt +0 -9
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt +0 -8
- /data/lib/generators/react_on_rails/templates/base/base/config/webpack/{webpackConfig.js.tt → generateWebpackConfigs.js.tt} +0 -0
- /data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/{HelloWorldApp.jsx → HelloWorldApp.client.jsx} +0 -0
@@ -1,11 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "package_json"
|
4
3
|
require "rainbow"
|
4
|
+
require "json"
|
5
5
|
|
6
6
|
module GeneratorHelper
|
7
7
|
def package_json
|
8
|
+
# Lazy load package_json gem only when actually needed for dependency management
|
9
|
+
|
10
|
+
require "package_json" unless defined?(PackageJson)
|
8
11
|
@package_json ||= PackageJson.read
|
12
|
+
rescue LoadError
|
13
|
+
puts "Warning: package_json gem not available. This is expected before Shakapacker installation."
|
14
|
+
puts "Dependencies will be installed using the default package manager after Shakapacker setup."
|
15
|
+
nil
|
16
|
+
rescue StandardError => e
|
17
|
+
puts "Warning: Could not read package.json: #{e.message}"
|
18
|
+
puts "This is normal before Shakapacker creates the package.json file."
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# Safe wrapper for package_json operations
|
23
|
+
def add_npm_dependencies(packages, dev: false)
|
24
|
+
pj = package_json
|
25
|
+
return false unless pj
|
26
|
+
|
27
|
+
begin
|
28
|
+
if dev
|
29
|
+
pj.manager.add(packages, type: :dev)
|
30
|
+
else
|
31
|
+
pj.manager.add(packages)
|
32
|
+
end
|
33
|
+
true
|
34
|
+
rescue StandardError => e
|
35
|
+
puts "Warning: Could not add packages via package_json gem: #{e.message}"
|
36
|
+
puts "Will fall back to direct npm commands."
|
37
|
+
false
|
38
|
+
end
|
9
39
|
end
|
10
40
|
|
11
41
|
# Takes a relative path from the destination root, such as `.gitignore` or `app/assets/javascripts/application.js`
|
@@ -38,37 +38,158 @@ module GeneratorMessages
|
|
38
38
|
@output = []
|
39
39
|
end
|
40
40
|
|
41
|
-
def helpful_message_after_installation
|
41
|
+
def helpful_message_after_installation(component_name: "HelloWorld")
|
42
|
+
process_manager_section = build_process_manager_section
|
43
|
+
testing_section = build_testing_section
|
44
|
+
package_manager = detect_package_manager
|
45
|
+
shakapacker_status = build_shakapacker_status_section
|
46
|
+
|
42
47
|
<<~MSG
|
43
48
|
|
44
|
-
|
49
|
+
╔════════════════════════════════════════════════════════════════════════╗
|
50
|
+
║ 🎉 React on Rails Successfully Installed! ║
|
51
|
+
╚════════════════════════════════════════════════════════════════════════╝
|
52
|
+
#{process_manager_section}#{shakapacker_status}
|
53
|
+
|
54
|
+
📋 QUICK START:
|
55
|
+
─────────────────────────────────────────────────────────────────────────
|
56
|
+
1. Install dependencies:
|
57
|
+
#{Rainbow("bundle && #{package_manager} install").cyan}
|
58
|
+
|
59
|
+
2. Start the app:
|
60
|
+
./bin/dev # HMR (Hot Module Replacement) mode
|
61
|
+
./bin/dev static # Static bundles (no HMR, faster initial load)
|
62
|
+
./bin/dev prod # Production-like mode for testing
|
63
|
+
./bin/dev help # See all available options
|
64
|
+
|
65
|
+
3. Visit: #{Rainbow('http://localhost:3000/hello_world').cyan.underline}
|
66
|
+
✨ KEY FEATURES:
|
67
|
+
─────────────────────────────────────────────────────────────────────────
|
68
|
+
• Auto-registration enabled - Your layout only needs:
|
69
|
+
<%= javascript_pack_tag %>
|
70
|
+
<%= stylesheet_pack_tag %>
|
71
|
+
|
72
|
+
• Server-side rendering - Enabled with prerender option in app/views/hello_world/index.html.erb:
|
73
|
+
<%= react_component("#{component_name}", props: @hello_world_props, prerender: true) %>
|
74
|
+
|
75
|
+
📚 LEARN MORE:
|
76
|
+
─────────────────────────────────────────────────────────────────────────
|
77
|
+
• Documentation: #{Rainbow('https://www.shakacode.com/react-on-rails/docs/').cyan.underline}
|
78
|
+
• Webpack customization: #{Rainbow('https://github.com/shakacode/shakapacker#webpack-configuration').cyan.underline}
|
79
|
+
|
80
|
+
💡 TIP: Run 'bin/dev help' for development server options and troubleshooting#{testing_section}
|
81
|
+
MSG
|
82
|
+
end
|
45
83
|
|
46
|
-
|
47
|
-
|
84
|
+
private
|
85
|
+
|
86
|
+
def build_process_manager_section
|
87
|
+
process_manager = detect_process_manager
|
88
|
+
if process_manager
|
89
|
+
if process_manager == "overmind"
|
90
|
+
"\n📦 #{Rainbow("#{process_manager} detected ✓").green} " \
|
91
|
+
"#{Rainbow('(Recommended for easier debugging)').blue}"
|
92
|
+
else
|
93
|
+
"\n📦 #{Rainbow("#{process_manager} detected ✓").green}"
|
94
|
+
end
|
95
|
+
else
|
96
|
+
<<~INSTALL
|
97
|
+
|
98
|
+
⚠️ No process manager detected. Install one:
|
99
|
+
#{Rainbow('brew install overmind').yellow.bold} # Recommended (easier debugging)
|
100
|
+
#{Rainbow('gem install foreman').yellow} # Alternative
|
101
|
+
INSTALL
|
102
|
+
end
|
103
|
+
end
|
48
104
|
|
49
|
-
|
105
|
+
def build_testing_section
|
106
|
+
# Check if we have any spec files to determine if testing setup is needed
|
107
|
+
has_spec_files = File.exist?("spec/rails_helper.rb") || File.exist?("spec/spec_helper.rb")
|
50
108
|
|
51
|
-
|
109
|
+
return "" if has_spec_files
|
52
110
|
|
53
|
-
|
111
|
+
<<~TESTING
|
54
112
|
|
55
|
-
./bin/dev # Running with HMR
|
56
113
|
|
57
|
-
|
114
|
+
🧪 TESTING SETUP (Optional):
|
115
|
+
─────────────────────────────────────────────────────────────────────────
|
116
|
+
For JavaScript testing with asset compilation, add this to your RSpec config:
|
58
117
|
|
59
|
-
|
118
|
+
# In spec/rails_helper.rb or spec/spec_helper.rb:
|
119
|
+
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
|
120
|
+
TESTING
|
121
|
+
end
|
60
122
|
|
61
|
-
|
62
|
-
|
123
|
+
def detect_process_manager
|
124
|
+
if system("which overmind > /dev/null 2>&1")
|
125
|
+
"overmind"
|
126
|
+
elsif system("which foreman > /dev/null 2>&1")
|
127
|
+
"foreman"
|
128
|
+
end
|
129
|
+
end
|
63
130
|
|
64
|
-
|
131
|
+
def build_shakapacker_status_section
|
132
|
+
version_warning = check_shakapacker_version_warning
|
133
|
+
|
134
|
+
if File.exist?(".shakapacker_just_installed")
|
135
|
+
base_message = <<~SHAKAPACKER
|
136
|
+
|
137
|
+
📦 SHAKAPACKER SETUP:
|
138
|
+
─────────────────────────────────────────────────────────────────────────
|
139
|
+
#{Rainbow('✓ Added to Gemfile automatically').green}
|
140
|
+
#{Rainbow('✓ Installer ran successfully').green}
|
141
|
+
#{Rainbow('✓ Webpack integration configured').green}
|
142
|
+
SHAKAPACKER
|
143
|
+
base_message + version_warning
|
144
|
+
elsif File.exist?("bin/shakapacker") && File.exist?("bin/shakapacker-dev-server")
|
145
|
+
"\n📦 #{Rainbow('Shakapacker already configured ✓').green}#{version_warning}"
|
146
|
+
else
|
147
|
+
"\n📦 #{Rainbow('Shakapacker setup may be incomplete').yellow}#{version_warning}"
|
148
|
+
end
|
149
|
+
end
|
65
150
|
|
66
|
-
|
151
|
+
def check_shakapacker_version_warning
|
152
|
+
# Try to detect Shakapacker version from Gemfile.lock
|
153
|
+
return "" unless File.exist?("Gemfile.lock")
|
67
154
|
|
68
|
-
|
155
|
+
gemfile_lock_content = File.read("Gemfile.lock")
|
156
|
+
shakapacker_match = gemfile_lock_content.match(/shakapacker \((\d+\.\d+\.\d+)\)/)
|
69
157
|
|
70
|
-
|
71
|
-
|
158
|
+
return "" unless shakapacker_match
|
159
|
+
|
160
|
+
version = shakapacker_match[1]
|
161
|
+
major_version = version.split(".").first.to_i
|
162
|
+
|
163
|
+
if major_version < 8
|
164
|
+
<<~WARNING
|
165
|
+
|
166
|
+
⚠️ #{Rainbow('IMPORTANT: Upgrade Recommended').yellow.bold}
|
167
|
+
─────────────────────────────────────────────────────────────────────────
|
168
|
+
You are using Shakapacker #{version}. React on Rails v15+ works best with
|
169
|
+
Shakapacker 8.0+ for optimal Hot Module Replacement and build performance.
|
170
|
+
|
171
|
+
To upgrade: #{Rainbow('bundle update shakapacker').cyan}
|
172
|
+
|
173
|
+
Learn more: #{Rainbow('https://github.com/shakacode/shakapacker').cyan.underline}
|
174
|
+
WARNING
|
175
|
+
else
|
176
|
+
""
|
177
|
+
end
|
178
|
+
rescue StandardError
|
179
|
+
# If version detection fails, don't show a warning to avoid noise
|
180
|
+
""
|
181
|
+
end
|
182
|
+
|
183
|
+
def detect_package_manager
|
184
|
+
# Check for lock files to determine package manager
|
185
|
+
if File.exist?("yarn.lock")
|
186
|
+
"yarn"
|
187
|
+
elsif File.exist?("pnpm-lock.yaml")
|
188
|
+
"pnpm"
|
189
|
+
else
|
190
|
+
# Default to npm (Shakapacker 8.x default) - covers package-lock.json and no lockfile
|
191
|
+
"npm"
|
192
|
+
end
|
72
193
|
end
|
73
194
|
end
|
74
195
|
end
|
@@ -6,6 +6,7 @@ require_relative "generator_messages"
|
|
6
6
|
|
7
7
|
module ReactOnRails
|
8
8
|
module Generators
|
9
|
+
# rubocop:disable Metrics/ClassLength
|
9
10
|
class InstallGenerator < Rails::Generators::Base
|
10
11
|
include GeneratorHelper
|
11
12
|
|
@@ -16,7 +17,7 @@ module ReactOnRails
|
|
16
17
|
class_option :redux,
|
17
18
|
type: :boolean,
|
18
19
|
default: false,
|
19
|
-
desc: "Install Redux
|
20
|
+
desc: "Install Redux package and Redux version of Hello World Example. Default: false",
|
20
21
|
aliases: "-R"
|
21
22
|
|
22
23
|
# --ignore-warnings
|
@@ -25,13 +26,22 @@ module ReactOnRails
|
|
25
26
|
default: false,
|
26
27
|
desc: "Skip warnings. Default: false"
|
27
28
|
|
29
|
+
# Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
|
30
|
+
|
28
31
|
def run_generators
|
29
32
|
if installation_prerequisites_met? || options.ignore_warnings?
|
30
33
|
invoke_generators
|
31
34
|
add_bin_scripts
|
32
35
|
add_post_install_message
|
33
36
|
else
|
34
|
-
error =
|
37
|
+
error = <<~MSG.strip
|
38
|
+
🚫 React on Rails generator prerequisites not met!
|
39
|
+
|
40
|
+
Please resolve the issues listed above before continuing.
|
41
|
+
All prerequisites must be satisfied for a successful installation.
|
42
|
+
|
43
|
+
Use --ignore-warnings to bypass checks (not recommended).
|
44
|
+
MSG
|
35
45
|
GeneratorMessages.add_error(error)
|
36
46
|
end
|
37
47
|
ensure
|
@@ -47,37 +57,82 @@ module ReactOnRails
|
|
47
57
|
end
|
48
58
|
|
49
59
|
def invoke_generators
|
60
|
+
ensure_shakapacker_installed
|
50
61
|
invoke "react_on_rails:base"
|
51
62
|
if options.redux?
|
52
63
|
invoke "react_on_rails:react_with_redux"
|
53
64
|
else
|
54
65
|
invoke "react_on_rails:react_no_redux"
|
55
66
|
end
|
56
|
-
|
57
|
-
invoke "react_on_rails:adapt_for_older_shakapacker" unless using_shakapacker_7_or_above?
|
58
67
|
end
|
59
68
|
|
60
69
|
# NOTE: other requirements for existing files such as .gitignore or application.
|
61
70
|
# js(.coffee) are not checked by this method, but instead produce warning messages
|
62
71
|
# and allow the build to continue
|
63
72
|
def installation_prerequisites_met?
|
64
|
-
!(missing_node? ||
|
73
|
+
!(missing_node? || missing_package_manager? || ReactOnRails::GitUtils.uncommitted_changes?(GeneratorMessages))
|
65
74
|
end
|
66
75
|
|
67
|
-
def
|
68
|
-
|
76
|
+
def missing_node?
|
77
|
+
node_missing = ReactOnRails::Utils.running_on_windows? ? `where node`.blank? : `which node`.blank?
|
78
|
+
|
79
|
+
if node_missing
|
80
|
+
error = <<~MSG.strip
|
81
|
+
🚫 Node.js is required but not found on your system.
|
69
82
|
|
70
|
-
|
71
|
-
|
72
|
-
|
83
|
+
Please install Node.js before continuing:
|
84
|
+
• Download from: https://nodejs.org/en/
|
85
|
+
• Recommended: Use a version manager like nvm, fnm, or volta
|
86
|
+
• Minimum required version: Node.js 18+
|
87
|
+
|
88
|
+
After installation, restart your terminal and try again.
|
89
|
+
MSG
|
90
|
+
GeneratorMessages.add_error(error)
|
91
|
+
return true
|
92
|
+
end
|
93
|
+
|
94
|
+
# Check Node.js version if available
|
95
|
+
check_node_version
|
96
|
+
false
|
73
97
|
end
|
74
98
|
|
75
|
-
def
|
76
|
-
|
99
|
+
def check_node_version
|
100
|
+
node_version = `node --version 2>/dev/null`.strip
|
101
|
+
return if node_version.blank?
|
77
102
|
|
78
|
-
|
79
|
-
|
80
|
-
|
103
|
+
# Extract major version number (e.g., "v18.17.0" -> 18)
|
104
|
+
major_version = node_version[/v(\d+)/, 1]&.to_i
|
105
|
+
return unless major_version
|
106
|
+
|
107
|
+
return unless major_version < 18
|
108
|
+
|
109
|
+
warning = <<~MSG.strip
|
110
|
+
⚠️ Node.js version #{node_version} detected.
|
111
|
+
|
112
|
+
React on Rails recommends Node.js 18+ for best compatibility.
|
113
|
+
You may experience issues with older versions.
|
114
|
+
|
115
|
+
Consider upgrading: https://nodejs.org/en/
|
116
|
+
MSG
|
117
|
+
GeneratorMessages.add_warning(warning)
|
118
|
+
end
|
119
|
+
|
120
|
+
def ensure_shakapacker_installed
|
121
|
+
return if shakapacker_configured?
|
122
|
+
|
123
|
+
print_shakapacker_setup_banner
|
124
|
+
ensure_shakapacker_in_gemfile
|
125
|
+
install_shakapacker
|
126
|
+
finalize_shakapacker_setup
|
127
|
+
end
|
128
|
+
|
129
|
+
# Checks whether "shakapacker" is explicitly declared in this project's Gemfile.
|
130
|
+
# We only check the Gemfile text, not lockfile or dependencies, because
|
131
|
+
# shakapacker might be present as a dependency of react_on_rails but not
|
132
|
+
# properly configured for this specific Rails application.
|
133
|
+
def shakapacker_in_gemfile?
|
134
|
+
gem_name = "shakapacker"
|
135
|
+
shakapacker_in_gemfile_text?(gem_name)
|
81
136
|
end
|
82
137
|
|
83
138
|
def add_bin_scripts
|
@@ -97,13 +152,160 @@ module ReactOnRails
|
|
97
152
|
GeneratorMessages.add_info(GeneratorMessages.helpful_message_after_installation)
|
98
153
|
end
|
99
154
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
155
|
+
def shakapacker_loaded_in_process?(gem_name)
|
156
|
+
Gem.loaded_specs.key?(gem_name)
|
157
|
+
end
|
158
|
+
|
159
|
+
def shakapacker_in_lockfile?(gem_name)
|
160
|
+
gemfile = ENV["BUNDLE_GEMFILE"] || "Gemfile"
|
161
|
+
lockfile = File.join(File.dirname(gemfile), "Gemfile.lock")
|
162
|
+
|
163
|
+
File.file?(lockfile) && File.foreach(lockfile).any? { |l| l.match?(/^\s{4}#{Regexp.escape(gem_name)}\s\(/) }
|
164
|
+
end
|
165
|
+
|
166
|
+
def shakapacker_in_bundler_specs?(gem_name)
|
167
|
+
require "bundler"
|
168
|
+
Bundler.load.specs.any? { |s| s.name == gem_name }
|
169
|
+
rescue StandardError
|
170
|
+
false
|
171
|
+
end
|
172
|
+
|
173
|
+
def shakapacker_in_gemfile_text?(gem_name)
|
174
|
+
gemfile = ENV["BUNDLE_GEMFILE"] || "Gemfile"
|
175
|
+
|
176
|
+
File.file?(gemfile) &&
|
177
|
+
File.foreach(gemfile).any? { |l| l.match?(/^\s*gem\s+['"]#{Regexp.escape(gem_name)}['"]/) }
|
178
|
+
end
|
179
|
+
|
180
|
+
def cli_exists?(command)
|
181
|
+
system("which #{command} > /dev/null 2>&1")
|
182
|
+
end
|
183
|
+
|
184
|
+
def shakapacker_binaries_exist?
|
185
|
+
File.exist?("bin/shakapacker") && File.exist?("bin/shakapacker-dev-server")
|
186
|
+
end
|
187
|
+
|
188
|
+
def shakapacker_configured?
|
189
|
+
# Check for essential shakapacker configuration files and binaries
|
190
|
+
shakapacker_binaries_exist? &&
|
191
|
+
File.exist?("config/shakapacker.yml") &&
|
192
|
+
File.exist?("config/webpack/webpack.config.js")
|
193
|
+
end
|
194
|
+
|
195
|
+
def print_shakapacker_setup_banner
|
196
|
+
puts Rainbow("\n#{'=' * 80}").cyan
|
197
|
+
puts Rainbow("🔧 SHAKAPACKER SETUP").cyan.bold
|
198
|
+
puts Rainbow("=" * 80).cyan
|
199
|
+
end
|
200
|
+
|
201
|
+
def ensure_shakapacker_in_gemfile
|
202
|
+
return if shakapacker_in_gemfile?
|
203
|
+
|
204
|
+
puts Rainbow("📝 Adding Shakapacker to Gemfile...").yellow
|
205
|
+
success = system("bundle add shakapacker --strict")
|
206
|
+
return if success
|
207
|
+
|
208
|
+
handle_shakapacker_gemfile_error
|
209
|
+
end
|
210
|
+
|
211
|
+
def install_shakapacker
|
212
|
+
puts Rainbow("⚙️ Installing Shakapacker (required for webpack integration)...").yellow
|
213
|
+
|
214
|
+
# First run bundle install to make shakapacker available
|
215
|
+
puts Rainbow("📦 Running bundle install...").yellow
|
216
|
+
bundle_success = system("bundle install")
|
217
|
+
unless bundle_success
|
218
|
+
handle_shakapacker_install_error
|
219
|
+
return
|
220
|
+
end
|
221
|
+
|
222
|
+
# Then run the shakapacker installer
|
223
|
+
success = system("bundle exec rails shakapacker:install")
|
224
|
+
return if success
|
225
|
+
|
226
|
+
handle_shakapacker_install_error
|
227
|
+
end
|
228
|
+
|
229
|
+
def finalize_shakapacker_setup
|
230
|
+
puts Rainbow("✅ Shakapacker installed successfully!").green
|
231
|
+
puts Rainbow("=" * 80).cyan
|
232
|
+
puts Rainbow("🚀 CONTINUING WITH REACT ON RAILS SETUP").cyan.bold
|
233
|
+
puts "#{Rainbow('=' * 80).cyan}\n"
|
234
|
+
|
235
|
+
# Create marker file so base generator can avoid copying shakapacker.yml
|
236
|
+
File.write(".shakapacker_just_installed", "")
|
237
|
+
end
|
238
|
+
|
239
|
+
def handle_shakapacker_gemfile_error
|
240
|
+
error = <<~MSG.strip
|
241
|
+
🚫 Failed to add Shakapacker to your Gemfile.
|
242
|
+
|
243
|
+
This could be due to:
|
244
|
+
• Bundle installation issues
|
245
|
+
• Network connectivity problems
|
246
|
+
• Gemfile permissions
|
247
|
+
|
248
|
+
Please try manually:
|
249
|
+
bundle add shakapacker --strict
|
250
|
+
|
251
|
+
Then re-run: rails generate react_on_rails:install
|
252
|
+
MSG
|
253
|
+
GeneratorMessages.add_error(error)
|
254
|
+
raise Thor::Error, error unless options.ignore_warnings?
|
255
|
+
end
|
256
|
+
|
257
|
+
def handle_shakapacker_install_error
|
258
|
+
error = <<~MSG.strip
|
259
|
+
🚫 Failed to install Shakapacker automatically.
|
260
|
+
|
261
|
+
This could be due to:
|
262
|
+
• Missing Node.js or npm/yarn
|
263
|
+
• Network connectivity issues
|
264
|
+
• Incomplete bundle installation
|
265
|
+
• Missing write permissions
|
266
|
+
|
267
|
+
Troubleshooting steps:
|
268
|
+
1. Ensure Node.js is installed: node --version
|
269
|
+
2. Run: bundle install
|
270
|
+
3. Try manually: bundle exec rails shakapacker:install
|
271
|
+
4. Check for error output above
|
272
|
+
5. Re-run: rails generate react_on_rails:install
|
273
|
+
|
274
|
+
Need help? Visit: https://github.com/shakacode/shakapacker/blob/main/docs/installation.md
|
275
|
+
MSG
|
276
|
+
GeneratorMessages.add_error(error)
|
277
|
+
raise Thor::Error, error unless options.ignore_warnings?
|
278
|
+
end
|
279
|
+
|
280
|
+
def missing_package_manager?
|
281
|
+
package_managers = %w[npm pnpm yarn bun]
|
282
|
+
missing = package_managers.none? { |pm| cli_exists?(pm) }
|
283
|
+
|
284
|
+
if missing
|
285
|
+
error = <<~MSG.strip
|
286
|
+
🚫 No JavaScript package manager found on your system.
|
287
|
+
|
288
|
+
React on Rails requires a JavaScript package manager to install dependencies.
|
289
|
+
Please install one of the following:
|
290
|
+
|
291
|
+
• npm: Usually comes with Node.js (https://nodejs.org/en/)
|
292
|
+
• yarn: npm install -g yarn (https://yarnpkg.com/)
|
293
|
+
• pnpm: npm install -g pnpm (https://pnpm.io/)
|
294
|
+
• bun: Install from https://bun.sh/
|
295
|
+
|
296
|
+
After installation, restart your terminal and try again.
|
297
|
+
MSG
|
298
|
+
GeneratorMessages.add_error(error)
|
299
|
+
return true
|
300
|
+
end
|
301
|
+
|
105
302
|
false
|
106
303
|
end
|
304
|
+
|
305
|
+
# Removed: Shakapacker auto-installation logic (now explicit dependency)
|
306
|
+
|
307
|
+
# Removed: Shakapacker 8+ is now required as explicit dependency
|
107
308
|
end
|
309
|
+
# rubocop:enable Metrics/ClassLength
|
108
310
|
end
|
109
311
|
end
|
@@ -7,24 +7,25 @@ module ReactOnRails
|
|
7
7
|
module Generators
|
8
8
|
class ReactNoReduxGenerator < Rails::Generators::Base
|
9
9
|
include GeneratorHelper
|
10
|
+
|
10
11
|
Rails::Generators.hide_namespace(namespace)
|
11
12
|
source_root(File.expand_path("templates", __dir__))
|
12
13
|
|
13
14
|
def copy_base_files
|
14
15
|
base_js_path = "base/base"
|
15
|
-
base_files = %w[app/javascript/
|
16
|
+
base_files = %w[app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx
|
17
|
+
app/javascript/src/HelloWorld/ror_components/HelloWorld.server.jsx
|
18
|
+
app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css]
|
16
19
|
base_files.each { |file| copy_file("#{base_js_path}/#{file}", file) }
|
17
20
|
end
|
18
21
|
|
19
22
|
def create_appropriate_templates
|
20
23
|
base_path = "base/base"
|
21
24
|
config = {
|
22
|
-
component_name: "HelloWorld"
|
23
|
-
app_relative_path: "../bundles/HelloWorld/components/HelloWorld"
|
25
|
+
component_name: "HelloWorld"
|
24
26
|
}
|
25
27
|
|
26
|
-
template
|
27
|
-
"app/javascript/packs/hello-world-bundle.js", config)
|
28
|
+
# Only create the view template - no manual bundle needed for auto registration
|
28
29
|
template("#{base_path}/app/views/hello_world/index.html.erb.tt",
|
29
30
|
"app/views/hello_world/index.html.erb", config)
|
30
31
|
end
|
@@ -9,14 +9,30 @@ module ReactOnRails
|
|
9
9
|
source_root(File.expand_path("templates", __dir__))
|
10
10
|
|
11
11
|
def create_redux_directories
|
12
|
-
|
13
|
-
|
12
|
+
# Create auto-registration directory structure for Redux
|
13
|
+
empty_directory("app/javascript/src/HelloWorldApp/ror_components")
|
14
|
+
|
15
|
+
# Create Redux support directories within the component directory
|
16
|
+
dirs = %w[actions constants containers reducers store components]
|
17
|
+
dirs.each { |name| empty_directory("app/javascript/src/HelloWorldApp/#{name}") }
|
14
18
|
end
|
15
19
|
|
16
20
|
def copy_base_files
|
17
21
|
base_js_path = "redux/base"
|
18
|
-
|
19
|
-
|
22
|
+
|
23
|
+
# Copy Redux-connected component to auto-registration structure
|
24
|
+
copy_file("#{base_js_path}/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.client.jsx",
|
25
|
+
"app/javascript/src/HelloWorldApp/ror_components/HelloWorldApp.client.jsx")
|
26
|
+
copy_file("#{base_js_path}/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.jsx",
|
27
|
+
"app/javascript/src/HelloWorldApp/ror_components/HelloWorldApp.server.jsx")
|
28
|
+
copy_file("#{base_js_path}/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css",
|
29
|
+
"app/javascript/src/HelloWorldApp/components/HelloWorld.module.css")
|
30
|
+
|
31
|
+
# Update import paths in client component
|
32
|
+
ror_client_file = "app/javascript/src/HelloWorldApp/ror_components/HelloWorldApp.client.jsx"
|
33
|
+
gsub_file(ror_client_file, "../store/helloWorldStore", "../store/helloWorldStore")
|
34
|
+
gsub_file(ror_client_file, "../containers/HelloWorldContainer",
|
35
|
+
"../containers/HelloWorldContainer")
|
20
36
|
end
|
21
37
|
|
22
38
|
def copy_base_redux_files
|
@@ -26,26 +42,34 @@ module ReactOnRails
|
|
26
42
|
constants/helloWorldConstants.js
|
27
43
|
reducers/helloWorldReducer.js
|
28
44
|
store/helloWorldStore.js
|
29
|
-
|
45
|
+
components/HelloWorld.jsx].each do |file|
|
30
46
|
copy_file("#{base_hello_world_path}/#{file}",
|
31
|
-
"app/javascript/
|
47
|
+
"app/javascript/src/HelloWorldApp/#{file}")
|
32
48
|
end
|
33
49
|
end
|
34
50
|
|
35
51
|
def create_appropriate_templates
|
36
52
|
base_path = "base/base"
|
37
|
-
base_js_path = "#{base_path}/app/javascript"
|
38
53
|
config = {
|
39
|
-
component_name: "HelloWorldApp"
|
40
|
-
app_relative_path: "../bundles/HelloWorld/startup/HelloWorldApp"
|
54
|
+
component_name: "HelloWorldApp"
|
41
55
|
}
|
42
56
|
|
43
|
-
|
44
|
-
template("#{base_path}/app/views/hello_world/index.html.erb.tt",
|
57
|
+
# Only create the view template - no manual bundle needed for auto registration
|
58
|
+
template("#{base_path}/app/views/hello_world/index.html.erb.tt",
|
59
|
+
"app/views/hello_world/index.html.erb", config)
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_redux_npm_dependencies
|
63
|
+
run "npm install redux react-redux"
|
45
64
|
end
|
46
65
|
|
47
|
-
def
|
48
|
-
|
66
|
+
def add_redux_specific_messages
|
67
|
+
# Override the generic messages with Redux-specific instructions
|
68
|
+
require_relative "generator_messages"
|
69
|
+
GeneratorMessages.output.clear
|
70
|
+
GeneratorMessages.add_info(
|
71
|
+
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp")
|
72
|
+
)
|
49
73
|
end
|
50
74
|
end
|
51
75
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# Procfile for development with production assets
|
2
|
+
# Uses production-optimized, precompiled assets with development environment
|
3
|
+
# Uncomment additional processes as needed for your app
|
4
|
+
|
5
|
+
rails: bundle exec rails s -p 3001
|
6
|
+
# sidekiq: bundle exec sidekiq -C config/sidekiq.yml
|
7
|
+
# redis: redis-server
|
8
|
+
# mailcatcher: mailcatcher --foreground
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import PropTypes from 'prop-types';
|
2
1
|
import React, { useState } from 'react';
|
3
2
|
import * as style from './HelloWorld.module.css';
|
4
3
|
|
@@ -19,8 +18,4 @@ const HelloWorld = (props) => {
|
|
19
18
|
);
|
20
19
|
};
|
21
20
|
|
22
|
-
HelloWorld.propTypes = {
|
23
|
-
name: PropTypes.string.isRequired, // this is passed from the Rails view
|
24
|
-
};
|
25
|
-
|
26
21
|
export default HelloWorld;
|