react_on_rails 16.4.0.rc.1 → 16.4.0.rc.2
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/.rubocop.yml +2 -0
- data/Gemfile.lock +1 -1
- data/lib/generators/react_on_rails/base_generator.rb +30 -10
- data/lib/generators/react_on_rails/dev_tests_generator.rb +9 -1
- data/lib/generators/react_on_rails/generator_helper.rb +101 -0
- data/lib/generators/react_on_rails/generator_messages.rb +2 -2
- data/lib/generators/react_on_rails/install_generator.rb +55 -19
- data/lib/generators/react_on_rails/js_dependency_manager.rb +115 -8
- data/lib/generators/react_on_rails/pro/USAGE +21 -0
- data/lib/generators/react_on_rails/pro_generator.rb +97 -0
- data/lib/generators/react_on_rails/pro_setup.rb +314 -0
- data/lib/generators/react_on_rails/rsc/USAGE +23 -0
- data/lib/generators/react_on_rails/rsc_generator.rb +100 -0
- data/lib/generators/react_on_rails/rsc_setup.rb +471 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -3
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/{generateWebpackConfigs.js.tt → ServerClientOrBoth.js.tt} +28 -3
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt +8 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +2 -2
- 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/serverWebpackConfig.js.tt +54 -0
- 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_server_spec.rb +17 -0
- data/lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js +41 -0
- data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +25 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb +25 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx +80 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx +90 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.jsx +54 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.tsx +54 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.jsx +10 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.tsx +10 -0
- data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb +37 -0
- data/lib/generators/react_on_rails/templates/rsc/base/config/webpack/rscWebpackConfig.js.tt +64 -0
- data/lib/react_on_rails/engine.rb +5 -1
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +6 -1
- metadata +21 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 880046575d7835f62a0a81e6613e38de78f23d923510af15ecff3ca6aaf30f82
|
|
4
|
+
data.tar.gz: 7090c54cae36e825fb88b25279c9152c9bd3cb7b0d38b072c43e5477fb050485
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1f7ddba8f47287950edae782fe3abca7caaf8ad683047962d0a92a085134ff28cda589f7c9fa6b2ce0467f5a7c199a0ec202630e160c1e76ec1230587d8e27a
|
|
7
|
+
data.tar.gz: 237295bfd09024fc32307555d9fde545d94e64c272547f3c653614f7bd49e3d8b5a65956bb19bc355456c4d54240c0e766880b4bde1868ee7dee2a3da56d374e
|
data/.rubocop.yml
CHANGED
|
@@ -59,6 +59,8 @@ RSpec/BeforeAfterAll:
|
|
|
59
59
|
Exclude:
|
|
60
60
|
- 'spec/react_on_rails/generators/dev_tests_generator_spec.rb'
|
|
61
61
|
- 'spec/react_on_rails/generators/install_generator_spec.rb'
|
|
62
|
+
- 'spec/react_on_rails/generators/pro_generator_spec.rb'
|
|
63
|
+
- 'spec/react_on_rails/generators/rsc_generator_spec.rb'
|
|
62
64
|
- 'spec/react_on_rails/binstubs/dev_spec.rb'
|
|
63
65
|
- 'spec/react_on_rails/binstubs/dev_static_spec.rb'
|
|
64
66
|
- 'spec/react_on_rails/dev/**/*_spec.rb' # Dev module tests require global setup
|
data/Gemfile.lock
CHANGED
|
@@ -27,27 +27,46 @@ module ReactOnRails
|
|
|
27
27
|
default: false,
|
|
28
28
|
desc: "Use Rspack instead of Webpack as the bundler"
|
|
29
29
|
|
|
30
|
+
# --pro
|
|
31
|
+
class_option :pro,
|
|
32
|
+
type: :boolean,
|
|
33
|
+
default: false,
|
|
34
|
+
desc: "Setup React on Rails Pro with Node Renderer"
|
|
35
|
+
|
|
36
|
+
# --rsc
|
|
37
|
+
class_option :rsc,
|
|
38
|
+
type: :boolean,
|
|
39
|
+
default: false,
|
|
40
|
+
desc: "Setup React Server Components (requires Pro)"
|
|
41
|
+
|
|
30
42
|
def add_hello_world_route
|
|
43
|
+
# RSC uses HelloServer instead of HelloWorld, but Redux still needs hello_world route
|
|
44
|
+
return if use_rsc? && !options.redux?
|
|
45
|
+
|
|
31
46
|
route "get 'hello_world', to: 'hello_world#index'"
|
|
32
47
|
end
|
|
33
48
|
|
|
34
49
|
def create_react_directories
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
return if options.redux?
|
|
50
|
+
# Skip HelloWorld directory for Redux (uses HelloWorldApp) or RSC (uses HelloServer)
|
|
51
|
+
return if options.redux? || use_rsc?
|
|
38
52
|
|
|
39
53
|
empty_directory("app/javascript/src/HelloWorld/ror_components")
|
|
40
54
|
end
|
|
41
55
|
|
|
42
56
|
def copy_base_files
|
|
43
57
|
base_path = "base/base/"
|
|
44
|
-
base_files = %w[
|
|
45
|
-
app/views/layouts/hello_world.html.erb
|
|
46
|
-
Procfile.dev
|
|
58
|
+
base_files = %w[Procfile.dev
|
|
47
59
|
Procfile.dev-static-assets
|
|
48
60
|
Procfile.dev-prod-assets
|
|
49
61
|
.dev-services.yml.example
|
|
50
62
|
bin/shakapacker-precompile-hook]
|
|
63
|
+
|
|
64
|
+
# HelloWorld controller/layout only when not using RSC (RSC uses HelloServer)
|
|
65
|
+
# Exception: Redux still needs the HelloWorld controller even with RSC
|
|
66
|
+
unless use_rsc? && !options.redux?
|
|
67
|
+
base_files += %w[app/controllers/hello_world_controller.rb
|
|
68
|
+
app/views/layouts/hello_world.html.erb]
|
|
69
|
+
end
|
|
51
70
|
base_templates = %w[config/initializers/react_on_rails.rb]
|
|
52
71
|
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
|
53
72
|
base_templates.each do |file|
|
|
@@ -62,9 +81,10 @@ module ReactOnRails
|
|
|
62
81
|
base_path = "base/base/"
|
|
63
82
|
base_files = %w[app/javascript/packs/server-bundle.js]
|
|
64
83
|
|
|
65
|
-
#
|
|
66
|
-
|
|
67
|
-
|
|
84
|
+
# Skip HelloWorld CSS for Redux (uses HelloWorldApp) or RSC (uses HelloServer)
|
|
85
|
+
unless options.redux? || use_rsc?
|
|
86
|
+
base_files << "app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css"
|
|
87
|
+
end
|
|
68
88
|
|
|
69
89
|
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
|
70
90
|
end
|
|
@@ -79,7 +99,7 @@ module ReactOnRails
|
|
|
79
99
|
config/webpack/development.js
|
|
80
100
|
config/webpack/production.js
|
|
81
101
|
config/webpack/serverWebpackConfig.js
|
|
82
|
-
config/webpack/
|
|
102
|
+
config/webpack/ServerClientOrBoth.js]
|
|
83
103
|
config = {
|
|
84
104
|
message: "// The source code including full typescript support is available at:"
|
|
85
105
|
}
|
|
@@ -17,6 +17,12 @@ module ReactOnRails
|
|
|
17
17
|
default: false,
|
|
18
18
|
desc: "Setup prerender true for server rendered examples"
|
|
19
19
|
|
|
20
|
+
# --rsc
|
|
21
|
+
class_option :rsc,
|
|
22
|
+
type: :boolean,
|
|
23
|
+
default: false,
|
|
24
|
+
desc: "Include React Server Components test (hello_server_spec.rb)"
|
|
25
|
+
|
|
20
26
|
def copy_rspec_files
|
|
21
27
|
%w[.eslintrc
|
|
22
28
|
spec/spec_helper.rb
|
|
@@ -26,7 +32,9 @@ module ReactOnRails
|
|
|
26
32
|
end
|
|
27
33
|
|
|
28
34
|
def copy_tests
|
|
29
|
-
%w[spec/system/hello_world_spec.rb]
|
|
35
|
+
files = %w[spec/system/hello_world_spec.rb]
|
|
36
|
+
files << "spec/system/hello_server_spec.rb" if options.rsc
|
|
37
|
+
files.each { |file| copy_file(file) }
|
|
30
38
|
end
|
|
31
39
|
|
|
32
40
|
def add_test_related_gems_to_gemfile
|
|
@@ -92,10 +92,85 @@ module GeneratorHelper
|
|
|
92
92
|
"#{message} \n#{source}"
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
+
def print_generator_messages
|
|
96
|
+
GeneratorMessages.messages.each do |message|
|
|
97
|
+
puts message
|
|
98
|
+
puts "" # Blank line after each message for readability
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
95
102
|
def component_extension(options)
|
|
96
103
|
options.typescript? ? "tsx" : "jsx"
|
|
97
104
|
end
|
|
98
105
|
|
|
106
|
+
# Check if a gem is present in Gemfile.lock
|
|
107
|
+
# Always checks the target app's Gemfile.lock, not inherited BUNDLE_GEMFILE
|
|
108
|
+
# See: https://github.com/shakacode/react_on_rails/issues/2287
|
|
109
|
+
#
|
|
110
|
+
# @param gem_name [String] Name of the gem to check
|
|
111
|
+
# @return [Boolean] true if the gem is in Gemfile.lock
|
|
112
|
+
def gem_in_lockfile?(gem_name)
|
|
113
|
+
File.file?("Gemfile.lock") &&
|
|
114
|
+
File.foreach("Gemfile.lock").any? { |line| line.match?(/^\s{4}#{Regexp.escape(gem_name)}\s\(/) }
|
|
115
|
+
rescue StandardError
|
|
116
|
+
false
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Check if React on Rails Pro gem is installed
|
|
120
|
+
#
|
|
121
|
+
# Detection priority:
|
|
122
|
+
# 1. Gem.loaded_specs - gem is loaded in current Ruby process (most reliable)
|
|
123
|
+
# 2. Gemfile.lock - gem is resolved and installed
|
|
124
|
+
#
|
|
125
|
+
# @return [Boolean] true if react_on_rails_pro gem is installed
|
|
126
|
+
def pro_gem_installed?
|
|
127
|
+
return @pro_gem_installed if defined?(@pro_gem_installed)
|
|
128
|
+
|
|
129
|
+
@pro_gem_installed = Gem.loaded_specs.key?("react_on_rails_pro") || gem_in_lockfile?("react_on_rails_pro")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Check if Pro features should be enabled
|
|
133
|
+
# Returns true if --pro flag is set OR --rsc flag is set (RSC implies Pro)
|
|
134
|
+
#
|
|
135
|
+
# @return [Boolean] true if Pro setup should be included
|
|
136
|
+
def use_pro?
|
|
137
|
+
options[:pro] || options[:rsc]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Check if RSC (React Server Components) should be enabled
|
|
141
|
+
# Returns true only if --rsc flag is explicitly set
|
|
142
|
+
#
|
|
143
|
+
# @return [Boolean] true if RSC setup should be included
|
|
144
|
+
def use_rsc?
|
|
145
|
+
options[:rsc]
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Detect the installed React version from package.json
|
|
149
|
+
# Uses VERSION_PARTS_REGEX pattern from VersionChecker for consistency
|
|
150
|
+
#
|
|
151
|
+
# @return [String, nil] React version string (e.g., "19.0.3") or nil if not found/parseable
|
|
152
|
+
def detect_react_version
|
|
153
|
+
pj = package_json
|
|
154
|
+
return nil unless pj
|
|
155
|
+
|
|
156
|
+
dependencies = pj.fetch("dependencies", {})
|
|
157
|
+
react_version = dependencies["react"]
|
|
158
|
+
return nil unless react_version
|
|
159
|
+
|
|
160
|
+
# Skip non-version strings (workspace:*, file:, link:, http://, etc.)
|
|
161
|
+
return nil if react_version.include?("/") || react_version.start_with?("workspace:")
|
|
162
|
+
|
|
163
|
+
# Extract version using the same regex pattern as VersionChecker
|
|
164
|
+
# Handles: "19.0.3", "^19.0.3", "~19.0.3", "19.0.3-beta.1", etc.
|
|
165
|
+
match = react_version.match(/(\d+)\.(\d+)\.(\d+)(?:[-.]([0-9A-Za-z.-]+))?/)
|
|
166
|
+
return nil unless match
|
|
167
|
+
|
|
168
|
+
# Return the matched version (without pre-release suffix for comparison)
|
|
169
|
+
"#{match[1]}.#{match[2]}.#{match[3]}"
|
|
170
|
+
rescue StandardError
|
|
171
|
+
nil
|
|
172
|
+
end
|
|
173
|
+
|
|
99
174
|
# Check if Shakapacker 9.0 or higher is available
|
|
100
175
|
# Returns true if Shakapacker >= 9.0, false otherwise
|
|
101
176
|
#
|
|
@@ -146,6 +221,32 @@ module GeneratorHelper
|
|
|
146
221
|
@using_swc = detect_swc_configuration
|
|
147
222
|
end
|
|
148
223
|
|
|
224
|
+
# Resolve the path to ServerClientOrBoth.js, handling the legacy name.
|
|
225
|
+
# Old installs may still use generateWebpackConfigs.js; this renames it
|
|
226
|
+
# and updates references in environment configs so downstream transforms
|
|
227
|
+
# can rely on the canonical name.
|
|
228
|
+
#
|
|
229
|
+
# @return [String, nil] relative config path, or nil if neither file exists
|
|
230
|
+
def resolve_server_client_or_both_path
|
|
231
|
+
new_path = "config/webpack/ServerClientOrBoth.js"
|
|
232
|
+
old_path = "config/webpack/generateWebpackConfigs.js"
|
|
233
|
+
full_new = File.join(destination_root, new_path)
|
|
234
|
+
full_old = File.join(destination_root, old_path)
|
|
235
|
+
|
|
236
|
+
if File.exist?(full_new)
|
|
237
|
+
new_path
|
|
238
|
+
elsif File.exist?(full_old)
|
|
239
|
+
FileUtils.mv(full_old, full_new)
|
|
240
|
+
%w[development.js production.js test.js].each do |env_file|
|
|
241
|
+
env_path = "config/webpack/#{env_file}"
|
|
242
|
+
if File.exist?(File.join(destination_root, env_path))
|
|
243
|
+
gsub_file(env_path, /generateWebpackConfigs/, "ServerClientOrBoth")
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
new_path
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
149
250
|
private
|
|
150
251
|
|
|
151
252
|
def detect_swc_configuration
|
|
@@ -69,8 +69,8 @@ module GeneratorMessages
|
|
|
69
69
|
<%= javascript_pack_tag %>
|
|
70
70
|
<%= stylesheet_pack_tag %>
|
|
71
71
|
|
|
72
|
-
• Server-side rendering - Enabled with prerender option in app/views/
|
|
73
|
-
<%= react_component("#{component_name}", props:
|
|
72
|
+
• Server-side rendering - Enabled with prerender option in app/views/#{route}/index.html.erb:
|
|
73
|
+
<%= react_component("#{component_name}", props: @#{route}_props, prerender: true) %>
|
|
74
74
|
|
|
75
75
|
📚 LEARN MORE:
|
|
76
76
|
─────────────────────────────────────────────────────────────────────────
|
|
@@ -6,13 +6,20 @@ require "bundler"
|
|
|
6
6
|
require_relative "generator_helper"
|
|
7
7
|
require_relative "generator_messages"
|
|
8
8
|
require_relative "js_dependency_manager"
|
|
9
|
+
require_relative "pro_setup"
|
|
10
|
+
require_relative "rsc_setup"
|
|
9
11
|
|
|
10
12
|
module ReactOnRails
|
|
11
13
|
module Generators
|
|
14
|
+
# TODO: Extract more modules to reduce class length below 150 lines.
|
|
15
|
+
# Candidates: ShakapackerSetup (~100 lines), TypeScriptSetup (~60 lines),
|
|
16
|
+
# ValidationHelpers (~80 lines for Node/package manager checks).
|
|
12
17
|
# rubocop:disable Metrics/ClassLength
|
|
13
18
|
class InstallGenerator < Rails::Generators::Base
|
|
14
19
|
include GeneratorHelper
|
|
15
20
|
include JsDependencyManager
|
|
21
|
+
include ProSetup
|
|
22
|
+
include RscSetup
|
|
16
23
|
|
|
17
24
|
# fetch USAGE file for details generator description
|
|
18
25
|
source_root(File.expand_path(__dir__))
|
|
@@ -43,6 +50,18 @@ module ReactOnRails
|
|
|
43
50
|
default: false,
|
|
44
51
|
desc: "Skip warnings. Default: false"
|
|
45
52
|
|
|
53
|
+
# --pro
|
|
54
|
+
class_option :pro,
|
|
55
|
+
type: :boolean,
|
|
56
|
+
default: false,
|
|
57
|
+
desc: "Install React on Rails Pro with Node Renderer. Default: false"
|
|
58
|
+
|
|
59
|
+
# --rsc
|
|
60
|
+
class_option :rsc,
|
|
61
|
+
type: :boolean,
|
|
62
|
+
default: false,
|
|
63
|
+
desc: "Install React Server Components support (includes Pro). Default: false"
|
|
64
|
+
|
|
46
65
|
# Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
|
|
47
66
|
|
|
48
67
|
# Main generator entry point
|
|
@@ -94,10 +113,6 @@ module ReactOnRails
|
|
|
94
113
|
|
|
95
114
|
private
|
|
96
115
|
|
|
97
|
-
def print_generator_messages
|
|
98
|
-
GeneratorMessages.messages.each { |message| puts message }
|
|
99
|
-
end
|
|
100
|
-
|
|
101
116
|
def invoke_generators
|
|
102
117
|
ensure_shakapacker_installed
|
|
103
118
|
if options.typescript?
|
|
@@ -106,13 +121,29 @@ module ReactOnRails
|
|
|
106
121
|
create_typescript_config
|
|
107
122
|
end
|
|
108
123
|
invoke "react_on_rails:base", [],
|
|
109
|
-
{ typescript: options.typescript?, redux: options.redux?, rspack: options.rspack
|
|
124
|
+
{ typescript: options.typescript?, redux: options.redux?, rspack: options.rspack?,
|
|
125
|
+
pro: options.pro?, rsc: options.rsc? }
|
|
126
|
+
|
|
127
|
+
# Component generator logic:
|
|
128
|
+
# - --rsc without --redux: Skip HelloWorld, HelloServer will be generated in setup_rsc
|
|
129
|
+
# - --rsc with --redux: Generate HelloWorldApp (user explicitly wants Redux) + HelloServer
|
|
130
|
+
# - Without --rsc: Normal behavior (HelloWorld or HelloWorldApp based on --redux)
|
|
110
131
|
if options.redux?
|
|
111
132
|
invoke "react_on_rails:react_with_redux", [], { typescript: options.typescript? }
|
|
112
|
-
|
|
133
|
+
elsif !use_rsc?
|
|
134
|
+
# Only generate HelloWorld if RSC is not enabled
|
|
135
|
+
# For RSC, HelloServer replaces HelloWorld as the example component
|
|
113
136
|
invoke "react_on_rails:react_no_redux", [], { typescript: options.typescript? }
|
|
114
137
|
end
|
|
138
|
+
|
|
115
139
|
setup_react_dependencies
|
|
140
|
+
|
|
141
|
+
# Invoke standalone Pro/RSC generators when flags are used
|
|
142
|
+
# Pass invoked_by_install: true so they skip message printing (we handle it)
|
|
143
|
+
invoke "react_on_rails:pro", [], { invoked_by_install: true } if use_pro?
|
|
144
|
+
return unless use_rsc?
|
|
145
|
+
|
|
146
|
+
invoke "react_on_rails:rsc", [], { typescript: options.typescript?, invoked_by_install: true }
|
|
116
147
|
end
|
|
117
148
|
|
|
118
149
|
def setup_react_dependencies
|
|
@@ -123,7 +154,8 @@ module ReactOnRails
|
|
|
123
154
|
# js(.coffee) are not checked by this method, but instead produce warning messages
|
|
124
155
|
# and allow the build to continue
|
|
125
156
|
def installation_prerequisites_met?
|
|
126
|
-
!(missing_node? || missing_package_manager? ||
|
|
157
|
+
!(missing_node? || missing_package_manager? || missing_pro_gem? ||
|
|
158
|
+
ReactOnRails::GitUtils.uncommitted_changes?(GeneratorMessages))
|
|
127
159
|
end
|
|
128
160
|
|
|
129
161
|
def missing_node?
|
|
@@ -193,6 +225,11 @@ module ReactOnRails
|
|
|
193
225
|
template_bin_path = "#{__dir__}/templates/base/base/bin"
|
|
194
226
|
directory template_bin_path, "bin"
|
|
195
227
|
|
|
228
|
+
# For --rsc without --redux, hello_world doesn't exist — update DEFAULT_ROUTE
|
|
229
|
+
if use_rsc? && !options.redux?
|
|
230
|
+
gsub_file "bin/dev", 'DEFAULT_ROUTE = "hello_world"', 'DEFAULT_ROUTE = "hello_server"'
|
|
231
|
+
end
|
|
232
|
+
|
|
196
233
|
# Make these and only these files executable
|
|
197
234
|
files_to_copy = []
|
|
198
235
|
Dir.chdir(template_bin_path) do
|
|
@@ -204,9 +241,15 @@ module ReactOnRails
|
|
|
204
241
|
end
|
|
205
242
|
|
|
206
243
|
def add_post_install_message
|
|
207
|
-
# Determine what route will be created by the generator
|
|
208
|
-
|
|
209
|
-
|
|
244
|
+
# Determine what route and component will be created by the generator
|
|
245
|
+
if use_rsc? && !options.redux?
|
|
246
|
+
# RSC without Redux: HelloServer replaces HelloWorld
|
|
247
|
+
route = "hello_server"
|
|
248
|
+
component_name = "HelloServer"
|
|
249
|
+
else
|
|
250
|
+
route = "hello_world"
|
|
251
|
+
component_name = options.redux? ? "HelloWorldApp" : "HelloWorld"
|
|
252
|
+
end
|
|
210
253
|
|
|
211
254
|
GeneratorMessages.add_info(GeneratorMessages.helpful_message_after_installation(
|
|
212
255
|
component_name: component_name,
|
|
@@ -219,10 +262,7 @@ module ReactOnRails
|
|
|
219
262
|
end
|
|
220
263
|
|
|
221
264
|
def shakapacker_in_lockfile?(gem_name)
|
|
222
|
-
|
|
223
|
-
# See: https://github.com/shakacode/react_on_rails/issues/2287
|
|
224
|
-
File.file?("Gemfile.lock") &&
|
|
225
|
-
File.foreach("Gemfile.lock").any? { |l| l.match?(/^\s{4}#{Regexp.escape(gem_name)}\s\(/) }
|
|
265
|
+
gem_in_lockfile?(gem_name)
|
|
226
266
|
end
|
|
227
267
|
|
|
228
268
|
def shakapacker_in_bundler_specs?(gem_name)
|
|
@@ -431,11 +471,7 @@ module ReactOnRails
|
|
|
431
471
|
File.write("tsconfig.json", JSON.pretty_generate(tsconfig_content))
|
|
432
472
|
puts Rainbow("✅ Created tsconfig.json").green
|
|
433
473
|
end
|
|
434
|
-
|
|
435
|
-
# Removed: Shakapacker auto-installation logic (now explicit dependency)
|
|
436
|
-
|
|
437
|
-
# Removed: Shakapacker 8+ is now required as explicit dependency
|
|
438
|
-
# rubocop:enable Metrics/ClassLength
|
|
439
474
|
end
|
|
475
|
+
# rubocop:enable Metrics/ClassLength
|
|
440
476
|
end
|
|
441
477
|
end
|
|
@@ -106,6 +106,19 @@ module ReactOnRails
|
|
|
106
106
|
swc-loader
|
|
107
107
|
].freeze
|
|
108
108
|
|
|
109
|
+
# React on Rails Pro dependencies (only installed when --pro or --rsc flag is used)
|
|
110
|
+
# These packages are published publicly on npmjs.org but require a license for production use
|
|
111
|
+
PRO_DEPENDENCIES = %w[
|
|
112
|
+
react-on-rails-pro
|
|
113
|
+
react-on-rails-pro-node-renderer
|
|
114
|
+
].freeze
|
|
115
|
+
|
|
116
|
+
# React Server Components dependencies (only installed when --rsc flag is used)
|
|
117
|
+
# Requires React 19.0.x - see https://react.dev/reference/rsc/server-components
|
|
118
|
+
RSC_DEPENDENCIES = %w[
|
|
119
|
+
react-on-rails-rsc
|
|
120
|
+
].freeze
|
|
121
|
+
|
|
109
122
|
private
|
|
110
123
|
|
|
111
124
|
def setup_js_dependencies
|
|
@@ -120,17 +133,23 @@ module ReactOnRails
|
|
|
120
133
|
end
|
|
121
134
|
|
|
122
135
|
def add_js_dependencies
|
|
123
|
-
|
|
136
|
+
using_pro = respond_to?(:use_pro?) && use_pro?
|
|
137
|
+
using_rsc = respond_to?(:use_rsc?) && use_rsc?
|
|
138
|
+
# Pro package includes react-on-rails, so skip base package when using Pro
|
|
139
|
+
add_react_on_rails_package unless using_pro
|
|
124
140
|
add_react_dependencies
|
|
125
141
|
add_css_dependencies
|
|
126
|
-
|
|
127
|
-
add_rspack_dependencies if respond_to?(:options) && options&.rspack?
|
|
128
|
-
# SWC dependencies are only added when SWC is the configured transpiler
|
|
142
|
+
add_rspack_dependencies if using_rspack?
|
|
129
143
|
add_swc_dependencies if using_swc?
|
|
130
|
-
|
|
144
|
+
add_pro_dependencies if using_pro
|
|
145
|
+
add_rsc_dependencies if using_rsc
|
|
131
146
|
add_dev_dependencies
|
|
132
147
|
end
|
|
133
148
|
|
|
149
|
+
def using_rspack?
|
|
150
|
+
respond_to?(:options) && options&.rspack?
|
|
151
|
+
end
|
|
152
|
+
|
|
134
153
|
def add_react_on_rails_package
|
|
135
154
|
# Use exact version match between gem and npm package for all versions including pre-releases
|
|
136
155
|
# Ruby gem versions use dots (16.2.0.beta.10) but npm requires hyphens (16.2.0-beta.10)
|
|
@@ -186,20 +205,29 @@ module ReactOnRails
|
|
|
186
205
|
|
|
187
206
|
def add_react_dependencies
|
|
188
207
|
puts "Installing React dependencies..."
|
|
189
|
-
|
|
208
|
+
|
|
209
|
+
# RSC requires React 19.0.x specifically (not 19.1.x or later)
|
|
210
|
+
# Pin to ~19.0.4 to allow patch updates while staying within 19.0.x
|
|
211
|
+
react_deps = if respond_to?(:use_rsc?) && use_rsc?
|
|
212
|
+
%w[react@~19.0.4 react-dom@~19.0.4 prop-types]
|
|
213
|
+
else
|
|
214
|
+
REACT_DEPENDENCIES
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
return if add_packages(react_deps)
|
|
190
218
|
|
|
191
219
|
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
192
220
|
⚠️ Failed to add React dependencies.
|
|
193
221
|
|
|
194
222
|
You can install them manually by running:
|
|
195
|
-
npm install #{
|
|
223
|
+
npm install #{react_deps.join(' ')}
|
|
196
224
|
MSG
|
|
197
225
|
rescue StandardError => e
|
|
198
226
|
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
199
227
|
⚠️ Error adding React dependencies: #{e.message}
|
|
200
228
|
|
|
201
229
|
You can install them manually by running:
|
|
202
|
-
npm install #{
|
|
230
|
+
npm install #{react_deps.join(' ')}
|
|
203
231
|
MSG
|
|
204
232
|
end
|
|
205
233
|
|
|
@@ -280,6 +308,85 @@ module ReactOnRails
|
|
|
280
308
|
MSG
|
|
281
309
|
end
|
|
282
310
|
|
|
311
|
+
def add_pro_dependencies
|
|
312
|
+
puts "Installing React on Rails Pro dependencies..."
|
|
313
|
+
|
|
314
|
+
# When upgrading from base React on Rails to Pro, remove the base package first
|
|
315
|
+
# Pro package includes all base functionality, so having both causes validation errors
|
|
316
|
+
remove_base_package_if_present
|
|
317
|
+
|
|
318
|
+
# Pin to exact version matching the gem (converts Ruby format to npm format)
|
|
319
|
+
# Falls back to latest if version can't be determined
|
|
320
|
+
pro_packages = pro_packages_with_version
|
|
321
|
+
results = pro_packages.map { |pkg| add_package(pkg) }
|
|
322
|
+
return if results.all?
|
|
323
|
+
|
|
324
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
325
|
+
⚠️ Failed to add React on Rails Pro dependencies.
|
|
326
|
+
|
|
327
|
+
You can install them manually by running:
|
|
328
|
+
npm install #{pro_packages.join(' ')}
|
|
329
|
+
MSG
|
|
330
|
+
rescue StandardError => e
|
|
331
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
332
|
+
⚠️ Error adding React on Rails Pro dependencies: #{e.message}
|
|
333
|
+
|
|
334
|
+
You can install them manually by running:
|
|
335
|
+
npm install #{PRO_DEPENDENCIES.join(' ')}
|
|
336
|
+
MSG
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
# Returns Pro package names with version suffix matching the gem version.
|
|
340
|
+
# Uses VersionSyntaxConverter to handle Ruby->npm format conversion.
|
|
341
|
+
# Falls back to unversioned package names if version can't be determined.
|
|
342
|
+
def pro_packages_with_version
|
|
343
|
+
return PRO_DEPENDENCIES unless defined?(ReactOnRailsPro::VERSION)
|
|
344
|
+
|
|
345
|
+
npm_version = ReactOnRails::VersionSyntaxConverter.new.rubygem_to_npm(ReactOnRailsPro::VERSION)
|
|
346
|
+
PRO_DEPENDENCIES.map { |pkg| "#{pkg}@#{npm_version}" }
|
|
347
|
+
rescue StandardError
|
|
348
|
+
puts "WARNING: Could not determine Pro package version. Installing latest."
|
|
349
|
+
PRO_DEPENDENCIES
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def add_rsc_dependencies
|
|
353
|
+
puts "Installing React Server Components dependencies..."
|
|
354
|
+
return if add_packages(RSC_DEPENDENCIES)
|
|
355
|
+
|
|
356
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
357
|
+
⚠️ Failed to add React Server Components dependencies.
|
|
358
|
+
|
|
359
|
+
You can install them manually by running:
|
|
360
|
+
npm install #{RSC_DEPENDENCIES.join(' ')}
|
|
361
|
+
MSG
|
|
362
|
+
rescue StandardError => e
|
|
363
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
364
|
+
⚠️ Error adding React Server Components dependencies: #{e.message}
|
|
365
|
+
|
|
366
|
+
You can install them manually by running:
|
|
367
|
+
npm install #{RSC_DEPENDENCIES.join(' ')}
|
|
368
|
+
MSG
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def remove_base_package_if_present
|
|
372
|
+
pj = package_json
|
|
373
|
+
return unless pj
|
|
374
|
+
|
|
375
|
+
dependencies = pj.fetch("dependencies", {})
|
|
376
|
+
return unless dependencies.key?("react-on-rails")
|
|
377
|
+
|
|
378
|
+
puts "Removing base 'react-on-rails' package (Pro package includes all base functionality)..."
|
|
379
|
+
pj.manager.remove(["react-on-rails"])
|
|
380
|
+
puts "✅ Removed 'react-on-rails' package"
|
|
381
|
+
rescue StandardError => e
|
|
382
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
383
|
+
⚠️ Could not remove base 'react-on-rails' package: #{e.message}
|
|
384
|
+
|
|
385
|
+
Please remove it manually:
|
|
386
|
+
npm uninstall react-on-rails
|
|
387
|
+
MSG
|
|
388
|
+
end
|
|
389
|
+
|
|
283
390
|
def add_dev_dependencies
|
|
284
391
|
puts "Installing development dependencies..."
|
|
285
392
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Add React on Rails Pro to an existing React on Rails application.
|
|
3
|
+
|
|
4
|
+
Example:
|
|
5
|
+
rails generate react_on_rails:pro
|
|
6
|
+
|
|
7
|
+
This will add:
|
|
8
|
+
- Pro initializer (config/initializers/react_on_rails_pro.rb)
|
|
9
|
+
- Node renderer (client/node-renderer.js)
|
|
10
|
+
- Node renderer process to Procfile.dev
|
|
11
|
+
|
|
12
|
+
Modifies:
|
|
13
|
+
- config/webpack/serverWebpackConfig.js (enables Pro settings: libraryTarget,
|
|
14
|
+
target, extractLoader, Babel SSR caller, object exports)
|
|
15
|
+
- config/webpack/ServerClientOrBoth.js (switches to destructured import)
|
|
16
|
+
- package.json (replaces react-on-rails with react-on-rails-pro and
|
|
17
|
+
react-on-rails-pro-node-renderer)
|
|
18
|
+
|
|
19
|
+
Prerequisites:
|
|
20
|
+
- React on Rails must be installed (rails g react_on_rails:install)
|
|
21
|
+
- react_on_rails_pro gem must be in your Gemfile
|