react_on_rails 16.2.0.beta.10 ā 16.2.0.beta.12
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 +14 -21
- data/CLAUDE.md +180 -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/analysis/v8-crash-retry-solution.md +148 -0
- data/bin/ci-run-failed-specs +6 -4
- data/bin/ci-switch-config +4 -3
- data/lib/generators/react_on_rails/base_generator.rb +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +29 -0
- data/lib/generators/react_on_rails/js_dependency_manager.rb +29 -7
- 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} +9 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +38 -4
- data/lib/react_on_rails/configuration.rb +89 -10
- data/lib/react_on_rails/dev/pack_generator.rb +49 -11
- 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/helper.rb +32 -5
- data/lib/react_on_rails/packs_generator.rb +47 -35
- 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/lib/tasks/generate_packs.rake +12 -6
- data/react_on_rails_pro/CHANGELOG.md +11 -4
- data/react_on_rails_pro/Gemfile.lock +3 -3
- data/react_on_rails_pro/app/helpers/react_on_rails_pro_helper.rb +2 -1
- 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/spec/helpers/react_on_rails_pro_helper_spec.rb +15 -7
- data/react_on_rails_pro/spec/dummy/spec/requests/renderer_console_logging_spec.rb +9 -4
- 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
- metadata +9 -3
data/bin/ci-run-failed-specs
CHANGED
|
@@ -139,10 +139,12 @@ echo ""
|
|
|
139
139
|
|
|
140
140
|
# Determine the working directory (check if we need to be in spec/dummy)
|
|
141
141
|
WORKING_DIR="."
|
|
142
|
-
if [ ${#UNIQUE_SPECS[@]} -gt 0 ]
|
|
143
|
-
if [
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
if [ ${#UNIQUE_SPECS[@]} -gt 0 ]; then
|
|
143
|
+
if [[ "${UNIQUE_SPECS[0]}" == *"spec/system"* ]] || [[ "${UNIQUE_SPECS[0]}" == *"spec/helpers"* ]]; then
|
|
144
|
+
if [ -d "spec/dummy" ]; then
|
|
145
|
+
WORKING_DIR="spec/dummy"
|
|
146
|
+
echo -e "${BLUE}Running from spec/dummy directory${NC}"
|
|
147
|
+
fi
|
|
146
148
|
fi
|
|
147
149
|
fi
|
|
148
150
|
|
data/bin/ci-switch-config
CHANGED
|
@@ -255,9 +255,10 @@ EOF
|
|
|
255
255
|
set_node_version "20.18.1" "$VERSION_MANAGER"
|
|
256
256
|
|
|
257
257
|
# Run conversion script
|
|
258
|
-
# NOTE: This
|
|
259
|
-
# The
|
|
260
|
-
#
|
|
258
|
+
# NOTE: This executes 'ruby' before the version manager reloads in your current shell.
|
|
259
|
+
# The script/convert file requires Ruby 2.6+ and uses basic file I/O operations.
|
|
260
|
+
# Most modern Ruby versions (2.6+) are compatible. The version manager changes above
|
|
261
|
+
# only take effect after shell reload, so this uses your current Ruby installation.
|
|
261
262
|
print_header "Running script/convert to downgrade dependencies"
|
|
262
263
|
cd "$PROJECT_ROOT"
|
|
263
264
|
ruby script/convert
|
|
@@ -101,7 +101,8 @@ module ReactOnRails
|
|
|
101
101
|
puts "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
|
|
102
102
|
base_path = "base/base/"
|
|
103
103
|
config = "config/shakapacker.yml"
|
|
104
|
-
|
|
104
|
+
# Use template to enable version-aware configuration
|
|
105
|
+
template("#{base_path}#{config}.tt", config)
|
|
105
106
|
configure_rspack_in_shakapacker if options.rspack?
|
|
106
107
|
end
|
|
107
108
|
|
|
@@ -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
|
|
@@ -123,14 +123,36 @@ module ReactOnRails
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
def add_react_on_rails_package
|
|
126
|
-
# Use exact version match between gem and npm package for
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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}"
|
|
132
153
|
else
|
|
133
|
-
puts "
|
|
154
|
+
puts "WARNING: Unrecognized version format #{ReactOnRails::VERSION}. " \
|
|
155
|
+
"Adding the latest react-on-rails NPM module. " \
|
|
134
156
|
"Double check this is correct in package.json"
|
|
135
157
|
"react-on-rails"
|
|
136
158
|
end
|
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
|
################################################################################
|
|
@@ -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: []
|
data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt
CHANGED
|
@@ -44,19 +44,53 @@ const configureServer = () => {
|
|
|
44
44
|
};
|
|
45
45
|
serverWebpackConfig.plugins.unshift(new bundler.optimize.LimitChunkCountPlugin({ maxChunks: 1 }));
|
|
46
46
|
|
|
47
|
-
// Custom output for the server-bundle
|
|
48
|
-
|
|
49
|
-
//
|
|
47
|
+
// Custom output for the server-bundle
|
|
48
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
49
|
+
// Using Shakapacker 9.0+ privateOutputPath for automatic sync with shakapacker.yml
|
|
50
|
+
// This eliminates manual path configuration and keeps configs in sync.
|
|
51
|
+
// Falls back to hardcoded path if private_output_path is not configured.
|
|
52
|
+
const serverBundleOutputPath = config.privateOutputPath ||
|
|
53
|
+
require('path').resolve(__dirname, '../../ssr-generated');
|
|
54
|
+
<% else -%>
|
|
55
|
+
// Using hardcoded path (Shakapacker < 9.0)
|
|
56
|
+
// For Shakapacker 9.0+, consider using config.privateOutputPath instead
|
|
57
|
+
// to automatically sync with shakapacker.yml private_output_path.
|
|
58
|
+
const serverBundleOutputPath = require('path').resolve(__dirname, '../../ssr-generated');
|
|
59
|
+
<% end -%>
|
|
60
|
+
|
|
50
61
|
serverWebpackConfig.output = {
|
|
51
62
|
filename: 'server-bundle.js',
|
|
52
63
|
globalObject: 'this',
|
|
53
64
|
// If using the React on Rails Pro node server renderer, uncomment the next line
|
|
54
65
|
// libraryTarget: 'commonjs2',
|
|
55
|
-
path:
|
|
66
|
+
path: serverBundleOutputPath,
|
|
56
67
|
// No publicPath needed since server bundles are not served via web
|
|
57
68
|
// https://webpack.js.org/configuration/output/#outputglobalobject
|
|
58
69
|
};
|
|
59
70
|
|
|
71
|
+
// Validate server bundle output path configuration
|
|
72
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
73
|
+
// For Shakapacker 9.0+, verify privateOutputPath is configured in shakapacker.yml
|
|
74
|
+
if (!config.privateOutputPath) {
|
|
75
|
+
console.warn('ā ļø Shakapacker 9.0+ detected but private_output_path not configured in shakapacker.yml');
|
|
76
|
+
console.warn(' Add to config/shakapacker.yml:');
|
|
77
|
+
console.warn(' private_output_path: ssr-generated');
|
|
78
|
+
console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
|
|
79
|
+
}
|
|
80
|
+
<% else -%>
|
|
81
|
+
// For Shakapacker < 9.0, verify hardcoded path syncs with Rails config
|
|
82
|
+
// 1. Ensure config/initializers/react_on_rails.rb has: config.server_bundle_output_path = "ssr-generated"
|
|
83
|
+
// 2. Run: rails react_on_rails:doctor to verify configuration
|
|
84
|
+
const fs = require('fs');
|
|
85
|
+
if (!fs.existsSync(serverBundleOutputPath)) {
|
|
86
|
+
console.warn(`ā ļø Server bundle output directory does not exist: ${serverBundleOutputPath}`);
|
|
87
|
+
console.warn(' It will be created during build, but ensure React on Rails is configured:');
|
|
88
|
+
console.warn(' config.server_bundle_output_path = "ssr-generated" in config/initializers/react_on_rails.rb');
|
|
89
|
+
console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
|
|
90
|
+
}
|
|
91
|
+
<% end -%>
|
|
92
|
+
|
|
93
|
+
|
|
60
94
|
// Don't hash the server bundle b/c would conflict with the client manifest
|
|
61
95
|
// And no need for the MiniCssExtractPlugin
|
|
62
96
|
serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter(
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
require "active_support/core_ext/object/blank"
|
|
5
|
+
|
|
6
|
+
# Polyfill for compact_blank (added in Rails 6.1) to support Rails 5.2-6.0
|
|
7
|
+
unless [].respond_to?(:compact_blank)
|
|
8
|
+
module Enumerable
|
|
9
|
+
def compact_blank
|
|
10
|
+
reject(&:blank?)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Array
|
|
15
|
+
def compact_blank
|
|
16
|
+
reject(&:blank?)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
3
21
|
# rubocop:disable Metrics/ClassLength
|
|
4
22
|
|
|
5
23
|
module ReactOnRails
|
|
@@ -10,6 +28,7 @@ module ReactOnRails
|
|
|
10
28
|
|
|
11
29
|
DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
|
|
12
30
|
DEFAULT_COMPONENT_REGISTRY_TIMEOUT = 5000
|
|
31
|
+
DEFAULT_SERVER_BUNDLE_OUTPUT_PATH = "ssr-generated"
|
|
13
32
|
|
|
14
33
|
def self.configuration
|
|
15
34
|
@configuration ||= Configuration.new(
|
|
@@ -46,7 +65,7 @@ module ReactOnRails
|
|
|
46
65
|
# Set to 0 to disable the timeout and wait indefinitely for component registration.
|
|
47
66
|
component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT,
|
|
48
67
|
generated_component_packs_loading_strategy: nil,
|
|
49
|
-
server_bundle_output_path:
|
|
68
|
+
server_bundle_output_path: DEFAULT_SERVER_BUNDLE_OUTPUT_PATH,
|
|
50
69
|
enforce_private_server_bundles: false
|
|
51
70
|
)
|
|
52
71
|
end
|
|
@@ -184,6 +203,7 @@ module ReactOnRails
|
|
|
184
203
|
check_component_registry_timeout
|
|
185
204
|
validate_generated_component_packs_loading_strategy
|
|
186
205
|
validate_enforce_private_server_bundles
|
|
206
|
+
auto_detect_server_bundle_path_from_shakapacker
|
|
187
207
|
end
|
|
188
208
|
|
|
189
209
|
private
|
|
@@ -257,6 +277,57 @@ module ReactOnRails
|
|
|
257
277
|
"the public directory. Please set it to a directory outside of public."
|
|
258
278
|
end
|
|
259
279
|
|
|
280
|
+
# Auto-detect server_bundle_output_path from Shakapacker 9.0+ private_output_path
|
|
281
|
+
# Checks if user explicitly set a value and warns them to use auto-detection instead
|
|
282
|
+
def auto_detect_server_bundle_path_from_shakapacker
|
|
283
|
+
# Skip if Shakapacker is not available
|
|
284
|
+
return unless defined?(::Shakapacker)
|
|
285
|
+
|
|
286
|
+
# Check if Shakapacker config has private_output_path method (9.0+)
|
|
287
|
+
return unless ::Shakapacker.config.respond_to?(:private_output_path)
|
|
288
|
+
|
|
289
|
+
# Get the private_output_path from Shakapacker
|
|
290
|
+
private_path = ::Shakapacker.config.private_output_path
|
|
291
|
+
return unless private_path
|
|
292
|
+
|
|
293
|
+
relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
|
|
294
|
+
|
|
295
|
+
# Check if user explicitly configured server_bundle_output_path
|
|
296
|
+
if server_bundle_output_path != ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
|
|
297
|
+
warn_about_explicit_configuration(relative_path)
|
|
298
|
+
return
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
apply_shakapacker_private_output_path(relative_path)
|
|
302
|
+
rescue StandardError => e
|
|
303
|
+
# Fail gracefully - if auto-detection fails, keep the default
|
|
304
|
+
Rails.logger&.debug("ReactOnRails: Could not auto-detect server bundle path from " \
|
|
305
|
+
"Shakapacker: #{e.message}")
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def warn_about_explicit_configuration(shakapacker_path)
|
|
309
|
+
# Normalize both paths for comparison
|
|
310
|
+
normalized_config = server_bundle_output_path.to_s.chomp("/")
|
|
311
|
+
normalized_shakapacker = shakapacker_path.to_s.chomp("/")
|
|
312
|
+
|
|
313
|
+
# Only warn if there's a mismatch
|
|
314
|
+
return if normalized_config == normalized_shakapacker
|
|
315
|
+
|
|
316
|
+
Rails.logger&.warn(
|
|
317
|
+
"ReactOnRails: server_bundle_output_path is explicitly set to '#{server_bundle_output_path}' " \
|
|
318
|
+
"but shakapacker.yml private_output_path is '#{shakapacker_path}'. " \
|
|
319
|
+
"Consider removing server_bundle_output_path from your React on Rails initializer " \
|
|
320
|
+
"to use the auto-detected value from shakapacker.yml."
|
|
321
|
+
)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def apply_shakapacker_private_output_path(relative_path)
|
|
325
|
+
self.server_bundle_output_path = relative_path
|
|
326
|
+
|
|
327
|
+
Rails.logger&.debug("ReactOnRails: Auto-detected server_bundle_output_path from " \
|
|
328
|
+
"shakapacker.yml private_output_path: '#{relative_path}'")
|
|
329
|
+
end
|
|
330
|
+
|
|
260
331
|
def check_minimum_shakapacker_version
|
|
261
332
|
ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_basic_pack_generation unless
|
|
262
333
|
ReactOnRails::PackerUtils.supports_basic_pack_generation?
|
|
@@ -358,15 +429,23 @@ module ReactOnRails
|
|
|
358
429
|
end
|
|
359
430
|
|
|
360
431
|
def ensure_webpack_generated_files_exists
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
432
|
+
all_required_files = ["manifest.json", server_bundle_js_file]
|
|
433
|
+
|
|
434
|
+
if ReactOnRails::Utils.react_on_rails_pro?
|
|
435
|
+
pro_config = ReactOnRailsPro.configuration
|
|
436
|
+
all_required_files << pro_config.rsc_bundle_js_file
|
|
437
|
+
all_required_files << pro_config.react_client_manifest_file
|
|
438
|
+
all_required_files << pro_config.react_server_client_manifest_file
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
all_required_files = all_required_files.compact_blank
|
|
442
|
+
|
|
443
|
+
if webpack_generated_files.empty?
|
|
444
|
+
self.webpack_generated_files = all_required_files
|
|
445
|
+
else
|
|
446
|
+
missing_files = all_required_files.reject { |file| webpack_generated_files.include?(file) }
|
|
447
|
+
self.webpack_generated_files += missing_files if missing_files.any?
|
|
448
|
+
end
|
|
370
449
|
end
|
|
371
450
|
|
|
372
451
|
def configure_skip_display_none_deprecation
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "English"
|
|
4
4
|
require "stringio"
|
|
5
|
+
require_relative "../packer_utils"
|
|
5
6
|
|
|
6
7
|
module ReactOnRails
|
|
7
8
|
module Dev
|
|
@@ -37,29 +38,40 @@ module ReactOnRails
|
|
|
37
38
|
|
|
38
39
|
if verbose
|
|
39
40
|
puts "š¦ Generating React on Rails packs..."
|
|
40
|
-
success = run_pack_generation
|
|
41
|
+
success = run_pack_generation(silent: false, verbose: true)
|
|
41
42
|
else
|
|
42
43
|
print "š¦ Generating packs... "
|
|
43
|
-
success = run_pack_generation(silent: true)
|
|
44
|
+
success = run_pack_generation(silent: true, verbose: false)
|
|
44
45
|
puts success ? "ā
" : "ā"
|
|
45
46
|
end
|
|
46
47
|
|
|
47
48
|
return if success
|
|
48
49
|
|
|
49
50
|
puts "ā Pack generation failed"
|
|
51
|
+
unless verbose
|
|
52
|
+
puts ""
|
|
53
|
+
puts "š” Run with #{Rainbow('--verbose').cyan.bold} flag for detailed output:"
|
|
54
|
+
puts " #{Rainbow('bin/dev --verbose').green.bold}"
|
|
55
|
+
end
|
|
50
56
|
exit 1
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
private
|
|
54
60
|
|
|
55
|
-
def run_pack_generation(silent: false)
|
|
61
|
+
def run_pack_generation(silent: false, verbose: false)
|
|
62
|
+
# Set environment variable for child processes to respect verbose mode
|
|
63
|
+
ENV["REACT_ON_RAILS_VERBOSE"] = verbose ? "true" : "false"
|
|
64
|
+
|
|
56
65
|
# If we're already inside a Bundler context AND Rails is available (e.g., called from bin/dev),
|
|
57
66
|
# we can directly require and run the task. Otherwise, use bundle exec.
|
|
58
67
|
if should_run_directly?
|
|
59
68
|
run_rake_task_directly(silent: silent)
|
|
60
69
|
else
|
|
61
|
-
run_via_bundle_exec(silent: silent)
|
|
70
|
+
run_via_bundle_exec(silent: silent, verbose: verbose)
|
|
62
71
|
end
|
|
72
|
+
ensure
|
|
73
|
+
# Clean up environment variable
|
|
74
|
+
ENV.delete("REACT_ON_RAILS_VERBOSE")
|
|
63
75
|
end
|
|
64
76
|
|
|
65
77
|
def should_run_directly?
|
|
@@ -139,14 +151,40 @@ module ReactOnRails
|
|
|
139
151
|
# rubocop:enable Style/StderrPuts, Style/GlobalStdStream
|
|
140
152
|
end
|
|
141
153
|
|
|
142
|
-
def run_via_bundle_exec(silent: false)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
154
|
+
def run_via_bundle_exec(silent: false, verbose: false)
|
|
155
|
+
# Environment variable is already set in run_pack_generation, but we make it explicit here
|
|
156
|
+
# for clarity and to ensure it's passed to the subprocess
|
|
157
|
+
env = { "REACT_ON_RAILS_VERBOSE" => verbose ? "true" : "false" }
|
|
158
|
+
|
|
159
|
+
# Need to unbundle to prevent Bundler from intercepting our bundle exec call
|
|
160
|
+
# when already running inside a Bundler context (e.g., from bin/dev)
|
|
161
|
+
with_unbundled_context do
|
|
162
|
+
if silent
|
|
163
|
+
system(
|
|
164
|
+
env,
|
|
165
|
+
"bundle", "exec", "rake", "react_on_rails:generate_packs",
|
|
166
|
+
out: File::NULL, err: File::NULL
|
|
167
|
+
)
|
|
168
|
+
else
|
|
169
|
+
system(env, "bundle", "exec", "rake", "react_on_rails:generate_packs")
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# DRY helper method for Bundler context switching with API compatibility
|
|
175
|
+
# Supports both new (with_unbundled_env) and legacy (with_clean_env) Bundler APIs
|
|
176
|
+
def with_unbundled_context(&block)
|
|
177
|
+
if defined?(Bundler)
|
|
178
|
+
if Bundler.respond_to?(:with_unbundled_env)
|
|
179
|
+
Bundler.with_unbundled_env(&block)
|
|
180
|
+
elsif Bundler.respond_to?(:with_clean_env)
|
|
181
|
+
Bundler.with_clean_env(&block)
|
|
182
|
+
else
|
|
183
|
+
# Fallback if neither method is available (very old Bundler versions)
|
|
184
|
+
yield
|
|
185
|
+
end
|
|
148
186
|
else
|
|
149
|
-
|
|
187
|
+
yield
|
|
150
188
|
end
|
|
151
189
|
end
|
|
152
190
|
end
|
|
@@ -667,6 +667,7 @@ module ReactOnRails
|
|
|
667
667
|
end
|
|
668
668
|
end
|
|
669
669
|
|
|
670
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
670
671
|
def analyze_server_rendering_config(content)
|
|
671
672
|
checker.add_info("\nš„ļø Server Rendering:")
|
|
672
673
|
|
|
@@ -678,6 +679,19 @@ module ReactOnRails
|
|
|
678
679
|
checker.add_info(" server_bundle_js_file: server-bundle.js (default)")
|
|
679
680
|
end
|
|
680
681
|
|
|
682
|
+
# Server bundle output path
|
|
683
|
+
server_bundle_path_match = content.match(/config\.server_bundle_output_path\s*=\s*["']([^"']+)["']/)
|
|
684
|
+
default_path = ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
|
|
685
|
+
rails_bundle_path = server_bundle_path_match ? server_bundle_path_match[1] : default_path
|
|
686
|
+
checker.add_info(" server_bundle_output_path: #{rails_bundle_path}")
|
|
687
|
+
|
|
688
|
+
# Enforce private server bundles
|
|
689
|
+
enforce_private_match = content.match(/config\.enforce_private_server_bundles\s*=\s*([^\s\n,]+)/)
|
|
690
|
+
checker.add_info(" enforce_private_server_bundles: #{enforce_private_match[1]}") if enforce_private_match
|
|
691
|
+
|
|
692
|
+
# Check Shakapacker integration and provide recommendations
|
|
693
|
+
check_shakapacker_private_output_path(rails_bundle_path)
|
|
694
|
+
|
|
681
695
|
# RSC bundle file (Pro feature)
|
|
682
696
|
rsc_bundle_match = content.match(/config\.rsc_bundle_js_file\s*=\s*["']([^"']+)["']/)
|
|
683
697
|
if rsc_bundle_match
|
|
@@ -702,9 +716,9 @@ module ReactOnRails
|
|
|
702
716
|
|
|
703
717
|
checker.add_info(" raise_on_prerender_error: #{raise_on_error_match[1]}")
|
|
704
718
|
end
|
|
705
|
-
# rubocop:enable Metrics/
|
|
719
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
706
720
|
|
|
707
|
-
# rubocop:disable Metrics/
|
|
721
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
708
722
|
def analyze_performance_config(content)
|
|
709
723
|
checker.add_info("\nā” Performance & Loading:")
|
|
710
724
|
|
|
@@ -1387,9 +1401,85 @@ module ReactOnRails
|
|
|
1387
1401
|
end
|
|
1388
1402
|
|
|
1389
1403
|
def log_debug(message)
|
|
1390
|
-
|
|
1404
|
+
Rails.logger&.debug(message)
|
|
1405
|
+
end
|
|
1406
|
+
|
|
1407
|
+
# Check Shakapacker private_output_path integration and provide recommendations
|
|
1408
|
+
def check_shakapacker_private_output_path(rails_bundle_path)
|
|
1409
|
+
return report_no_shakapacker unless defined?(::Shakapacker)
|
|
1410
|
+
return report_upgrade_shakapacker unless ::Shakapacker.config.respond_to?(:private_output_path)
|
|
1411
|
+
|
|
1412
|
+
check_shakapacker_9_private_output_path(rails_bundle_path)
|
|
1413
|
+
rescue StandardError => e
|
|
1414
|
+
checker.add_info("\n ā¹ļø Could not check Shakapacker config: #{e.message}")
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
def report_no_shakapacker
|
|
1418
|
+
checker.add_info("\n ā¹ļø Shakapacker not detected - using manual configuration")
|
|
1419
|
+
end
|
|
1420
|
+
|
|
1421
|
+
def report_upgrade_shakapacker
|
|
1422
|
+
checker.add_info(<<~MSG.strip)
|
|
1423
|
+
\n š” Recommendation: Upgrade to Shakapacker 9.0+
|
|
1424
|
+
|
|
1425
|
+
Shakapacker 9.0+ adds 'private_output_path' in shakapacker.yml for server bundles.
|
|
1426
|
+
This eliminates the need to configure server_bundle_output_path separately.
|
|
1427
|
+
|
|
1428
|
+
Benefits:
|
|
1429
|
+
- Single source of truth in shakapacker.yml
|
|
1430
|
+
- Automatic detection by React on Rails
|
|
1431
|
+
- No configuration duplication
|
|
1432
|
+
MSG
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
def check_shakapacker_9_private_output_path(rails_bundle_path)
|
|
1436
|
+
private_path = ::Shakapacker.config.private_output_path
|
|
1437
|
+
|
|
1438
|
+
if private_path
|
|
1439
|
+
report_shakapacker_path_status(private_path, rails_bundle_path)
|
|
1440
|
+
else
|
|
1441
|
+
report_configure_private_output_path(rails_bundle_path)
|
|
1442
|
+
end
|
|
1443
|
+
end
|
|
1444
|
+
|
|
1445
|
+
def report_shakapacker_path_status(private_path, rails_bundle_path)
|
|
1446
|
+
relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
|
|
1447
|
+
# Normalize both paths for comparison (remove trailing slashes)
|
|
1448
|
+
normalized_relative = relative_path.to_s.chomp("/")
|
|
1449
|
+
normalized_rails = rails_bundle_path.to_s.chomp("/")
|
|
1450
|
+
|
|
1451
|
+
if normalized_relative == normalized_rails
|
|
1452
|
+
checker.add_success("\n ā
Using Shakapacker 9.0+ private_output_path: '#{relative_path}'")
|
|
1453
|
+
checker.add_info(" Auto-detected from shakapacker.yml - no manual config needed")
|
|
1454
|
+
else
|
|
1455
|
+
report_configuration_mismatch(relative_path, rails_bundle_path)
|
|
1456
|
+
end
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
def report_configuration_mismatch(relative_path, rails_bundle_path)
|
|
1460
|
+
checker.add_warning(<<~MSG.strip)
|
|
1461
|
+
\n ā ļø Configuration mismatch detected!
|
|
1462
|
+
|
|
1463
|
+
Shakapacker private_output_path: '#{relative_path}'
|
|
1464
|
+
React on Rails server_bundle_output_path: '#{rails_bundle_path}'
|
|
1465
|
+
|
|
1466
|
+
Recommendation: Remove server_bundle_output_path from your React on Rails
|
|
1467
|
+
initializer and let it auto-detect from shakapacker.yml private_output_path.
|
|
1468
|
+
MSG
|
|
1469
|
+
end
|
|
1470
|
+
|
|
1471
|
+
def report_configure_private_output_path(rails_bundle_path)
|
|
1472
|
+
checker.add_info(<<~MSG.strip)
|
|
1473
|
+
\n š” Recommendation: Configure private_output_path in shakapacker.yml
|
|
1474
|
+
|
|
1475
|
+
Add to config/shakapacker.yml:
|
|
1476
|
+
private_output_path: #{rails_bundle_path}
|
|
1391
1477
|
|
|
1392
|
-
|
|
1478
|
+
This will:
|
|
1479
|
+
- Keep webpack and Rails configs in sync automatically
|
|
1480
|
+
- Enable auto-detection by React on Rails
|
|
1481
|
+
- Serve as single source of truth for server bundle location
|
|
1482
|
+
MSG
|
|
1393
1483
|
end
|
|
1394
1484
|
end
|
|
1395
1485
|
# rubocop:enable Metrics/ClassLength
|