react_on_rails 16.2.0.beta.8 → 16.2.0.beta.11
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 +19 -13
- data/CLAUDE.md +136 -5
- data/CONTRIBUTING.md +3 -1
- data/Gemfile.lock +1 -1
- data/Steepfile +4 -0
- data/analysis/rake-task-duplicate-analysis.md +149 -0
- data/bin/ci-run-failed-specs +6 -4
- data/bin/ci-switch-config +4 -3
- data/knip.ts +1 -1
- data/lib/generators/react_on_rails/base_generator.rb +5 -119
- data/lib/generators/react_on_rails/generator_helper.rb +29 -0
- data/lib/generators/react_on_rails/install_generator.rb +5 -180
- data/lib/generators/react_on_rails/js_dependency_manager.rb +354 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +19 -0
- data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt} +18 -2
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +38 -4
- data/lib/react_on_rails/configuration.rb +82 -8
- data/lib/react_on_rails/dev/pack_generator.rb +1 -0
- data/lib/react_on_rails/dev/server_manager.rb +1 -0
- data/lib/react_on_rails/doctor.rb +94 -4
- data/lib/react_on_rails/engine.rb +2 -5
- data/lib/react_on_rails/system_checker.rb +7 -4
- data/lib/react_on_rails/utils.rb +54 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/react_on_rails_pro/Gemfile.lock +3 -3
- data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
- data/react_on_rails_pro/package.json +1 -1
- data/react_on_rails_pro/spec/dummy/Gemfile.lock +3 -3
- data/react_on_rails_pro/spec/dummy/bin/shakapacker-precompile-hook +19 -0
- data/react_on_rails_pro/spec/dummy/config/shakapacker.yml +5 -0
- data/sig/react_on_rails/dev/file_manager.rbs +15 -0
- data/sig/react_on_rails/dev/pack_generator.rbs +19 -0
- data/sig/react_on_rails/dev/process_manager.rbs +22 -0
- data/sig/react_on_rails/dev/server_manager.rbs +39 -0
- data/sig/react_on_rails/generators/js_dependency_manager.rbs +123 -0
- metadata +11 -3
|
@@ -95,4 +95,33 @@ module GeneratorHelper
|
|
|
95
95
|
def component_extension(options)
|
|
96
96
|
options.typescript? ? "tsx" : "jsx"
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
# Check if Shakapacker 9.0 or higher is available
|
|
100
|
+
# Returns true if Shakapacker >= 9.0, false otherwise
|
|
101
|
+
#
|
|
102
|
+
# This method is used during code generation to determine which configuration
|
|
103
|
+
# patterns to use in generated files (e.g., config.privateOutputPath vs hardcoded paths).
|
|
104
|
+
#
|
|
105
|
+
# @return [Boolean] true if Shakapacker 9.0+ is available or likely to be installed
|
|
106
|
+
#
|
|
107
|
+
# @note Default behavior: Returns true when Shakapacker is not yet installed
|
|
108
|
+
# Rationale: During fresh installations, we optimistically assume users will install
|
|
109
|
+
# the latest Shakapacker version. This ensures new projects get best-practice configs.
|
|
110
|
+
# If users later install an older version, the generated webpack config includes
|
|
111
|
+
# fallback logic (e.g., `config.privateOutputPath || hardcodedPath`) that prevents
|
|
112
|
+
# breakage, and validation warnings guide them to fix any misconfigurations.
|
|
113
|
+
def shakapacker_version_9_or_higher?
|
|
114
|
+
return @shakapacker_version_9_or_higher if defined?(@shakapacker_version_9_or_higher)
|
|
115
|
+
|
|
116
|
+
@shakapacker_version_9_or_higher = begin
|
|
117
|
+
# If Shakapacker is not available yet (fresh install), default to true
|
|
118
|
+
# since we're likely installing the latest version
|
|
119
|
+
return true unless defined?(ReactOnRails::PackerUtils)
|
|
120
|
+
|
|
121
|
+
ReactOnRails::PackerUtils.shakapacker_version_requirement_met?("9.0.0")
|
|
122
|
+
rescue StandardError
|
|
123
|
+
# If we can't determine version, assume latest
|
|
124
|
+
true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
98
127
|
end
|
|
@@ -4,12 +4,14 @@ require "rails/generators"
|
|
|
4
4
|
require "json"
|
|
5
5
|
require_relative "generator_helper"
|
|
6
6
|
require_relative "generator_messages"
|
|
7
|
+
require_relative "js_dependency_manager"
|
|
7
8
|
|
|
8
9
|
module ReactOnRails
|
|
9
10
|
module Generators
|
|
10
11
|
# rubocop:disable Metrics/ClassLength
|
|
11
12
|
class InstallGenerator < Rails::Generators::Base
|
|
12
13
|
include GeneratorHelper
|
|
14
|
+
include JsDependencyManager
|
|
13
15
|
|
|
14
16
|
# fetch USAGE file for details generator description
|
|
15
17
|
source_root(File.expand_path(__dir__))
|
|
@@ -113,10 +115,7 @@ module ReactOnRails
|
|
|
113
115
|
end
|
|
114
116
|
|
|
115
117
|
def setup_react_dependencies
|
|
116
|
-
|
|
117
|
-
@ran_direct_installs ||= false
|
|
118
|
-
add_js_dependencies
|
|
119
|
-
install_js_dependencies if @added_dependencies_to_package_json && !@ran_direct_installs
|
|
118
|
+
setup_js_dependencies
|
|
120
119
|
end
|
|
121
120
|
|
|
122
121
|
# NOTE: other requirements for existing files such as .gitignore or application.
|
|
@@ -366,29 +365,8 @@ module ReactOnRails
|
|
|
366
365
|
|
|
367
366
|
def install_typescript_dependencies
|
|
368
367
|
puts Rainbow("📝 Installing TypeScript dependencies...").yellow
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
typescript_packages = %w[
|
|
372
|
-
typescript
|
|
373
|
-
@types/react
|
|
374
|
-
@types/react-dom
|
|
375
|
-
@babel/preset-typescript
|
|
376
|
-
]
|
|
377
|
-
|
|
378
|
-
# Try using GeneratorHelper first (package manager agnostic)
|
|
379
|
-
return if add_npm_dependencies(typescript_packages, dev: true)
|
|
380
|
-
|
|
381
|
-
# Fallback to npm if GeneratorHelper fails
|
|
382
|
-
success = system("npm", "install", "--save-dev", *typescript_packages)
|
|
383
|
-
return if success
|
|
384
|
-
|
|
385
|
-
warning = <<~MSG.strip
|
|
386
|
-
⚠️ Failed to install TypeScript dependencies automatically.
|
|
387
|
-
|
|
388
|
-
Please run manually:
|
|
389
|
-
npm install --save-dev #{typescript_packages.join(' ')}
|
|
390
|
-
MSG
|
|
391
|
-
GeneratorMessages.add_warning(warning)
|
|
368
|
+
# Delegate to shared module for consistent dependency management
|
|
369
|
+
add_typescript_dependencies
|
|
392
370
|
end
|
|
393
371
|
|
|
394
372
|
def create_css_module_types
|
|
@@ -450,159 +428,6 @@ module ReactOnRails
|
|
|
450
428
|
puts Rainbow("✅ Created tsconfig.json").green
|
|
451
429
|
end
|
|
452
430
|
|
|
453
|
-
def add_js_dependencies
|
|
454
|
-
add_react_on_rails_package
|
|
455
|
-
add_react_dependencies
|
|
456
|
-
add_css_dependencies
|
|
457
|
-
add_rspack_dependencies if options.rspack?
|
|
458
|
-
add_dev_dependencies
|
|
459
|
-
end
|
|
460
|
-
|
|
461
|
-
def add_react_on_rails_package
|
|
462
|
-
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
|
|
463
|
-
|
|
464
|
-
# Try to use package_json gem first, fall back to direct npm commands
|
|
465
|
-
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
|
|
466
|
-
["react-on-rails@#{ReactOnRails::VERSION}"]
|
|
467
|
-
else
|
|
468
|
-
puts "Adding the latest react-on-rails NPM module. " \
|
|
469
|
-
"Double check this is correct in package.json"
|
|
470
|
-
["react-on-rails"]
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
puts "Installing React on Rails package..."
|
|
474
|
-
if add_npm_dependencies(react_on_rails_pkg)
|
|
475
|
-
@added_dependencies_to_package_json = true
|
|
476
|
-
return
|
|
477
|
-
end
|
|
478
|
-
|
|
479
|
-
puts "Using direct npm commands as fallback"
|
|
480
|
-
success = system("npm", "install", *react_on_rails_pkg)
|
|
481
|
-
@ran_direct_installs = true if success
|
|
482
|
-
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
|
|
483
|
-
end
|
|
484
|
-
|
|
485
|
-
def add_react_dependencies
|
|
486
|
-
puts "Installing React dependencies..."
|
|
487
|
-
react_deps = %w[
|
|
488
|
-
react
|
|
489
|
-
react-dom
|
|
490
|
-
@babel/preset-react
|
|
491
|
-
prop-types
|
|
492
|
-
babel-plugin-transform-react-remove-prop-types
|
|
493
|
-
babel-plugin-macros
|
|
494
|
-
]
|
|
495
|
-
if add_npm_dependencies(react_deps)
|
|
496
|
-
@added_dependencies_to_package_json = true
|
|
497
|
-
return
|
|
498
|
-
end
|
|
499
|
-
|
|
500
|
-
success = system("npm", "install", *react_deps)
|
|
501
|
-
@ran_direct_installs = true if success
|
|
502
|
-
handle_npm_failure("React dependencies", react_deps) unless success
|
|
503
|
-
end
|
|
504
|
-
|
|
505
|
-
def add_css_dependencies
|
|
506
|
-
puts "Installing CSS handling dependencies..."
|
|
507
|
-
css_deps = %w[
|
|
508
|
-
css-loader
|
|
509
|
-
css-minimizer-webpack-plugin
|
|
510
|
-
mini-css-extract-plugin
|
|
511
|
-
style-loader
|
|
512
|
-
]
|
|
513
|
-
if add_npm_dependencies(css_deps)
|
|
514
|
-
@added_dependencies_to_package_json = true
|
|
515
|
-
return
|
|
516
|
-
end
|
|
517
|
-
|
|
518
|
-
success = system("npm", "install", *css_deps)
|
|
519
|
-
@ran_direct_installs = true if success
|
|
520
|
-
handle_npm_failure("CSS dependencies", css_deps) unless success
|
|
521
|
-
end
|
|
522
|
-
|
|
523
|
-
def add_rspack_dependencies
|
|
524
|
-
puts "Installing Rspack core dependencies..."
|
|
525
|
-
rspack_deps = %w[
|
|
526
|
-
@rspack/core
|
|
527
|
-
rspack-manifest-plugin
|
|
528
|
-
]
|
|
529
|
-
if add_npm_dependencies(rspack_deps)
|
|
530
|
-
@added_dependencies_to_package_json = true
|
|
531
|
-
return
|
|
532
|
-
end
|
|
533
|
-
|
|
534
|
-
success = system("npm", "install", *rspack_deps)
|
|
535
|
-
@ran_direct_installs = true if success
|
|
536
|
-
handle_npm_failure("Rspack dependencies", rspack_deps) unless success
|
|
537
|
-
end
|
|
538
|
-
|
|
539
|
-
def add_dev_dependencies
|
|
540
|
-
puts "Installing development dependencies..."
|
|
541
|
-
dev_deps = if options.rspack?
|
|
542
|
-
%w[
|
|
543
|
-
@rspack/cli
|
|
544
|
-
@rspack/plugin-react-refresh
|
|
545
|
-
react-refresh
|
|
546
|
-
]
|
|
547
|
-
else
|
|
548
|
-
%w[
|
|
549
|
-
@pmmmwh/react-refresh-webpack-plugin
|
|
550
|
-
react-refresh
|
|
551
|
-
]
|
|
552
|
-
end
|
|
553
|
-
if add_npm_dependencies(dev_deps, dev: true)
|
|
554
|
-
@added_dependencies_to_package_json = true
|
|
555
|
-
return
|
|
556
|
-
end
|
|
557
|
-
|
|
558
|
-
success = system("npm", "install", "--save-dev", *dev_deps)
|
|
559
|
-
@ran_direct_installs = true if success
|
|
560
|
-
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
|
|
561
|
-
end
|
|
562
|
-
|
|
563
|
-
def install_js_dependencies
|
|
564
|
-
# Detect which package manager to use
|
|
565
|
-
success = if File.exist?(File.join(destination_root, "yarn.lock"))
|
|
566
|
-
system("yarn", "install")
|
|
567
|
-
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
|
|
568
|
-
system("pnpm", "install")
|
|
569
|
-
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
|
|
570
|
-
File.exist?(File.join(destination_root, "package.json"))
|
|
571
|
-
# Use npm for package-lock.json or as default fallback
|
|
572
|
-
system("npm", "install")
|
|
573
|
-
else
|
|
574
|
-
true # No package manager detected, skip
|
|
575
|
-
end
|
|
576
|
-
|
|
577
|
-
unless success
|
|
578
|
-
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
579
|
-
⚠️ JavaScript dependencies installation failed.
|
|
580
|
-
|
|
581
|
-
This could be due to network issues or missing package manager.
|
|
582
|
-
You can install dependencies manually later by running:
|
|
583
|
-
• npm install (if using npm)
|
|
584
|
-
• yarn install (if using yarn)
|
|
585
|
-
• pnpm install (if using pnpm)
|
|
586
|
-
MSG
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
success
|
|
590
|
-
end
|
|
591
|
-
|
|
592
|
-
def handle_npm_failure(dependency_type, packages, dev: false)
|
|
593
|
-
install_command = dev ? "npm install --save-dev" : "npm install"
|
|
594
|
-
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
595
|
-
⚠️ Failed to install #{dependency_type}.
|
|
596
|
-
|
|
597
|
-
The following packages could not be installed automatically:
|
|
598
|
-
#{packages.map { |pkg| " • #{pkg}" }.join("\n")}
|
|
599
|
-
|
|
600
|
-
This could be due to network issues or missing package manager.
|
|
601
|
-
You can install them manually later by running:
|
|
602
|
-
#{install_command} #{packages.join(' ')}
|
|
603
|
-
MSG
|
|
604
|
-
end
|
|
605
|
-
|
|
606
431
|
# Removed: Shakapacker auto-installation logic (now explicit dependency)
|
|
607
432
|
|
|
608
433
|
# Removed: Shakapacker 8+ is now required as explicit dependency
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "generator_messages"
|
|
4
|
+
|
|
5
|
+
# rubocop:disable Metrics/ModuleLength
|
|
6
|
+
module ReactOnRails
|
|
7
|
+
module Generators
|
|
8
|
+
# Shared module for managing JavaScript dependencies across generators
|
|
9
|
+
# This module provides common functionality for adding and installing
|
|
10
|
+
# JS dependencies to avoid code duplication between generators.
|
|
11
|
+
#
|
|
12
|
+
# Since react_on_rails requires shakapacker, and shakapacker includes
|
|
13
|
+
# package_json as a dependency, the package_json gem is always available.
|
|
14
|
+
#
|
|
15
|
+
# == Required Methods
|
|
16
|
+
# Including classes must include GeneratorHelper module which provides:
|
|
17
|
+
# - add_npm_dependencies(packages, dev: false): Add packages via package_json gem
|
|
18
|
+
# - package_json: Access to PackageJson instance (always available via shakapacker)
|
|
19
|
+
# - destination_root: Generator destination directory
|
|
20
|
+
#
|
|
21
|
+
# == Optional Methods
|
|
22
|
+
# Including classes may define:
|
|
23
|
+
# - options.rspack?: Returns true if --rspack flag is set (for Rspack support)
|
|
24
|
+
# - options.typescript?: Returns true if --typescript flag is set (for TypeScript support)
|
|
25
|
+
#
|
|
26
|
+
# == Installation Behavior
|
|
27
|
+
# The module ALWAYS runs package manager install after adding dependencies.
|
|
28
|
+
# This is safe because package_json gem's install method is idempotent - it only
|
|
29
|
+
# installs what's actually needed from package.json. This prevents edge cases
|
|
30
|
+
# where package.json was modified but dependencies weren't installed.
|
|
31
|
+
#
|
|
32
|
+
# == Error Handling Philosophy
|
|
33
|
+
# All dependency addition methods use a graceful degradation approach:
|
|
34
|
+
# - Methods return false on failure instead of raising exceptions
|
|
35
|
+
# - StandardError is caught at the lowest level (add_package) and higher levels (add_*_dependencies)
|
|
36
|
+
# - Failures trigger user-facing warnings via GeneratorMessages
|
|
37
|
+
# - Warnings provide clear manual installation instructions
|
|
38
|
+
#
|
|
39
|
+
# This ensures the generator ALWAYS completes successfully, even when:
|
|
40
|
+
# - Network connectivity issues prevent package downloads
|
|
41
|
+
# - Package manager (npm/yarn/pnpm) has permission errors
|
|
42
|
+
# - package_json gem encounters unexpected states
|
|
43
|
+
#
|
|
44
|
+
# Users can manually run package installation commands after generator completion.
|
|
45
|
+
# This is preferable to generator crashes that leave Rails apps in incomplete states.
|
|
46
|
+
#
|
|
47
|
+
# == Usage
|
|
48
|
+
# Include this module in generator classes and call setup_js_dependencies
|
|
49
|
+
# to handle all JS dependency installation via package_json gem.
|
|
50
|
+
module JsDependencyManager
|
|
51
|
+
# Core React dependencies required for React on Rails
|
|
52
|
+
# Note: @babel/preset-react and babel plugins are NOT included here because:
|
|
53
|
+
# - Shakapacker handles JavaScript transpiler configuration (babel, swc, or esbuild)
|
|
54
|
+
# - Users configure their preferred transpiler via shakapacker.yml javascript_transpiler setting
|
|
55
|
+
# - SWC is now the default and doesn't need Babel presets
|
|
56
|
+
# - For Babel users, shakapacker will install babel-loader and its dependencies
|
|
57
|
+
REACT_DEPENDENCIES = %w[
|
|
58
|
+
react
|
|
59
|
+
react-dom
|
|
60
|
+
prop-types
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
# CSS processing dependencies for webpack
|
|
64
|
+
CSS_DEPENDENCIES = %w[
|
|
65
|
+
css-loader
|
|
66
|
+
css-minimizer-webpack-plugin
|
|
67
|
+
mini-css-extract-plugin
|
|
68
|
+
style-loader
|
|
69
|
+
].freeze
|
|
70
|
+
|
|
71
|
+
# Development-only dependencies for hot reloading (Webpack)
|
|
72
|
+
DEV_DEPENDENCIES = %w[
|
|
73
|
+
@pmmmwh/react-refresh-webpack-plugin
|
|
74
|
+
react-refresh
|
|
75
|
+
].freeze
|
|
76
|
+
|
|
77
|
+
# Rspack core dependencies (only installed when --rspack flag is used)
|
|
78
|
+
RSPACK_DEPENDENCIES = %w[
|
|
79
|
+
@rspack/core
|
|
80
|
+
rspack-manifest-plugin
|
|
81
|
+
].freeze
|
|
82
|
+
|
|
83
|
+
# Rspack development dependencies for hot reloading
|
|
84
|
+
RSPACK_DEV_DEPENDENCIES = %w[
|
|
85
|
+
@rspack/cli
|
|
86
|
+
@rspack/plugin-react-refresh
|
|
87
|
+
react-refresh
|
|
88
|
+
].freeze
|
|
89
|
+
|
|
90
|
+
# TypeScript dependencies (only installed when --typescript flag is used)
|
|
91
|
+
# Note: @babel/preset-typescript is NOT included because:
|
|
92
|
+
# - SWC is now the default javascript_transpiler (has built-in TypeScript support)
|
|
93
|
+
# - Shakapacker handles the transpiler configuration via shakapacker.yml
|
|
94
|
+
# - If users choose javascript_transpiler: 'babel', they should manually add @babel/preset-typescript
|
|
95
|
+
# and configure it in their babel.config.js
|
|
96
|
+
TYPESCRIPT_DEPENDENCIES = %w[
|
|
97
|
+
typescript
|
|
98
|
+
@types/react
|
|
99
|
+
@types/react-dom
|
|
100
|
+
].freeze
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def setup_js_dependencies
|
|
105
|
+
add_js_dependencies
|
|
106
|
+
|
|
107
|
+
# Always run install to ensure all dependencies are properly installed.
|
|
108
|
+
# The package_json gem's install method is idempotent and safe to call
|
|
109
|
+
# even if packages were already added - it will only install what's needed.
|
|
110
|
+
# This ensures edge cases where package.json was modified but install wasn't
|
|
111
|
+
# run are handled correctly.
|
|
112
|
+
install_js_dependencies
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def add_js_dependencies
|
|
116
|
+
add_react_on_rails_package
|
|
117
|
+
add_react_dependencies
|
|
118
|
+
add_css_dependencies
|
|
119
|
+
# Rspack dependencies are only added when --rspack flag is used
|
|
120
|
+
add_rspack_dependencies if respond_to?(:options) && options&.rspack?
|
|
121
|
+
# Dev dependencies vary based on bundler choice
|
|
122
|
+
add_dev_dependencies
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def add_react_on_rails_package
|
|
126
|
+
# Use exact version match between gem and npm package for all versions including pre-releases
|
|
127
|
+
# Ruby gem versions use dots (16.2.0.beta.10) but npm requires hyphens (16.2.0-beta.10)
|
|
128
|
+
# This method converts between the two formats.
|
|
129
|
+
#
|
|
130
|
+
# The regex matches:
|
|
131
|
+
# - Stable: 16.2.0
|
|
132
|
+
# - Beta (Ruby): 16.2.0.beta.10 or (npm): 16.2.0-beta.10
|
|
133
|
+
# - RC (Ruby): 16.1.0.rc.1 or (npm): 16.1.0-rc.1
|
|
134
|
+
# - Alpha (Ruby): 16.0.0.alpha.5 or (npm): 16.0.0-alpha.5
|
|
135
|
+
# This ensures beta/rc versions use the exact version instead of "latest" which would
|
|
136
|
+
# install the latest stable release and cause version mismatches.
|
|
137
|
+
|
|
138
|
+
# Accept both dot and hyphen separators for pre-release versions
|
|
139
|
+
version_with_optional_prerelease = /\A(\d+\.\d+\.\d+)([-.]([a-zA-Z0-9.]+))?\z/
|
|
140
|
+
|
|
141
|
+
react_on_rails_pkg = if (match = ReactOnRails::VERSION.match(version_with_optional_prerelease))
|
|
142
|
+
base_version = match[1]
|
|
143
|
+
prerelease = match[3]
|
|
144
|
+
|
|
145
|
+
# Convert Ruby gem format (dot) to npm semver format (hyphen)
|
|
146
|
+
npm_version = if prerelease
|
|
147
|
+
"#{base_version}-#{prerelease}"
|
|
148
|
+
else
|
|
149
|
+
base_version
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
"react-on-rails@#{npm_version}"
|
|
153
|
+
else
|
|
154
|
+
puts "WARNING: Unrecognized version format #{ReactOnRails::VERSION}. " \
|
|
155
|
+
"Adding the latest react-on-rails NPM module. " \
|
|
156
|
+
"Double check this is correct in package.json"
|
|
157
|
+
"react-on-rails"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
puts "Installing React on Rails package..."
|
|
161
|
+
return if add_package(react_on_rails_pkg)
|
|
162
|
+
|
|
163
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
164
|
+
⚠️ Failed to add react-on-rails package.
|
|
165
|
+
|
|
166
|
+
You can install it manually by running:
|
|
167
|
+
npm install #{react_on_rails_pkg}
|
|
168
|
+
MSG
|
|
169
|
+
rescue StandardError => e
|
|
170
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
171
|
+
⚠️ Error adding react-on-rails package: #{e.message}
|
|
172
|
+
|
|
173
|
+
You can install it manually by running:
|
|
174
|
+
npm install #{react_on_rails_pkg}
|
|
175
|
+
MSG
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def add_react_dependencies
|
|
179
|
+
puts "Installing React dependencies..."
|
|
180
|
+
return if add_packages(REACT_DEPENDENCIES)
|
|
181
|
+
|
|
182
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
183
|
+
⚠️ Failed to add React dependencies.
|
|
184
|
+
|
|
185
|
+
You can install them manually by running:
|
|
186
|
+
npm install #{REACT_DEPENDENCIES.join(' ')}
|
|
187
|
+
MSG
|
|
188
|
+
rescue StandardError => e
|
|
189
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
190
|
+
⚠️ Error adding React dependencies: #{e.message}
|
|
191
|
+
|
|
192
|
+
You can install them manually by running:
|
|
193
|
+
npm install #{REACT_DEPENDENCIES.join(' ')}
|
|
194
|
+
MSG
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def add_css_dependencies
|
|
198
|
+
puts "Installing CSS handling dependencies..."
|
|
199
|
+
return if add_packages(CSS_DEPENDENCIES)
|
|
200
|
+
|
|
201
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
202
|
+
⚠️ Failed to add CSS dependencies.
|
|
203
|
+
|
|
204
|
+
You can install them manually by running:
|
|
205
|
+
npm install #{CSS_DEPENDENCIES.join(' ')}
|
|
206
|
+
MSG
|
|
207
|
+
rescue StandardError => e
|
|
208
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
209
|
+
⚠️ Error adding CSS dependencies: #{e.message}
|
|
210
|
+
|
|
211
|
+
You can install them manually by running:
|
|
212
|
+
npm install #{CSS_DEPENDENCIES.join(' ')}
|
|
213
|
+
MSG
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def add_rspack_dependencies
|
|
217
|
+
puts "Installing Rspack core dependencies..."
|
|
218
|
+
return if add_packages(RSPACK_DEPENDENCIES)
|
|
219
|
+
|
|
220
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
221
|
+
⚠️ Failed to add Rspack dependencies.
|
|
222
|
+
|
|
223
|
+
You can install them manually by running:
|
|
224
|
+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
|
|
225
|
+
MSG
|
|
226
|
+
rescue StandardError => e
|
|
227
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
228
|
+
⚠️ Error adding Rspack dependencies: #{e.message}
|
|
229
|
+
|
|
230
|
+
You can install them manually by running:
|
|
231
|
+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
|
|
232
|
+
MSG
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def add_typescript_dependencies
|
|
236
|
+
puts "Installing TypeScript dependencies..."
|
|
237
|
+
return if add_packages(TYPESCRIPT_DEPENDENCIES, dev: true)
|
|
238
|
+
|
|
239
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
240
|
+
⚠️ Failed to add TypeScript dependencies.
|
|
241
|
+
|
|
242
|
+
You can install them manually by running:
|
|
243
|
+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
|
|
244
|
+
MSG
|
|
245
|
+
rescue StandardError => e
|
|
246
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
247
|
+
⚠️ Error adding TypeScript dependencies: #{e.message}
|
|
248
|
+
|
|
249
|
+
You can install them manually by running:
|
|
250
|
+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
|
|
251
|
+
MSG
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def add_dev_dependencies
|
|
255
|
+
puts "Installing development dependencies..."
|
|
256
|
+
|
|
257
|
+
# Use Rspack-specific dev dependencies if --rspack flag is set
|
|
258
|
+
dev_deps = if respond_to?(:options) && options&.rspack?
|
|
259
|
+
RSPACK_DEV_DEPENDENCIES
|
|
260
|
+
else
|
|
261
|
+
DEV_DEPENDENCIES
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
return if add_packages(dev_deps, dev: true)
|
|
265
|
+
|
|
266
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
267
|
+
⚠️ Failed to add development dependencies.
|
|
268
|
+
|
|
269
|
+
You can install them manually by running:
|
|
270
|
+
npm install --save-dev #{dev_deps.join(' ')}
|
|
271
|
+
MSG
|
|
272
|
+
rescue StandardError => e
|
|
273
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
274
|
+
⚠️ Error adding development dependencies: #{e.message}
|
|
275
|
+
|
|
276
|
+
You can install them manually by running:
|
|
277
|
+
npm install --save-dev #{dev_deps.join(' ')}
|
|
278
|
+
MSG
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# Add a single dependency using package_json gem
|
|
282
|
+
#
|
|
283
|
+
# This method is used internally for adding the react-on-rails package
|
|
284
|
+
# with version-specific handling (react-on-rails@VERSION).
|
|
285
|
+
# For batch operations, use add_packages instead.
|
|
286
|
+
#
|
|
287
|
+
# The exact: true flag ensures version pinning aligns with the gem version,
|
|
288
|
+
# preventing version mismatches between the Ruby gem and NPM package.
|
|
289
|
+
#
|
|
290
|
+
# @param package [String] Package specifier (e.g., "react-on-rails@16.0.0")
|
|
291
|
+
# @param dev [Boolean] Whether to add as dev dependency
|
|
292
|
+
# @return [Boolean] true if successful, false otherwise
|
|
293
|
+
def add_package(package, dev: false)
|
|
294
|
+
pj = package_json
|
|
295
|
+
return false unless pj
|
|
296
|
+
|
|
297
|
+
begin
|
|
298
|
+
# Ensure package is in array format for package_json gem
|
|
299
|
+
packages_array = [package]
|
|
300
|
+
if dev
|
|
301
|
+
pj.manager.add(packages_array, type: :dev, exact: true)
|
|
302
|
+
else
|
|
303
|
+
pj.manager.add(packages_array, exact: true)
|
|
304
|
+
end
|
|
305
|
+
true
|
|
306
|
+
rescue StandardError
|
|
307
|
+
# Return false to trigger warning in calling method
|
|
308
|
+
false
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Add multiple dependencies at once using package_json gem
|
|
313
|
+
#
|
|
314
|
+
# This method delegates to GeneratorHelper's add_npm_dependencies for
|
|
315
|
+
# better package manager abstraction and batch processing efficiency.
|
|
316
|
+
#
|
|
317
|
+
# @param packages [Array<String>] Package names to add
|
|
318
|
+
# @param dev [Boolean] Whether to add as dev dependencies
|
|
319
|
+
# @return [Boolean] true if successful, false otherwise
|
|
320
|
+
def add_packages(packages, dev: false)
|
|
321
|
+
# Use the add_npm_dependencies helper from GeneratorHelper
|
|
322
|
+
add_npm_dependencies(packages, dev: dev)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def install_js_dependencies
|
|
326
|
+
# Use package_json gem's install method (always available via shakapacker)
|
|
327
|
+
# package_json is guaranteed to be available because:
|
|
328
|
+
# 1. react_on_rails gemspec requires shakapacker
|
|
329
|
+
# 2. shakapacker gemspec requires package_json
|
|
330
|
+
# 3. GeneratorHelper provides package_json method
|
|
331
|
+
pj = package_json
|
|
332
|
+
unless pj
|
|
333
|
+
GeneratorMessages.add_warning("package_json not available, skipping dependency installation")
|
|
334
|
+
return false
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
pj.manager.install
|
|
338
|
+
true
|
|
339
|
+
rescue StandardError => e
|
|
340
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
341
|
+
⚠️ JavaScript dependencies installation failed: #{e.message}
|
|
342
|
+
|
|
343
|
+
This could be due to network issues or package manager problems.
|
|
344
|
+
You can install dependencies manually later by running:
|
|
345
|
+
• npm install (if using npm)
|
|
346
|
+
• yarn install (if using yarn)
|
|
347
|
+
• pnpm install (if using pnpm)
|
|
348
|
+
MSG
|
|
349
|
+
false
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
# rubocop:enable Metrics/ModuleLength
|
data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt
CHANGED
|
@@ -12,6 +12,25 @@ ReactOnRails.configure do |config|
|
|
|
12
12
|
# Set to "" if you're not using server rendering
|
|
13
13
|
config.server_bundle_js_file = "server-bundle.js"
|
|
14
14
|
|
|
15
|
+
# ⚠️ RECOMMENDED: Use Shakapacker 9.0+ private_output_path instead
|
|
16
|
+
#
|
|
17
|
+
# If using Shakapacker 9.0+, add to config/shakapacker.yml:
|
|
18
|
+
# private_output_path: ssr-generated
|
|
19
|
+
#
|
|
20
|
+
# React on Rails will auto-detect this value, eliminating the need to set it here.
|
|
21
|
+
# This keeps your webpack and Rails configs in sync automatically.
|
|
22
|
+
#
|
|
23
|
+
# For older Shakapacker versions or custom setups, manually configure:
|
|
24
|
+
# config.server_bundle_output_path = "ssr-generated"
|
|
25
|
+
#
|
|
26
|
+
# The path is relative to Rails.root and should point to a private directory
|
|
27
|
+
# (outside of public/) for security. Run 'rails react_on_rails:doctor' to verify.
|
|
28
|
+
|
|
29
|
+
# Enforce that server bundles are only loaded from private (non-public) directories.
|
|
30
|
+
# When true, server bundles will only be loaded from the configured server_bundle_output_path.
|
|
31
|
+
# This is recommended for production to prevent server-side code from being exposed.
|
|
32
|
+
config.enforce_private_server_bundles = true
|
|
33
|
+
|
|
15
34
|
################################################################################
|
|
16
35
|
# Test Configuration (Optional)
|
|
17
36
|
################################################################################
|
data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt}
RENAMED
|
@@ -29,6 +29,15 @@ default: &default
|
|
|
29
29
|
# Location for manifest.json, defaults to {public_output_path}/manifest.json if unset
|
|
30
30
|
# manifest_path: public/packs/manifest.json
|
|
31
31
|
|
|
32
|
+
# Location for private server-side bundles (e.g., for SSR)
|
|
33
|
+
# These bundles are not served publicly, unlike public_output_path
|
|
34
|
+
# Shakapacker 9.0+ feature - automatically detected by React on Rails
|
|
35
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
36
|
+
private_output_path: ssr-generated
|
|
37
|
+
<% else -%>
|
|
38
|
+
# private_output_path: ssr-generated # Uncomment to enable (requires Shakapacker 9.0+)
|
|
39
|
+
<% end -%>
|
|
40
|
+
|
|
32
41
|
# Additional paths webpack should look up modules
|
|
33
42
|
# ['app/assets', 'engine/foo/app/assets']
|
|
34
43
|
additional_paths: []
|
|
@@ -36,8 +45,15 @@ default: &default
|
|
|
36
45
|
# Reload manifest.json on all requests so we reload latest compiled packs
|
|
37
46
|
cache_manifest: false
|
|
38
47
|
|
|
39
|
-
# Select
|
|
40
|
-
|
|
48
|
+
# Select JavaScript transpiler to use
|
|
49
|
+
# Available options: 'swc' (default, 20x faster), 'babel', 'esbuild', or 'none'
|
|
50
|
+
# Use 'none' when providing a completely custom webpack configuration
|
|
51
|
+
# Note: When using rspack, swc is used automatically regardless of this setting
|
|
52
|
+
javascript_transpiler: "swc"
|
|
53
|
+
|
|
54
|
+
# Select assets bundler to use
|
|
55
|
+
# Available options: 'webpack' (default) or 'rspack'
|
|
56
|
+
assets_bundler: "webpack"
|
|
41
57
|
|
|
42
58
|
# Raises an error if there is a mismatch in the shakapacker gem and npm package being used
|
|
43
59
|
ensure_consistent_versioning: true
|