react_on_rails 16.7.0.rc.3 → 17.0.0.rc.1
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 +1 -0
- data/Gemfile.development_dependencies +7 -3
- data/Gemfile.lock +9 -9
- data/lib/generators/react_on_rails/base_generator.rb +28 -3
- data/lib/generators/react_on_rails/generator_helper.rb +82 -27
- data/lib/generators/react_on_rails/generator_messages/ci_section.rb +9 -1
- data/lib/generators/react_on_rails/install_generator.rb +48 -21
- data/lib/generators/react_on_rails/js_dependency_manager.rb +7 -0
- data/lib/generators/react_on_rails/pro_setup.rb +56 -4
- data/lib/generators/react_on_rails/rsc_setup/client_references.rb +158 -40
- data/lib/generators/react_on_rails/rsc_setup.rb +19 -0
- data/lib/generators/react_on_rails/shakapacker_precompile_hook_helper.rb +160 -0
- data/lib/generators/react_on_rails/templates/base/base/.github/workflows/ci.yml.tt +7 -1
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +1 -1
- data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +6 -1
- data/lib/generators/react_on_rails/templates/pro/base/renderer/{node-renderer.js → node-renderer.js.tt} +6 -1
- data/lib/react_on_rails/config_path_resolver.rb +0 -2
- data/lib/react_on_rails/dev/server_manager.rb +260 -44
- data/lib/react_on_rails/dev/server_mode.rb +211 -0
- data/lib/react_on_rails/dev.rb +1 -0
- data/lib/react_on_rails/doctor.rb +188 -41
- data/lib/react_on_rails/engine.rb +9 -1
- data/lib/react_on_rails/helper.rb +35 -1
- data/lib/react_on_rails/length_prefixed_parser.rb +5 -4
- data/lib/react_on_rails/packs_generator.rb +24 -8
- data/lib/react_on_rails/prerender_error.rb +14 -6
- data/lib/react_on_rails/pro_helper.rb +2 -0
- data/lib/react_on_rails/system_checker.rb +48 -16
- data/lib/react_on_rails/test_helper/dev_assets_detector.rb +19 -17
- data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +2 -2
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +8 -8
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +2 -2
- data/lib/react_on_rails/test_helper.rb +6 -6
- data/lib/react_on_rails/version.rb +1 -1
- data/rakelib/lint.rake +1 -1
- data/rakelib/run_rspec.rake +0 -2
- data/rakelib/shakapacker_version.rake +4 -1
- data/react_on_rails.gemspec +2 -2
- metadata +6 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0feb399078c3e60a35b5e36bc257cc2711bf793fd04dab39c3ccfcfdd8448cd8
|
|
4
|
+
data.tar.gz: 3848ca13d934d2fda5ca63f8b7660aaac360ac3daec07d7a15433a647d058c44
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d2a9e86976672ce1b5ae6b869a9d777bb652b35423cb7b361614db8ccdb710423ad8434115f460ffd7522336a9eb8eec74382bd793f4cd537dfe2d12b69df46
|
|
7
|
+
data.tar.gz: b75324ae9ad146861baebd20716ef293c28509734afbf206da63275db4d29c6a24115a9e2b834781d275a1a586fd9215cdd208c1e93a1101a47d275436cbfda1
|
data/.rubocop.yml
CHANGED
|
@@ -2,18 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
eval_gemfile File.expand_path("../Gemfile.shared_dev_dependencies", __dir__)
|
|
4
4
|
|
|
5
|
-
gem "shakapacker", "
|
|
5
|
+
gem "shakapacker", "10.1.0"
|
|
6
6
|
gem "bootsnap", require: false
|
|
7
7
|
gem "rails", "~> 7.1.0"
|
|
8
8
|
|
|
9
|
-
gem "sqlite3", "~>
|
|
9
|
+
gem "sqlite3", "~> 2.0"
|
|
10
10
|
gem "sass-rails", "~> 6.0"
|
|
11
11
|
gem "uglifier"
|
|
12
12
|
gem "jquery-rails"
|
|
13
13
|
gem "puma", "~> 6.0"
|
|
14
14
|
|
|
15
15
|
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
|
|
16
|
-
|
|
16
|
+
# Declared unconditionally so the gemset always matches Gemfile.lock. DISABLE_TURBOLINKS
|
|
17
|
+
# toggles Turbolinks at the application layer (the require_asset in
|
|
18
|
+
# spec/dummy/app/assets/javascripts/application_non_webpack.js.erb), not gem inclusion.
|
|
19
|
+
# A conditional declaration broke `bundle install --frozen` in CI (see AGENTS.md).
|
|
20
|
+
gem "turbolinks"
|
|
17
21
|
|
|
18
22
|
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
|
19
23
|
gem "jbuilder"
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
react_on_rails (
|
|
4
|
+
react_on_rails (17.0.0.rc.1)
|
|
5
5
|
addressable
|
|
6
6
|
connection_pool
|
|
7
7
|
execjs (~> 2.5)
|
|
@@ -237,7 +237,7 @@ GEM
|
|
|
237
237
|
nio4r (~> 2.0)
|
|
238
238
|
racc (1.8.1)
|
|
239
239
|
rack (3.2.5)
|
|
240
|
-
rack-proxy (0.
|
|
240
|
+
rack-proxy (0.8.2)
|
|
241
241
|
rack
|
|
242
242
|
rack-session (2.1.1)
|
|
243
243
|
base64 (>= 0.1.0)
|
|
@@ -360,7 +360,7 @@ GEM
|
|
|
360
360
|
rubyzip (>= 1.2.2, < 3.0)
|
|
361
361
|
websocket (~> 1.0)
|
|
362
362
|
semantic_range (3.1.1)
|
|
363
|
-
shakapacker (
|
|
363
|
+
shakapacker (10.1.0)
|
|
364
364
|
activesupport (>= 5.2)
|
|
365
365
|
package_json
|
|
366
366
|
rack-proxy (>= 0.6.1)
|
|
@@ -379,10 +379,10 @@ GEM
|
|
|
379
379
|
actionpack (>= 5.2)
|
|
380
380
|
activesupport (>= 5.2)
|
|
381
381
|
sprockets (>= 3.0.0)
|
|
382
|
-
sqlite3 (
|
|
382
|
+
sqlite3 (2.9.4)
|
|
383
383
|
mini_portile2 (~> 2.8.0)
|
|
384
|
-
sqlite3 (
|
|
385
|
-
sqlite3 (
|
|
384
|
+
sqlite3 (2.9.4-arm64-darwin)
|
|
385
|
+
sqlite3 (2.9.4-x86_64-linux-gnu)
|
|
386
386
|
steep (1.9.4)
|
|
387
387
|
activesupport (>= 5.1)
|
|
388
388
|
concurrent-ruby (>= 1.1.10)
|
|
@@ -475,11 +475,11 @@ DEPENDENCIES
|
|
|
475
475
|
sass-rails (~> 6.0)
|
|
476
476
|
sdoc
|
|
477
477
|
selenium-webdriver (= 4.9.0)
|
|
478
|
-
shakapacker (=
|
|
478
|
+
shakapacker (= 10.1.0)
|
|
479
479
|
simplecov (~> 0.16.1)
|
|
480
480
|
spring (~> 4.0)
|
|
481
481
|
sprockets (~> 4.0)
|
|
482
|
-
sqlite3 (~>
|
|
482
|
+
sqlite3 (~> 2.0)
|
|
483
483
|
steep
|
|
484
484
|
turbo-rails
|
|
485
485
|
turbolinks
|
|
@@ -487,4 +487,4 @@ DEPENDENCIES
|
|
|
487
487
|
webdrivers (= 5.3.0)
|
|
488
488
|
|
|
489
489
|
BUNDLED WITH
|
|
490
|
-
|
|
490
|
+
4.0.10
|
|
@@ -6,11 +6,13 @@ require "erb"
|
|
|
6
6
|
require_relative "generator_messages"
|
|
7
7
|
require_relative "generator_helper"
|
|
8
8
|
require_relative "js_dependency_manager"
|
|
9
|
+
require_relative "shakapacker_precompile_hook_helper"
|
|
9
10
|
module ReactOnRails
|
|
10
11
|
module Generators
|
|
11
12
|
class BaseGenerator < Rails::Generators::Base
|
|
12
13
|
include GeneratorHelper
|
|
13
14
|
include JsDependencyManager
|
|
15
|
+
include ShakapackerPrecompileHookHelper
|
|
14
16
|
|
|
15
17
|
Rails::Generators.hide_namespace(namespace)
|
|
16
18
|
source_root(File.expand_path("templates", __dir__))
|
|
@@ -22,11 +24,22 @@ module ReactOnRails
|
|
|
22
24
|
desc: "Install Redux package and Redux version of Hello World Example",
|
|
23
25
|
aliases: "-R"
|
|
24
26
|
|
|
25
|
-
# --rspack
|
|
27
|
+
# --rspack / --no-rspack (Rspack is the default on fresh installs; --no-rspack selects Webpack)
|
|
28
|
+
# IMPORTANT: do NOT add a `default:` here. The absence of a default is load-bearing — Thor
|
|
29
|
+
# only includes :rspack in the options hash when the flag is explicitly passed, which is how
|
|
30
|
+
# GeneratorHelper#using_rspack? tells an explicit choice from "no flag given" (the latter
|
|
31
|
+
# falls back to rspack_bundler_default). Adding `default: false` would make
|
|
32
|
+
# options.key?(:rspack) always true and silently break the fresh-install Rspack default.
|
|
33
|
+
# (Thor's omit-when-no-default behavior verified against Thor 1.5.0; see Gemfile.lock.)
|
|
26
34
|
class_option :rspack,
|
|
27
35
|
type: :boolean,
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
desc: "Use Rspack (default) as the bundler; pass --no-rspack to use Webpack"
|
|
37
|
+
|
|
38
|
+
# --webpack: friendly alias for --no-rspack (reconciled in GeneratorHelper#explicit_bundler_choice).
|
|
39
|
+
# No `default:` here either — same load-bearing reason as --rspack above.
|
|
40
|
+
class_option :webpack,
|
|
41
|
+
type: :boolean,
|
|
42
|
+
desc: "Use Webpack as the bundler (alias for --no-rspack; --no-webpack is equivalent to --rspack)"
|
|
30
43
|
|
|
31
44
|
# --pro
|
|
32
45
|
class_option :pro,
|
|
@@ -313,6 +326,18 @@ module ReactOnRails
|
|
|
313
326
|
|
|
314
327
|
private
|
|
315
328
|
|
|
329
|
+
# Fresh-install context: default to Rspack (when Shakapacker supports it) unless the
|
|
330
|
+
# app already declares a bundler. See GeneratorHelper#fresh_install_rspack_default.
|
|
331
|
+
# NOTE: InstallGenerator#rspack_bundler_default is an intentional twin of this override
|
|
332
|
+
# (both generators are independently CLI-invocable); keep the two in sync.
|
|
333
|
+
def rspack_bundler_default
|
|
334
|
+
fresh_install_rspack_default
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def generated_build_test_command
|
|
338
|
+
shakapacker_build_command(env: "RAILS_ENV=test NODE_ENV=test", environment: "test")
|
|
339
|
+
end
|
|
340
|
+
|
|
316
341
|
def generate_new_app_home_page?
|
|
317
342
|
options.new_app? && new_app_root_route_added?
|
|
318
343
|
end
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "json"
|
|
4
|
+
require_relative "shakapacker_precompile_hook_helper"
|
|
4
5
|
|
|
6
|
+
# rubocop:disable Metrics/ModuleLength
|
|
5
7
|
module GeneratorHelper
|
|
8
|
+
include ReactOnRails::Generators::ShakapackerPrecompileHookHelper
|
|
9
|
+
|
|
6
10
|
def package_json
|
|
7
11
|
# Lazy load package_json gem only when actually needed for dependency management
|
|
8
12
|
|
|
@@ -128,11 +132,57 @@ module GeneratorHelper
|
|
|
128
132
|
def using_rspack?
|
|
129
133
|
return @using_rspack if defined?(@using_rspack)
|
|
130
134
|
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
#
|
|
134
|
-
|
|
135
|
-
@using_rspack =
|
|
135
|
+
# An explicit bundler flag always wins. When none was passed (or the generator doesn't
|
|
136
|
+
# declare the flags, e.g. RscGenerator/ProGenerator), fall back to the bundler default,
|
|
137
|
+
# which each generator defines for its own context.
|
|
138
|
+
explicit = explicit_bundler_choice
|
|
139
|
+
@using_rspack = explicit.nil? ? rspack_bundler_default : explicit
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Resolve the explicit bundler flags into a single choice.
|
|
143
|
+
#
|
|
144
|
+
# --rspack selects Rspack; --no-rspack and --webpack select Webpack (--webpack is a friendly
|
|
145
|
+
# alias for --no-rspack, and the auto-generated --no-webpack mirrors --rspack). Returns true
|
|
146
|
+
# for Rspack, false for Webpack, or nil when no bundler flag was passed (so the caller falls
|
|
147
|
+
# back to rspack_bundler_default).
|
|
148
|
+
#
|
|
149
|
+
# IMPORTANT: this relies on Thor NOT including a nil-defaulted option in the hash when the flag
|
|
150
|
+
# is absent — options.key?(:rspack)/(:webpack) is true only when the user passed that flag.
|
|
151
|
+
# Re-adding `default:` to either class_option would make the key always present and break both
|
|
152
|
+
# the "no flag given" fallback and the conflict detection here.
|
|
153
|
+
# (Thor's omit-when-no-default behavior verified against Thor 1.5.0; see Gemfile.lock.)
|
|
154
|
+
#
|
|
155
|
+
# Passing contradictory flags (e.g. --rspack --webpack) raises a Thor::Error.
|
|
156
|
+
def explicit_bundler_choice
|
|
157
|
+
choices = []
|
|
158
|
+
choices << options[:rspack] if options.key?(:rspack)
|
|
159
|
+
# --webpack means "use Webpack" (rspack = false); --no-webpack means "use Rspack".
|
|
160
|
+
# Name the inverted webpack flag so the rspack-boolean intent reads directly.
|
|
161
|
+
rspack_via_webpack_flag = !options[:webpack]
|
|
162
|
+
choices << rspack_via_webpack_flag if options.key?(:webpack)
|
|
163
|
+
return nil if choices.empty?
|
|
164
|
+
|
|
165
|
+
if choices.uniq.length > 1
|
|
166
|
+
raise Thor::Error,
|
|
167
|
+
"Conflicting bundler flags: pass either Rspack (--rspack) or Webpack " \
|
|
168
|
+
"(--webpack / --no-rspack), not both."
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
choices.first
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# True when the user passed any explicit bundler flag
|
|
175
|
+
# (--rspack/--no-rspack/--webpack/--no-webpack).
|
|
176
|
+
def bundler_flag_given?
|
|
177
|
+
options.key?(:rspack) || options.key?(:webpack)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
# Bundler to use when no explicit bundler flag was passed.
|
|
181
|
+
# Default (standalone generators like RscGenerator/ProGenerator): respect the existing
|
|
182
|
+
# project's shakapacker.yml and never impose a bundler. InstallGenerator/BaseGenerator
|
|
183
|
+
# override this to default fresh installs to Rspack.
|
|
184
|
+
def rspack_bundler_default
|
|
185
|
+
rspack_configured_in_project?
|
|
136
186
|
end
|
|
137
187
|
|
|
138
188
|
# Remap a config path from config/webpack/ to config/rspack/ when using rspack.
|
|
@@ -291,25 +341,6 @@ module GeneratorHelper
|
|
|
291
341
|
shakapacker_version_9_3_or_higher?
|
|
292
342
|
end
|
|
293
343
|
|
|
294
|
-
def parse_shakapacker_yml(path)
|
|
295
|
-
require "yaml"
|
|
296
|
-
# Use safe_load_file for security (defense-in-depth, even though this is user's own config)
|
|
297
|
-
# permitted_classes: [Symbol] allows symbol keys which shakapacker.yml may use
|
|
298
|
-
# aliases: true allows YAML anchors (&default, *default) commonly used in Rails configs
|
|
299
|
-
YAML.safe_load_file(path, permitted_classes: [Symbol], aliases: true)
|
|
300
|
-
rescue ArgumentError
|
|
301
|
-
# Older Psych versions don't support all parameters - try without aliases
|
|
302
|
-
begin
|
|
303
|
-
YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
304
|
-
rescue ArgumentError
|
|
305
|
-
# Very old Psych - fall back to safe_load with File.read
|
|
306
|
-
YAML.safe_load(File.read(path), permitted_classes: [Symbol]) # rubocop:disable Style/YAMLFileRead
|
|
307
|
-
end
|
|
308
|
-
rescue StandardError
|
|
309
|
-
# If we can't parse the file, return empty config
|
|
310
|
-
{}
|
|
311
|
-
end
|
|
312
|
-
|
|
313
344
|
# Check if Shakapacker 9.3.0 or higher is available
|
|
314
345
|
# This version made SWC the default JavaScript transpiler
|
|
315
346
|
def shakapacker_version_9_3_or_higher?
|
|
@@ -330,10 +361,34 @@ module GeneratorHelper
|
|
|
330
361
|
# `assets_bundler` inside the `default: &default` block, and our generator writes
|
|
331
362
|
# it there too via configure_rspack_in_shakapacker.
|
|
332
363
|
def rspack_configured_in_project?
|
|
364
|
+
shakapacker_assets_bundler_value == "rspack"
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# Fresh-install bundler default used by InstallGenerator/BaseGenerator: prefer Rspack
|
|
368
|
+
# when Shakapacker supports it (Rspack landed in Shakapacker 9.0), but never override an
|
|
369
|
+
# existing app's explicit assets_bundler choice. On a brand-new install where Shakapacker
|
|
370
|
+
# isn't loaded yet, shakapacker_version_9_or_higher? optimistically returns true.
|
|
371
|
+
def fresh_install_rspack_default
|
|
372
|
+
return rspack_configured_in_project? if project_declares_assets_bundler?
|
|
373
|
+
|
|
374
|
+
shakapacker_version_9_or_higher?
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
# True when config/shakapacker.yml exists and its default: section declares an
|
|
378
|
+
# assets_bundler (i.e., the project has already made an explicit bundler choice).
|
|
379
|
+
def project_declares_assets_bundler?
|
|
380
|
+
!shakapacker_assets_bundler_value.nil?
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
# Single source for the config/shakapacker.yml default-section read shared by
|
|
384
|
+
# rspack_configured_in_project? and project_declares_assets_bundler?. Returns the
|
|
385
|
+
# assets_bundler value (e.g. "rspack"), or nil when the file is absent or the key is unset.
|
|
386
|
+
# Only the default: section is inspected (see rspack_configured_in_project? for the rationale).
|
|
387
|
+
def shakapacker_assets_bundler_value
|
|
333
388
|
shakapacker_yml_path = File.join(destination_root, "config/shakapacker.yml")
|
|
334
|
-
return
|
|
389
|
+
return nil unless File.exist?(shakapacker_yml_path)
|
|
335
390
|
|
|
336
|
-
|
|
337
|
-
config.dig("default", "assets_bundler") == "rspack"
|
|
391
|
+
parse_shakapacker_yml(shakapacker_yml_path).dig("default", "assets_bundler")
|
|
338
392
|
end
|
|
339
393
|
end
|
|
394
|
+
# rubocop:enable Metrics/ModuleLength
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "rainbow"
|
|
4
|
+
require_relative "../shakapacker_precompile_hook_helper"
|
|
4
5
|
|
|
5
6
|
module GeneratorMessages
|
|
6
7
|
module CiSection
|
|
8
|
+
include ReactOnRails::Generators::ShakapackerPrecompileHookHelper
|
|
9
|
+
|
|
7
10
|
private
|
|
8
11
|
|
|
9
12
|
def build_ci_section(app_root: Dir.pwd, ci_workflow_generated: false)
|
|
@@ -25,6 +28,11 @@ module GeneratorMessages
|
|
|
25
28
|
else
|
|
26
29
|
""
|
|
27
30
|
end
|
|
31
|
+
manual_build_command = shakapacker_build_command(
|
|
32
|
+
env: "RAILS_ENV=test NODE_ENV=test",
|
|
33
|
+
app_root: app_root,
|
|
34
|
+
environment: "test"
|
|
35
|
+
)
|
|
28
36
|
|
|
29
37
|
<<~CI
|
|
30
38
|
|
|
@@ -35,7 +43,7 @@ module GeneratorMessages
|
|
|
35
43
|
#{ci_status}
|
|
36
44
|
|
|
37
45
|
To build bundles manually before tests:
|
|
38
|
-
#{Rainbow(
|
|
46
|
+
#{Rainbow(manual_build_command).cyan}#{build_test_hint}
|
|
39
47
|
CI
|
|
40
48
|
end
|
|
41
49
|
end
|
|
@@ -9,6 +9,7 @@ require_relative "generator_messages"
|
|
|
9
9
|
require_relative "js_dependency_manager"
|
|
10
10
|
require_relative "pro_setup"
|
|
11
11
|
require_relative "rsc_setup"
|
|
12
|
+
require_relative "shakapacker_precompile_hook_helper"
|
|
12
13
|
# Load-path require: git_utils lives under react_on_rails/lib, not relative to this generator directory.
|
|
13
14
|
require "react_on_rails/git_utils"
|
|
14
15
|
|
|
@@ -23,6 +24,7 @@ module ReactOnRails
|
|
|
23
24
|
include JsDependencyManager
|
|
24
25
|
include ProSetup
|
|
25
26
|
include RscSetup
|
|
27
|
+
include ShakapackerPrecompileHookHelper
|
|
26
28
|
|
|
27
29
|
# fetch USAGE file for details generator description
|
|
28
30
|
source_root(File.expand_path(__dir__))
|
|
@@ -41,11 +43,22 @@ module ReactOnRails
|
|
|
41
43
|
desc: "Generate TypeScript files and install TypeScript dependencies. Default: false",
|
|
42
44
|
aliases: "-T"
|
|
43
45
|
|
|
44
|
-
# --rspack
|
|
46
|
+
# --rspack / --no-rspack (Rspack is the default on fresh installs; --no-rspack selects Webpack)
|
|
47
|
+
# IMPORTANT: do NOT add a `default:` here. The absence of a default is load-bearing — Thor
|
|
48
|
+
# only includes :rspack in the options hash when the flag is explicitly passed, which is how
|
|
49
|
+
# GeneratorHelper#using_rspack? tells an explicit choice from "no flag given" (the latter
|
|
50
|
+
# falls back to rspack_bundler_default). Adding `default: false` would make
|
|
51
|
+
# options.key?(:rspack) always true and silently break the fresh-install Rspack default.
|
|
52
|
+
# (Thor's omit-when-no-default behavior verified against Thor 1.5.0; see Gemfile.lock.)
|
|
45
53
|
class_option :rspack,
|
|
46
54
|
type: :boolean,
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
desc: "Use Rspack (default) as the bundler; pass --no-rspack to use Webpack"
|
|
56
|
+
|
|
57
|
+
# --webpack: friendly alias for --no-rspack (reconciled in GeneratorHelper#explicit_bundler_choice).
|
|
58
|
+
# No `default:` here either — same load-bearing reason as --rspack above.
|
|
59
|
+
class_option :webpack,
|
|
60
|
+
type: :boolean,
|
|
61
|
+
desc: "Use Webpack as the bundler (alias for --no-rspack; --no-webpack is equivalent to --rspack)"
|
|
49
62
|
|
|
50
63
|
# --ignore-warnings
|
|
51
64
|
class_option :ignore_warnings,
|
|
@@ -87,7 +100,6 @@ module ReactOnRails
|
|
|
87
100
|
|
|
88
101
|
# Removed: --skip-shakapacker-install (Shakapacker is now a required dependency)
|
|
89
102
|
|
|
90
|
-
SHAKAPACKER_YML_PATH = "config/shakapacker.yml"
|
|
91
103
|
HELLO_WORLD_ROUTE = "hello_world"
|
|
92
104
|
HELLO_SERVER_ROUTE = "hello_server"
|
|
93
105
|
# Matches the stock `bin/dev` written by Rails 8.x. Rails 7.1 commonly
|
|
@@ -196,6 +208,14 @@ module ReactOnRails
|
|
|
196
208
|
|
|
197
209
|
private
|
|
198
210
|
|
|
211
|
+
# Fresh-install context: default to Rspack (when Shakapacker supports it) unless the
|
|
212
|
+
# app already declares a bundler. See GeneratorHelper#fresh_install_rspack_default.
|
|
213
|
+
# NOTE: BaseGenerator#rspack_bundler_default is an intentional twin of this override
|
|
214
|
+
# (both generators are independently CLI-invocable); keep the two in sync.
|
|
215
|
+
def rspack_bundler_default
|
|
216
|
+
fresh_install_rspack_default
|
|
217
|
+
end
|
|
218
|
+
|
|
199
219
|
def invoke_generators
|
|
200
220
|
ensure_shakapacker_installed
|
|
201
221
|
if options.typescript?
|
|
@@ -206,7 +226,7 @@ module ReactOnRails
|
|
|
206
226
|
# `invoke` instantiates child generators with a fresh options hash, so
|
|
207
227
|
# --pretend/--force/--skip must be forwarded explicitly at each boundary.
|
|
208
228
|
invoke "react_on_rails:base", [],
|
|
209
|
-
{ typescript: options.typescript?, redux: options.redux?, rspack:
|
|
229
|
+
{ typescript: options.typescript?, redux: options.redux?, rspack: using_rspack?,
|
|
210
230
|
pro: use_pro?, rsc: use_rsc?, new_app: options.new_app?,
|
|
211
231
|
shakapacker_just_installed: shakapacker_just_installed?,
|
|
212
232
|
force: options[:force], skip: options[:skip], pretend: options[:pretend] }
|
|
@@ -296,18 +316,19 @@ module ReactOnRails
|
|
|
296
316
|
{ package_manager: package_manager, has_lockfile: has_lockfile,
|
|
297
317
|
pnpm_version_declared: pnpm_version_declared,
|
|
298
318
|
pnpm_fallback_version: CI_PNPM_FALLBACK_VERSION,
|
|
299
|
-
has_active_record: has_active_record, has_rspec: has_rspec
|
|
319
|
+
has_active_record: has_active_record, has_rspec: has_rspec,
|
|
320
|
+
precompile_hook_command: shakapacker_precompile_hook_command(environment: "test") })
|
|
300
321
|
@ci_workflow_generated = true
|
|
301
322
|
end
|
|
302
323
|
|
|
303
|
-
#
|
|
304
|
-
#
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
324
|
+
# RAILS_ENV=production runs the hook with production Rails config, while
|
|
325
|
+
# NODE_ENV=production makes Shakapacker emit a minified production bundle.
|
|
326
|
+
def default_package_json_scripts
|
|
327
|
+
{
|
|
328
|
+
"build" => shakapacker_build_command(env: "RAILS_ENV=production NODE_ENV=production"),
|
|
329
|
+
"build:test" => shakapacker_build_command(env: "RAILS_ENV=test NODE_ENV=test", environment: "test")
|
|
330
|
+
}
|
|
331
|
+
end
|
|
311
332
|
|
|
312
333
|
def add_package_json_scripts
|
|
313
334
|
return if options[:pretend]
|
|
@@ -317,7 +338,7 @@ module ReactOnRails
|
|
|
317
338
|
|
|
318
339
|
original_text = File.read(package_json_path)
|
|
319
340
|
existing_scripts = JSON.parse(original_text)["scripts"] || {}
|
|
320
|
-
scripts_to_add =
|
|
341
|
+
scripts_to_add = default_package_json_scripts.reject { |key, _| existing_scripts.key?(key) }
|
|
321
342
|
|
|
322
343
|
if scripts_to_add.empty?
|
|
323
344
|
say_status :skip, "build scripts already present in package.json", :yellow
|
|
@@ -690,7 +711,10 @@ module ReactOnRails
|
|
|
690
711
|
flags = []
|
|
691
712
|
flags << "--redux" if options.redux?
|
|
692
713
|
flags << "--typescript" if options.typescript?
|
|
693
|
-
|
|
714
|
+
# Echo the resolved bundler choice (normalized to --rspack/--no-rspack, so a --webpack
|
|
715
|
+
# alias re-runs as --no-rspack) only when the user passed one explicitly. An unset choice
|
|
716
|
+
# re-resolves to the fresh-install default on re-run, so we don't pin it here.
|
|
717
|
+
flags << (using_rspack? ? "--rspack" : "--no-rspack") if bundler_flag_given?
|
|
694
718
|
|
|
695
719
|
if options.rsc?
|
|
696
720
|
flags << "--rsc"
|
|
@@ -838,11 +862,14 @@ module ReactOnRails
|
|
|
838
862
|
|
|
839
863
|
seed_package_manager_in_package_json_from_lockfile!
|
|
840
864
|
|
|
841
|
-
# Then run the shakapacker installer
|
|
842
|
-
#
|
|
843
|
-
#
|
|
844
|
-
#
|
|
845
|
-
|
|
865
|
+
# Then run the shakapacker installer.
|
|
866
|
+
# Resolve the bundler via using_rspack?. shakapacker.yml doesn't exist yet at this point,
|
|
867
|
+
# so the fresh-install default applies: an unset --rspack flag resolves to Rspack when
|
|
868
|
+
# Shakapacker supports it (shakapacker_version_9_or_higher? is optimistically true on a
|
|
869
|
+
# brand-new install where Shakapacker isn't loaded yet). An explicit --no-rspack still
|
|
870
|
+
# selects Webpack. using_rspack? memoizes, so the rest of the run (e.g.
|
|
871
|
+
# configure_rspack_in_shakapacker) stays consistent with this decision.
|
|
872
|
+
shakapacker_install_env = using_rspack? ? { "SHAKAPACKER_ASSETS_BUNDLER" => "rspack" } : {}
|
|
846
873
|
success = Bundler.with_unbundled_env do
|
|
847
874
|
system(shakapacker_install_env, "bundle exec rails shakapacker:install")
|
|
848
875
|
end
|
|
@@ -578,12 +578,19 @@ module ReactOnRails
|
|
|
578
578
|
end
|
|
579
579
|
|
|
580
580
|
File.write("package.json", "#{JSON.pretty_generate(content)}\n")
|
|
581
|
+
GeneratorMessages.add_warning(package_json_pin_fallback_warning(versioned_packages))
|
|
581
582
|
true
|
|
582
583
|
rescue StandardError => e
|
|
583
584
|
GeneratorMessages.add_warning("⚠️ Could not write dependency pins to package.json: #{e.message}")
|
|
584
585
|
false
|
|
585
586
|
end
|
|
586
587
|
|
|
588
|
+
def package_json_pin_fallback_warning(versioned_packages)
|
|
589
|
+
pinned_list = versioned_packages.map { |name, version| "#{name}@#{version}" }.join(", ")
|
|
590
|
+
"⚠️ Package manager install failed. Wrote the following version pins to package.json " \
|
|
591
|
+
"so you can rerun your package manager manually: #{pinned_list}"
|
|
592
|
+
end
|
|
593
|
+
|
|
587
594
|
def fallback_package_manager
|
|
588
595
|
package_manager = GeneratorMessages.detect_package_manager(app_root: destination_root)
|
|
589
596
|
return package_manager if GeneratorMessages.supported_package_manager?(package_manager)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "securerandom"
|
|
3
4
|
require_relative "generator_messages"
|
|
4
5
|
require "react_on_rails/node_renderer_procfile"
|
|
5
6
|
require "react_on_rails/pro_migration"
|
|
@@ -46,16 +47,58 @@ module ReactOnRails
|
|
|
46
47
|
say set_color("🚀 REACT ON RAILS PRO SETUP", :cyan, :bold)
|
|
47
48
|
say set_color("=" * 80, :cyan)
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
# The Rails initializer and Node renderer bootstrap must share the same
|
|
51
|
+
# password literal. Only mint a fresh random password when BOTH files will
|
|
52
|
+
# be created — otherwise nil so each template falls back to the env-only
|
|
53
|
+
# branch, avoiding a literal mismatch with any existing file.
|
|
54
|
+
# Always reassign so a stale value from a prior invocation on the same
|
|
55
|
+
# instance can't leak into a later partial-install run.
|
|
56
|
+
@generated_renderer_password = nil
|
|
57
|
+
if pro_initializer_will_be_created? && node_renderer_will_be_created?
|
|
58
|
+
@generated_renderer_password = SecureRandom.hex(32)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
initializer_created = create_pro_initializer
|
|
50
62
|
legacy_renderer_detected = create_node_renderer
|
|
51
63
|
add_pro_to_procfiles unless legacy_renderer_detected
|
|
52
64
|
update_webpack_config_for_pro
|
|
53
65
|
|
|
66
|
+
say_renderer_password_setup_summary(initializer_created)
|
|
67
|
+
|
|
54
68
|
say set_color("=" * 80, :cyan)
|
|
55
69
|
say "✅ React on Rails Pro setup complete!", :green
|
|
56
70
|
say set_color("=" * 80, :cyan)
|
|
57
71
|
end
|
|
58
72
|
|
|
73
|
+
def say_renderer_password_setup_summary(initializer_created)
|
|
74
|
+
if @generated_renderer_password
|
|
75
|
+
say ""
|
|
76
|
+
say set_color("🔐 A random renderer password was written into your config files.", :yellow, :bold)
|
|
77
|
+
say " For production, set RENDERER_PASSWORD as an env var instead and"
|
|
78
|
+
say " remove the literal value from version control."
|
|
79
|
+
say " See: https://www.shakacode.com/react-on-rails/docs/pro/node-renderer/"
|
|
80
|
+
say ""
|
|
81
|
+
elsif initializer_created
|
|
82
|
+
# Initializer was newly created but the Node renderer file already exists;
|
|
83
|
+
# the new initializer falls back to ENV["RENDERER_PASSWORD"] only so it doesn't
|
|
84
|
+
# disagree with whatever literal the existing renderer file contains.
|
|
85
|
+
say ""
|
|
86
|
+
say set_color("⚠️ Existing Node renderer detected — Rails initializer uses " \
|
|
87
|
+
"ENV[\"RENDERER_PASSWORD\"] only.", :yellow, :bold)
|
|
88
|
+
say " Set RENDERER_PASSWORD in your environment to match the password in your existing renderer."
|
|
89
|
+
say ""
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def pro_initializer_will_be_created?
|
|
94
|
+
!File.exist?(File.join(destination_root, "config/initializers/react_on_rails_pro.rb"))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def node_renderer_will_be_created?
|
|
98
|
+
!File.exist?(File.join(destination_root, "renderer/node-renderer.js")) &&
|
|
99
|
+
!File.exist?(File.join(destination_root, "client/node-renderer.js"))
|
|
100
|
+
end
|
|
101
|
+
|
|
59
102
|
# Check if the Pro gem is missing. When the base react_on_rails gem is in
|
|
60
103
|
# the Gemfile, installation is deferred to the later Gemfile swap (which
|
|
61
104
|
# preserves the user's version pin); otherwise auto-install via `bundle
|
|
@@ -205,14 +248,18 @@ module ReactOnRails
|
|
|
205
248
|
|
|
206
249
|
if File.exist?(File.join(destination_root, initializer_path))
|
|
207
250
|
say "ℹ️ #{initializer_path} already exists, skipping", :yellow
|
|
208
|
-
return
|
|
251
|
+
return false
|
|
209
252
|
end
|
|
210
253
|
|
|
211
254
|
say "📝 Creating React on Rails Pro initializer...", :yellow
|
|
212
255
|
|
|
256
|
+
# @generated_renderer_password is set by setup_pro only when both this
|
|
257
|
+
# file and the Node renderer bootstrap will be created together; nil here
|
|
258
|
+
# means the template emits the env-only fallback (no literal password).
|
|
213
259
|
template("templates/pro/base/config/initializers/react_on_rails_pro.rb.tt", initializer_path)
|
|
214
260
|
|
|
215
261
|
say "✅ Created #{initializer_path}", :green
|
|
262
|
+
true
|
|
216
263
|
end
|
|
217
264
|
|
|
218
265
|
# Matches active (uncommented) Procfile.dev node-renderer lines that
|
|
@@ -267,6 +314,11 @@ module ReactOnRails
|
|
|
267
314
|
"to migrate, move it to #{node_renderer_path} and update any references " \
|
|
268
315
|
"(e.g. Procfile.dev, Procfile.prod, Docker CMD / command):", :yellow
|
|
269
316
|
say " #{node_renderer_procfile_command('Procfile.dev')}", :yellow
|
|
317
|
+
say set_color(
|
|
318
|
+
"⚠️ Ensure the password in #{legacy_node_renderer_path} matches " \
|
|
319
|
+
"config/initializers/react_on_rails_pro.rb. Both must use the same RENDERER_PASSWORD.",
|
|
320
|
+
:yellow
|
|
321
|
+
)
|
|
270
322
|
warn_on_stale_legacy_procfile_entry
|
|
271
323
|
return true
|
|
272
324
|
end
|
|
@@ -275,8 +327,8 @@ module ReactOnRails
|
|
|
275
327
|
|
|
276
328
|
empty_directory("renderer")
|
|
277
329
|
|
|
278
|
-
template_path = "templates/pro/base/renderer/node-renderer.js"
|
|
279
|
-
|
|
330
|
+
template_path = "templates/pro/base/renderer/node-renderer.js.tt"
|
|
331
|
+
template(template_path, node_renderer_path)
|
|
280
332
|
|
|
281
333
|
say "✅ Created #{node_renderer_path}", :green
|
|
282
334
|
false
|