react_on_rails 16.4.0.rc.10 → 16.5.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/Gemfile.lock +1 -1
- data/lib/generators/react_on_rails/base_generator.rb +62 -5
- data/lib/generators/react_on_rails/generator_messages.rb +20 -18
- data/lib/generators/react_on_rails/install_generator.rb +128 -12
- data/lib/generators/react_on_rails/pro_generator.rb +1 -1
- data/lib/generators/react_on_rails/pro_setup.rb +3 -2
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +2 -1
- data/lib/generators/react_on_rails/rsc_generator.rb +1 -1
- data/lib/generators/react_on_rails/templates/base/base/bin/dev +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/rspack.config.js.tt +15 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/rspack.config.ts.tt +15 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/webpack.config.ts.tt +15 -0
- data/lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js +8 -4
- data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +1 -1
- data/lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb.tt +1 -1
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx +1 -1
- data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx +1 -1
- data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb +1 -1
- data/lib/generators/react_on_rails/templates/rsc/base/config/webpack/rscWebpackConfig.js.tt +1 -1
- data/lib/react_on_rails/config_path_resolver.rb +50 -0
- data/lib/react_on_rails/configuration.rb +1 -1
- data/lib/react_on_rails/dev/process_manager.rb +16 -1
- data/lib/react_on_rails/dev/server_manager.rb +2 -2
- data/lib/react_on_rails/doctor.rb +389 -25
- data/lib/react_on_rails/git_utils.rb +95 -23
- data/lib/react_on_rails/packer_utils.rb +1 -1
- data/lib/react_on_rails/packs_generator.rb +3 -3
- data/lib/react_on_rails/react_component/render_options.rb +48 -0
- data/lib/react_on_rails/server_rendering_js_code.rb +1 -1
- data/lib/react_on_rails/system_checker.rb +133 -37
- data/lib/react_on_rails/utils.rb +1 -1
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_synchronizer.rb +250 -0
- data/lib/tasks/generate_packs.rake +3 -3
- data/lib/tasks/sync_versions.rake +23 -0
- data/rakelib/examples_config.yml +1 -1
- data/rakelib/update_changelog.rake +5 -5
- data/react_on_rails.gemspec +1 -1
- data/sig/react_on_rails/dev/process_manager.rbs +2 -0
- metadata +9 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 14bbaccde12f9bb4f998ade94c02d95d27e1df386a9dfaf887fefb0f073070e0
|
|
4
|
+
data.tar.gz: 952bf7eb1d5694d86b74dd654ab2cb10fd7490207d6be3c66ac6ea4866802eee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3bdbf4f3343cf568ea879a13d0902d650379016004832c44affd1498ac8c0be881de9e7d4bb42ecd883f095f5697518dfcc773d7d79b61c4250026457100d9cd
|
|
7
|
+
data.tar.gz: 920530b24dbe7d23af418d53ad564e9f75bbf0f21fcc03851b89de03994d6a1e910fdaeb962da9eb4f66eed0cc37f28a9048fd2dcf3d208c9422843a7208fe4c
|
data/Gemfile.lock
CHANGED
|
@@ -267,6 +267,7 @@ module ReactOnRails
|
|
|
267
267
|
|
|
268
268
|
def copy_webpack_main_config(base_path, config)
|
|
269
269
|
webpack_config_path = bundler_main_config_path
|
|
270
|
+
template_path = bundler_main_config_template_path(base_path, webpack_config_path)
|
|
270
271
|
|
|
271
272
|
if File.exist?(webpack_config_path)
|
|
272
273
|
existing_content = File.read(webpack_config_path)
|
|
@@ -279,7 +280,7 @@ module ReactOnRails
|
|
|
279
280
|
say_status :replace,
|
|
280
281
|
"#{webpack_config_path} (auto-upgrading from standard Shakapacker to React on Rails config)",
|
|
281
282
|
:green
|
|
282
|
-
template(
|
|
283
|
+
template(template_path, webpack_config_path, config)
|
|
283
284
|
elsif react_on_rails_config?(existing_content)
|
|
284
285
|
say_status :identical, "#{webpack_config_path} (already React on Rails compatible)", :blue
|
|
285
286
|
# Skip - don't need to do anything
|
|
@@ -288,7 +289,7 @@ module ReactOnRails
|
|
|
288
289
|
end
|
|
289
290
|
else
|
|
290
291
|
# File doesn't exist, create it
|
|
291
|
-
template(
|
|
292
|
+
template(template_path, webpack_config_path, config)
|
|
292
293
|
end
|
|
293
294
|
end
|
|
294
295
|
|
|
@@ -309,7 +310,7 @@ module ReactOnRails
|
|
|
309
310
|
say_status :create, "#{backup_path} (backup of your custom config)", :green
|
|
310
311
|
end
|
|
311
312
|
|
|
312
|
-
template(
|
|
313
|
+
template(bundler_main_config_template_path(base_path, webpack_config_path), webpack_config_path, config)
|
|
313
314
|
else
|
|
314
315
|
say_status :skip, webpack_config_path, :yellow
|
|
315
316
|
say_status :warning,
|
|
@@ -320,7 +321,13 @@ module ReactOnRails
|
|
|
320
321
|
|
|
321
322
|
def bundler_main_config_path
|
|
322
323
|
if using_rspack?
|
|
323
|
-
"config/rspack/rspack.config.
|
|
324
|
+
if File.exist?("config/rspack/rspack.config.ts")
|
|
325
|
+
"config/rspack/rspack.config.ts"
|
|
326
|
+
else
|
|
327
|
+
"config/rspack/rspack.config.js"
|
|
328
|
+
end
|
|
329
|
+
elsif File.exist?("config/webpack/webpack.config.ts")
|
|
330
|
+
"config/webpack/webpack.config.ts"
|
|
324
331
|
else
|
|
325
332
|
"config/webpack/webpack.config.js"
|
|
326
333
|
end
|
|
@@ -584,10 +591,26 @@ module ReactOnRails
|
|
|
584
591
|
|
|
585
592
|
# Normalize whitespace while preserving comments by default so added comments
|
|
586
593
|
# count as potential customizations and keep cleanup conservative.
|
|
587
|
-
normalized_content.gsub(/\s+/, " ")
|
|
594
|
+
normalized_content.gsub(/\s+/, " ")
|
|
595
|
+
.tr('"', "'") # Normalize quote style for import/require statements
|
|
596
|
+
.strip
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def bundler_main_config_template_path(base_path, config_path)
|
|
600
|
+
template_ext = config_path.end_with?(".ts") ? "ts.tt" : "js.tt"
|
|
601
|
+
template_base = if config_path.include?("/rspack/") || File.basename(config_path).start_with?("rspack.config")
|
|
602
|
+
"rspack.config"
|
|
603
|
+
else
|
|
604
|
+
"webpack.config"
|
|
605
|
+
end
|
|
606
|
+
"#{base_path}/config/webpack/#{template_base}.#{template_ext}"
|
|
588
607
|
end
|
|
589
608
|
|
|
590
609
|
def shakapacker_default_configs
|
|
610
|
+
shakapacker_cjs_default_configs + shakapacker_esm_default_configs
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
def shakapacker_cjs_default_configs
|
|
591
614
|
configs = []
|
|
592
615
|
|
|
593
616
|
# Shakapacker v7+ (generateWebpackConfig function)
|
|
@@ -640,6 +663,40 @@ module ReactOnRails
|
|
|
640
663
|
configs
|
|
641
664
|
end
|
|
642
665
|
|
|
666
|
+
def shakapacker_esm_default_configs
|
|
667
|
+
configs = []
|
|
668
|
+
|
|
669
|
+
# Shakapacker v9.4+ TypeScript webpack configs (ESM syntax)
|
|
670
|
+
configs << <<~CONFIG
|
|
671
|
+
import { generateWebpackConfig } from 'shakapacker'
|
|
672
|
+
import type { Configuration } from 'webpack'
|
|
673
|
+
const webpackConfig: Configuration = generateWebpackConfig()
|
|
674
|
+
export default webpackConfig
|
|
675
|
+
CONFIG
|
|
676
|
+
|
|
677
|
+
configs << <<~CONFIG
|
|
678
|
+
import { generateWebpackConfig } from 'shakapacker'
|
|
679
|
+
const webpackConfig = generateWebpackConfig()
|
|
680
|
+
export default webpackConfig
|
|
681
|
+
CONFIG
|
|
682
|
+
|
|
683
|
+
# Shakapacker v9.4+ TypeScript rspack configs (ESM syntax)
|
|
684
|
+
configs << <<~CONFIG
|
|
685
|
+
import { generateRspackConfig } from 'shakapacker/rspack'
|
|
686
|
+
import type { RspackOptions } from '@rspack/core'
|
|
687
|
+
const rspackConfig: RspackOptions = generateRspackConfig()
|
|
688
|
+
export default rspackConfig
|
|
689
|
+
CONFIG
|
|
690
|
+
|
|
691
|
+
configs << <<~CONFIG
|
|
692
|
+
import { generateRspackConfig } from 'shakapacker/rspack'
|
|
693
|
+
const rspackConfig = generateRspackConfig()
|
|
694
|
+
export default rspackConfig
|
|
695
|
+
CONFIG
|
|
696
|
+
|
|
697
|
+
configs
|
|
698
|
+
end
|
|
699
|
+
|
|
643
700
|
def react_on_rails_config?(content)
|
|
644
701
|
# Check if it already has React on Rails environment-specific loading
|
|
645
702
|
content.include?("envSpecificConfig") || content.include?("env.nodeEnv")
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
require "rainbow"
|
|
4
4
|
|
|
5
5
|
module GeneratorMessages
|
|
6
|
+
PRO_UPGRADE_HINT = "\n\n 💎 For RSC, streaming SSR, and 10-100x faster SSR, try React on Rails Pro:" \
|
|
7
|
+
"\n #{Rainbow('https://reactonrails.com/docs/pro/upgrading-to-pro/').cyan.underline}".freeze
|
|
8
|
+
|
|
6
9
|
class << self
|
|
7
10
|
def output
|
|
8
11
|
@output ||= []
|
|
@@ -40,14 +43,16 @@ module GeneratorMessages
|
|
|
40
43
|
@output = []
|
|
41
44
|
end
|
|
42
45
|
|
|
43
|
-
def helpful_message_after_installation(component_name: "HelloWorld", route: "hello_world",
|
|
44
|
-
shakapacker_just_installed: false)
|
|
46
|
+
def helpful_message_after_installation(component_name: "HelloWorld", route: "hello_world", pro: false,
|
|
47
|
+
rsc: false, shakapacker_just_installed: false)
|
|
45
48
|
process_manager_section = build_process_manager_section
|
|
46
49
|
testing_section = build_testing_section
|
|
47
50
|
package_manager = detect_package_manager
|
|
48
51
|
shakapacker_status = build_shakapacker_status_section(shakapacker_just_installed: shakapacker_just_installed)
|
|
49
52
|
render_example = build_render_example(component_name: component_name, route: route, rsc: rsc)
|
|
50
53
|
render_label = build_render_label(route: route, rsc: rsc)
|
|
54
|
+
# rsc guard is defensive; callers via install_generator already pass pro: true when rsc is set
|
|
55
|
+
pro_hint = pro || rsc ? "" : PRO_UPGRADE_HINT
|
|
51
56
|
|
|
52
57
|
<<~MSG
|
|
53
58
|
|
|
@@ -61,13 +66,16 @@ module GeneratorMessages
|
|
|
61
66
|
1. Install dependencies:
|
|
62
67
|
#{Rainbow("bundle && #{package_manager} install").cyan}
|
|
63
68
|
|
|
64
|
-
2.
|
|
69
|
+
2. Prepare database:
|
|
70
|
+
#{Rainbow('bin/rails db:prepare').cyan}
|
|
71
|
+
|
|
72
|
+
3. Start the app:
|
|
65
73
|
./bin/dev # HMR (Hot Module Replacement) mode
|
|
66
74
|
./bin/dev static # Static bundles (no HMR, faster initial load)
|
|
67
75
|
./bin/dev prod # Production-like mode for testing
|
|
68
76
|
./bin/dev help # See all available options
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
4. Visit: #{Rainbow(route ? "http://localhost:3000/#{route}" : 'http://localhost:3000').cyan.underline}
|
|
71
79
|
✨ KEY FEATURES:
|
|
72
80
|
─────────────────────────────────────────────────────────────────────────
|
|
73
81
|
• Auto-registration enabled - Your layout only needs:
|
|
@@ -79,16 +87,19 @@ module GeneratorMessages
|
|
|
79
87
|
|
|
80
88
|
📚 LEARN MORE:
|
|
81
89
|
─────────────────────────────────────────────────────────────────────────
|
|
82
|
-
• Documentation: #{Rainbow('https://
|
|
90
|
+
• Documentation: #{Rainbow('https://reactonrails.com/docs/').cyan.underline}
|
|
83
91
|
• Webpack customization: #{Rainbow('https://github.com/shakacode/shakapacker#webpack-configuration').cyan.underline}
|
|
84
92
|
|
|
85
|
-
💡 TIP: Run 'bin/dev help' for development server options and troubleshooting#{testing_section}
|
|
93
|
+
💡 TIP: Run 'bin/dev help' for development server options and troubleshooting#{testing_section}#{pro_hint}
|
|
86
94
|
MSG
|
|
87
95
|
end
|
|
88
96
|
|
|
89
97
|
# Uses relative lockfile paths resolved against Dir.pwd, so callers must invoke
|
|
90
98
|
# this while the current working directory is the target Rails app root.
|
|
91
99
|
def detect_package_manager
|
|
100
|
+
env_package_manager = ENV.fetch("REACT_ON_RAILS_PACKAGE_MANAGER", nil)&.strip&.downcase
|
|
101
|
+
return env_package_manager if %w[npm pnpm yarn bun].include?(env_package_manager)
|
|
102
|
+
|
|
92
103
|
# Check for lock files to determine package manager
|
|
93
104
|
return "yarn" if File.exist?("yarn.lock")
|
|
94
105
|
return "pnpm" if File.exist?("pnpm-lock.yaml")
|
|
@@ -133,10 +144,7 @@ module GeneratorMessages
|
|
|
133
144
|
end
|
|
134
145
|
|
|
135
146
|
def build_testing_section
|
|
136
|
-
|
|
137
|
-
has_spec_files = File.exist?("spec/rails_helper.rb") || File.exist?("spec/spec_helper.rb")
|
|
138
|
-
|
|
139
|
-
return "" if has_spec_files
|
|
147
|
+
return "" if File.exist?("spec/rails_helper.rb") || File.exist?("spec/spec_helper.rb")
|
|
140
148
|
|
|
141
149
|
<<~TESTING
|
|
142
150
|
|
|
@@ -160,7 +168,6 @@ module GeneratorMessages
|
|
|
160
168
|
|
|
161
169
|
def build_shakapacker_status_section(shakapacker_just_installed: false)
|
|
162
170
|
version_warning = check_shakapacker_version_warning
|
|
163
|
-
|
|
164
171
|
if shakapacker_just_installed
|
|
165
172
|
base = <<~SHAKAPACKER
|
|
166
173
|
|
|
@@ -179,18 +186,13 @@ module GeneratorMessages
|
|
|
179
186
|
end
|
|
180
187
|
|
|
181
188
|
def check_shakapacker_version_warning
|
|
182
|
-
# Try to detect Shakapacker version from Gemfile.lock
|
|
183
189
|
return "" unless File.exist?("Gemfile.lock")
|
|
184
190
|
|
|
185
|
-
|
|
186
|
-
shakapacker_match = gemfile_lock_content.match(/shakapacker \((\d+\.\d+\.\d+)\)/)
|
|
187
|
-
|
|
191
|
+
shakapacker_match = File.read("Gemfile.lock").match(/shakapacker \((\d+\.\d+\.\d+)\)/)
|
|
188
192
|
return "" unless shakapacker_match
|
|
189
193
|
|
|
190
194
|
version = shakapacker_match[1]
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
if major_version < 8
|
|
195
|
+
if version.split(".").first.to_i < 8
|
|
194
196
|
<<~WARNING
|
|
195
197
|
|
|
196
198
|
⚠️ #{Rainbow('IMPORTANT: Upgrade Recommended').yellow.bold}
|
|
@@ -79,6 +79,49 @@ module ReactOnRails
|
|
|
79
79
|
# Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
|
|
80
80
|
|
|
81
81
|
SHAKAPACKER_YML_PATH = "config/shakapacker.yml"
|
|
82
|
+
# Matches the stock `bin/dev` written by Rails 8.x. Rails 7.1 commonly
|
|
83
|
+
# generated a foreman-based shell script instead, which stock_rails_bin_dev?
|
|
84
|
+
# also recognizes so the React on Rails template can replace either variant.
|
|
85
|
+
STOCK_RAILS_BIN_DEV = <<~RUBY
|
|
86
|
+
#!/usr/bin/env ruby
|
|
87
|
+
exec "./bin/rails", "server", *ARGV
|
|
88
|
+
RUBY
|
|
89
|
+
# Recognize only known legacy Rails foreman templates. Any other variant is
|
|
90
|
+
# treated as customized so install does not overwrite app-specific logic.
|
|
91
|
+
LEGACY_FOREMAN_BIN_DEV_TEMPLATES = [
|
|
92
|
+
<<~BASH,
|
|
93
|
+
#!/usr/bin/env bash
|
|
94
|
+
if ! gem list foreman -i --silent; then
|
|
95
|
+
gem install foreman
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
exec foreman start -f Procfile.dev "$@"
|
|
99
|
+
BASH
|
|
100
|
+
<<~SH,
|
|
101
|
+
#!/usr/bin/env sh
|
|
102
|
+
if ! gem list foreman -i --silent; then
|
|
103
|
+
gem install foreman
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
exec foreman start -f Procfile.dev "$@"
|
|
107
|
+
SH
|
|
108
|
+
<<~BASH,
|
|
109
|
+
#!/usr/bin/env bash
|
|
110
|
+
if ! gem list foreman -i --silent; then
|
|
111
|
+
gem install foreman
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
exec foreman start -f Procfile.dev $@
|
|
115
|
+
BASH
|
|
116
|
+
<<~SH
|
|
117
|
+
#!/usr/bin/env sh
|
|
118
|
+
if ! gem list foreman -i --silent; then
|
|
119
|
+
gem install foreman
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
exec foreman start -f Procfile.dev $@
|
|
123
|
+
SH
|
|
124
|
+
].map { |template| template.gsub("\r\n", "\n").strip }.freeze
|
|
82
125
|
|
|
83
126
|
# Main generator entry point
|
|
84
127
|
#
|
|
@@ -188,10 +231,28 @@ module ReactOnRails
|
|
|
188
231
|
# js(.coffee) are not checked by this method, but instead produce warning messages
|
|
189
232
|
# and allow the build to continue
|
|
190
233
|
def installation_prerequisites_met?
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
|
|
194
|
-
|
|
234
|
+
# Non-blocking: warn about dirty worktree but don't prevent installation.
|
|
235
|
+
# A clean tree makes the generator diff easier to review, but blocking would
|
|
236
|
+
# be too strict for a generator that creates many new files.
|
|
237
|
+
has_worktree_issues = ReactOnRails::GitUtils.warn_if_uncommitted_changes(
|
|
238
|
+
GeneratorMessages, git_installed: cli_exists?("git")
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# missing_pro_gem? may auto-install the gem (mutating Gemfile), so only run
|
|
242
|
+
# it on a clean worktree. On a dirty tree, use the read-only pro_gem_installed?
|
|
243
|
+
# check to catch a missing gem without triggering auto-install.
|
|
244
|
+
if has_worktree_issues && use_pro? && !pro_gem_installed?
|
|
245
|
+
GeneratorMessages.add_error(<<~MSG.strip)
|
|
246
|
+
🚫 react_on_rails_pro gem is required for #{options[:rsc] ? '--rsc' : '--pro'} but is not installed.
|
|
247
|
+
Auto-install was skipped because the worktree has uncommitted changes.
|
|
248
|
+
Please add it manually:
|
|
249
|
+
gem 'react_on_rails_pro', '~> #{recommended_pro_gem_version}'
|
|
250
|
+
Then run: bundle install
|
|
251
|
+
MSG
|
|
252
|
+
return false
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
!(missing_node? || missing_package_manager? || (!has_worktree_issues && missing_pro_gem?))
|
|
195
256
|
end
|
|
196
257
|
|
|
197
258
|
def missing_node?
|
|
@@ -277,13 +338,23 @@ module ReactOnRails
|
|
|
277
338
|
end
|
|
278
339
|
|
|
279
340
|
def add_bin_scripts
|
|
341
|
+
replace_stock_rails_bin_dev!
|
|
342
|
+
|
|
280
343
|
# Copy bin scripts from templates
|
|
281
344
|
template_bin_path = "#{__dir__}/templates/base/base/bin"
|
|
282
|
-
|
|
345
|
+
directory_options = {}
|
|
346
|
+
directory_options[:exclude_pattern] = %r{/dev(?:\.tt)?\z} if preserve_existing_bin_dev?
|
|
347
|
+
directory template_bin_path, "bin", directory_options
|
|
283
348
|
|
|
284
349
|
# For --rsc without --redux, hello_world doesn't exist — update DEFAULT_ROUTE
|
|
285
350
|
if use_rsc? && !options.redux?
|
|
286
|
-
|
|
351
|
+
if preserve_existing_bin_dev?
|
|
352
|
+
say_status :warn,
|
|
353
|
+
'Custom bin/dev detected: update DEFAULT_ROUTE to "hello_server" manually for --rsc',
|
|
354
|
+
:yellow
|
|
355
|
+
else
|
|
356
|
+
gsub_file "bin/dev", 'DEFAULT_ROUTE = "hello_world"', 'DEFAULT_ROUTE = "hello_server"'
|
|
357
|
+
end
|
|
287
358
|
end
|
|
288
359
|
|
|
289
360
|
# `directory` and `gsub_file` above are Thor actions that already honor
|
|
@@ -294,13 +365,48 @@ module ReactOnRails
|
|
|
294
365
|
end
|
|
295
366
|
|
|
296
367
|
# Make these and only these files executable
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
368
|
+
files_to_become_executable = bin_scripts_to_chmod(template_bin_path)
|
|
369
|
+
File.chmod(0o755, *files_to_become_executable)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def replace_stock_rails_bin_dev!
|
|
373
|
+
@preserve_existing_bin_dev = false
|
|
374
|
+
|
|
375
|
+
unless stock_rails_bin_dev?
|
|
376
|
+
if File.exist?("bin/dev")
|
|
377
|
+
say_status :skip, "bin/dev exists but does not match a stock Rails template; keeping existing file", :yellow
|
|
378
|
+
@preserve_existing_bin_dev = true
|
|
379
|
+
end
|
|
380
|
+
return
|
|
300
381
|
end
|
|
301
|
-
files_to_become_executable = files_to_copy.map { |filename| "bin/#{filename}" }
|
|
302
382
|
|
|
303
|
-
|
|
383
|
+
if options[:pretend] || options[:skip]
|
|
384
|
+
say_status :skip, "Detected stock Rails bin/dev; leaving existing file in place for --pretend/--skip", :yellow
|
|
385
|
+
@preserve_existing_bin_dev = true
|
|
386
|
+
return
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
say_status :replace, "Detected stock Rails bin/dev; installing React on Rails bin/dev", :yellow
|
|
390
|
+
remove_file "bin/dev", verbose: false
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def preserve_existing_bin_dev?
|
|
394
|
+
# Set by replace_stock_rails_bin_dev! which always runs first via add_bin_scripts.
|
|
395
|
+
# Explicitly coerce to boolean so nil (before initialization) is treated as false.
|
|
396
|
+
!!@preserve_existing_bin_dev
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def bin_scripts_to_chmod(template_bin_path)
|
|
400
|
+
files = Dir.children(template_bin_path)
|
|
401
|
+
files.reject! { |f| f == "dev" } if preserve_existing_bin_dev?
|
|
402
|
+
files.map { |filename| "bin/#{filename}" }
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def stock_rails_bin_dev?
|
|
406
|
+
return false unless File.exist?("bin/dev")
|
|
407
|
+
|
|
408
|
+
content = normalize_bin_dev_content(File.read("bin/dev"))
|
|
409
|
+
content == normalize_bin_dev_content(STOCK_RAILS_BIN_DEV) || legacy_foreman_bin_dev?(content)
|
|
304
410
|
end
|
|
305
411
|
|
|
306
412
|
def add_post_install_message
|
|
@@ -322,6 +428,7 @@ module ReactOnRails
|
|
|
322
428
|
GeneratorMessages.add_info(GeneratorMessages.helpful_message_after_installation(
|
|
323
429
|
component_name: component_name,
|
|
324
430
|
route: route,
|
|
431
|
+
pro: use_pro?,
|
|
325
432
|
rsc: use_rsc?,
|
|
326
433
|
shakapacker_just_installed: shakapacker_just_installed?
|
|
327
434
|
))
|
|
@@ -411,7 +518,16 @@ module ReactOnRails
|
|
|
411
518
|
end
|
|
412
519
|
|
|
413
520
|
def cli_exists?(command)
|
|
414
|
-
|
|
521
|
+
which_command = ReactOnRails::Utils.running_on_windows? ? "where" : "which"
|
|
522
|
+
system(which_command, command, out: File::NULL, err: File::NULL)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
def normalize_bin_dev_content(content)
|
|
526
|
+
content.gsub("\r\n", "\n").strip
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def legacy_foreman_bin_dev?(content)
|
|
530
|
+
LEGACY_FOREMAN_BIN_DEV_TEMPLATES.include?(content)
|
|
415
531
|
end
|
|
416
532
|
|
|
417
533
|
def shakapacker_binaries_exist?
|
|
@@ -78,8 +78,9 @@ module ReactOnRails
|
|
|
78
78
|
|
|
79
79
|
Then run: bundle install
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
No license needed for evaluation or non-production use.
|
|
82
|
+
Free or low-cost production licenses available for startups and small companies.
|
|
83
|
+
Get started: https://pro.reactonrails.com/
|
|
83
84
|
MSG
|
|
84
85
|
true
|
|
85
86
|
end
|
|
@@ -99,7 +99,8 @@ module ReactOnRails
|
|
|
99
99
|
|
|
100
100
|
# Append Redux-specific post-install instructions
|
|
101
101
|
GeneratorMessages.add_info(
|
|
102
|
-
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world"
|
|
102
|
+
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world",
|
|
103
|
+
pro: Gem.loaded_specs.key?("react_on_rails_pro"))
|
|
103
104
|
)
|
|
104
105
|
end
|
|
105
106
|
|
|
@@ -92,7 +92,7 @@ module ReactOnRails
|
|
|
92
92
|
2. Visit http://localhost:3000/hello_server to see RSC in action
|
|
93
93
|
3. The RSC bundle watcher will compile server components
|
|
94
94
|
|
|
95
|
-
Documentation: https://
|
|
95
|
+
Documentation: https://reactonrails.com/docs/pro/react-server-components/
|
|
96
96
|
MSG
|
|
97
97
|
end
|
|
98
98
|
end
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
# 2. Remove precompile_hook from config/shakapacker.yml if present
|
|
36
36
|
# 3. Uncomment the run_precompile_tasks call near the bottom of this file
|
|
37
37
|
#
|
|
38
|
-
# See documentation: https://
|
|
38
|
+
# See documentation: https://reactonrails.com/docs/building-features/extensible-precompile-pattern
|
|
39
39
|
#
|
|
40
40
|
# def run_precompile_tasks
|
|
41
41
|
# require_relative "../config/environment"
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { env } = require('shakapacker')
|
|
2
|
+
const { existsSync } = require('fs')
|
|
3
|
+
const { resolve } = require('path')
|
|
4
|
+
|
|
5
|
+
const envSpecificConfig = () => {
|
|
6
|
+
const path = resolve(__dirname, `${env.nodeEnv}.js`)
|
|
7
|
+
if (existsSync(path)) {
|
|
8
|
+
console.log(`Loading ENV specific rspack configuration file ${path}`)
|
|
9
|
+
return require(path)
|
|
10
|
+
} else {
|
|
11
|
+
throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = envSpecificConfig()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { env } from 'shakapacker'
|
|
2
|
+
import { existsSync } from 'fs'
|
|
3
|
+
import { resolve } from 'path'
|
|
4
|
+
|
|
5
|
+
const envSpecificConfig = () => {
|
|
6
|
+
const path = resolve(__dirname, `${env.nodeEnv}.js`)
|
|
7
|
+
if (existsSync(path)) {
|
|
8
|
+
console.log(`Loading ENV specific rspack configuration file ${path}`)
|
|
9
|
+
return require(path)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default envSpecificConfig()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { env } from 'shakapacker'
|
|
2
|
+
import { existsSync } from 'fs'
|
|
3
|
+
import { resolve } from 'path'
|
|
4
|
+
|
|
5
|
+
const envSpecificConfig = () => {
|
|
6
|
+
const path = resolve(__dirname, `${env.nodeEnv}.js`)
|
|
7
|
+
if (existsSync(path)) {
|
|
8
|
+
console.log(`Loading ENV specific webpack configuration file ${path}`)
|
|
9
|
+
return require(path)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default envSpecificConfig()
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
-
const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
|
|
2
|
+
const { reactOnRailsProNodeRenderer, parseWorkersCount } = require('react-on-rails-pro-node-renderer');
|
|
3
3
|
|
|
4
4
|
const { env } = process;
|
|
5
|
+
const configuredWorkersCount =
|
|
6
|
+
parseWorkersCount(env.RENDERER_WORKERS_COUNT) ?? parseWorkersCount(env.NODE_RENDERER_CONCURRENCY);
|
|
5
7
|
|
|
6
8
|
const config = {
|
|
7
9
|
serverBundleCachePath: path.resolve(__dirname, '../.node-renderer-bundles'),
|
|
@@ -12,8 +14,10 @@ const config = {
|
|
|
12
14
|
password: env.RENDERER_PASSWORD || 'devPassword',
|
|
13
15
|
|
|
14
16
|
// Number of Node.js worker threads for SSR rendering
|
|
15
|
-
// Set
|
|
16
|
-
|
|
17
|
+
// Set RENDERER_WORKERS_COUNT env var to override (e.g., for production tuning)
|
|
18
|
+
// Set to 0 for single-process mode (useful for debugging).
|
|
19
|
+
// Legacy fallback: NODE_RENDERER_CONCURRENCY
|
|
20
|
+
workersCount: configuredWorkersCount ?? 3,
|
|
17
21
|
|
|
18
22
|
// If set to true, `supportModules` enables the server-bundle code to call a default set of NodeJS modules
|
|
19
23
|
// that get added to the VM context: { Buffer, process, setTimeout, setInterval, clearTimeout, clearInterval }.
|
|
@@ -34,7 +38,7 @@ const config = {
|
|
|
34
38
|
// Renderer detects a total number of CPUs on virtual hostings like Heroku or CircleCI instead
|
|
35
39
|
// of CPUs number allocated for current container. This results in spawning many workers while
|
|
36
40
|
// only 1-2 of them really needed.
|
|
37
|
-
if (env.CI) {
|
|
41
|
+
if (env.CI && configuredWorkersCount == null) {
|
|
38
42
|
config.workersCount = 2;
|
|
39
43
|
}
|
|
40
44
|
|
data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# See https://
|
|
3
|
+
# See https://reactonrails.com/docs/configuration/configuration-pro
|
|
4
4
|
# License: Set REACT_ON_RAILS_PRO_LICENSE environment variable
|
|
5
5
|
ReactOnRailsPro.configure do |config|
|
|
6
6
|
config.server_renderer = "NodeRenderer"
|
data/lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb.tt
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# - Automatic hydration on the client
|
|
11
11
|
#
|
|
12
12
|
# For more information, see:
|
|
13
|
-
# https://
|
|
13
|
+
# https://reactonrails.com/docs/pro/react-server-components/
|
|
14
14
|
|
|
15
15
|
class HelloServerController < ApplicationController
|
|
16
16
|
layout "<%= config[:layout_name] %>"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
|
|
10
10
|
//
|
|
11
11
|
// For more information, see:
|
|
12
|
-
// https://
|
|
12
|
+
// https://reactonrails.com/docs/pro/react-server-components/
|
|
13
13
|
|
|
14
14
|
import React from 'react';
|
|
15
15
|
import LikeButton from './LikeButton';
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
|
|
10
10
|
//
|
|
11
11
|
// For more information, see:
|
|
12
|
-
// https://
|
|
12
|
+
// https://reactonrails.com/docs/pro/react-server-components/
|
|
13
13
|
|
|
14
14
|
import React from 'react';
|
|
15
15
|
import LikeButton from './LikeButton';
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
<p style="margin-top: 16px;">
|
|
32
32
|
<strong>Learn more:</strong>
|
|
33
|
-
<a href="https://
|
|
33
|
+
<a href="https://reactonrails.com/docs/pro/react-server-components/">
|
|
34
34
|
React Server Components Documentation
|
|
35
35
|
</a>
|
|
36
36
|
</p>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// React Server Components webpack configuration
|
|
2
2
|
// This creates the RSC bundle based on the server webpack config
|
|
3
|
-
// See: https://
|
|
3
|
+
// See: https://reactonrails.com/docs/pro/react-server-components/
|
|
4
4
|
|
|
5
5
|
const serverWebpackModule = require('./serverWebpackConfig');
|
|
6
6
|
|