Class: ReactOnRails::SystemChecker
- Inherits:
-
Object
- Object
- ReactOnRails::SystemChecker
- Defined in:
- lib/react_on_rails/system_checker.rb
Overview
SystemChecker provides validation methods for React on Rails setup Used by install generator and doctor rake task rubocop:disable Metrics/ClassLength
Instance Attribute Summary collapse
-
#messages ⇒ Object
readonly
Returns the value of attribute messages.
Instance Method Summary collapse
- #add_error(message) ⇒ Object
- #add_info(message) ⇒ Object
- #add_success(message) ⇒ Object
- #add_warning(message) ⇒ Object
- #bundle_analyzer_available? ⇒ Boolean
-
#check_node_installation ⇒ Object
Node.js validation.
- #check_node_version ⇒ Object
-
#check_package_manager ⇒ Object
Package manager validation.
- #check_package_version_sync ⇒ Object
-
#check_react_dependencies ⇒ Object
React dependencies validation.
- #check_react_on_rails_gem ⇒ Object
-
#check_react_on_rails_initializer ⇒ Object
Rails integration validation.
- #check_react_on_rails_npm_package ⇒ Object
-
#check_react_on_rails_packages ⇒ Object
React on Rails package validation.
-
#check_shakapacker_configuration ⇒ Object
Shakapacker validation.
- #check_shakapacker_in_gemfile ⇒ Object
- #check_webpack_config_content ⇒ Object
-
#check_webpack_configuration ⇒ Object
Webpack configuration validation.
- #errors? ⇒ Boolean
-
#initialize ⇒ SystemChecker
constructor
A new instance of SystemChecker.
- #suggest_webpack_inspection ⇒ Object
- #warnings? ⇒ Boolean
Constructor Details
#initialize ⇒ SystemChecker
Returns a new instance of SystemChecker.
14 15 16 |
# File 'lib/react_on_rails/system_checker.rb', line 14 def initialize @messages = [] end |
Instance Attribute Details
#messages ⇒ Object (readonly)
Returns the value of attribute messages.
12 13 14 |
# File 'lib/react_on_rails/system_checker.rb', line 12 def @messages end |
Instance Method Details
#add_error(message) ⇒ Object
18 19 20 |
# File 'lib/react_on_rails/system_checker.rb', line 18 def add_error() @messages << { type: :error, content: } end |
#add_info(message) ⇒ Object
30 31 32 |
# File 'lib/react_on_rails/system_checker.rb', line 30 def add_info() @messages << { type: :info, content: } end |
#add_success(message) ⇒ Object
26 27 28 |
# File 'lib/react_on_rails/system_checker.rb', line 26 def add_success() @messages << { type: :success, content: } end |
#add_warning(message) ⇒ Object
22 23 24 |
# File 'lib/react_on_rails/system_checker.rb', line 22 def add_warning() @messages << { type: :warning, content: } end |
#bundle_analyzer_available? ⇒ Boolean
339 340 341 342 343 344 345 346 347 348 349 |
# File 'lib/react_on_rails/system_checker.rb', line 339 def bundle_analyzer_available? return false unless File.exist?("package.json") begin package_json = JSON.parse(File.read("package.json")) all_deps = (package_json["dependencies"] || {}).merge(package_json["devDependencies"] || {}) all_deps["webpack-bundle-analyzer"] rescue StandardError false end end |
#check_node_installation ⇒ Object
Node.js validation
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/react_on_rails/system_checker.rb', line 43 def check_node_installation if node_missing? add_error(<<~MSG.strip) 🚫 Node.js is required but not found on your system. Please install Node.js before continuing: • Download from: https://nodejs.org/en/ • Recommended: Use a version manager like nvm, fnm, or volta • Minimum required version: Node.js 18+ After installation, restart your terminal and try again. MSG return false end check_node_version true end |
#check_node_version ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/react_on_rails/system_checker.rb', line 62 def check_node_version stdout, stderr, status = Open3.capture3("node", "--version") # Use stdout if available, fallback to stderr if stdout is empty node_version = stdout.strip node_version = stderr.strip if node_version.empty? # Return early if node is not found (non-zero status) or no output return if !status.success? || node_version.empty? # Extract major version number (e.g., "v18.17.0" -> 18) major_version = node_version[/v(\d+)/, 1]&.to_i return unless major_version if major_version < 18 add_warning(<<~MSG.strip) ⚠️ Node.js version #{node_version} detected. React on Rails recommends Node.js 18+ for best compatibility. You may experience issues with older versions. Consider upgrading: https://nodejs.org/en/ MSG else add_success("✅ Node.js #{node_version} is installed and compatible") end end |
#check_package_manager ⇒ Object
Package manager validation
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
# File 'lib/react_on_rails/system_checker.rb', line 91 def check_package_manager package_managers = %w[npm pnpm yarn bun] available_managers = package_managers.select { |pm| cli_exists?(pm) } if available_managers.empty? add_error(<<~MSG.strip) 🚫 No JavaScript package manager found on your system. React on Rails requires a JavaScript package manager to install dependencies. Please install one of the following: • npm: Usually comes with Node.js (https://nodejs.org/en/) • yarn: npm install -g yarn (https://yarnpkg.com/) • pnpm: npm install -g pnpm (https://pnpm.io/) • bun: Install from https://bun.sh/ After installation, restart your terminal and try again. MSG return false end # Detect which package manager is actually being used used_manager = detect_used_package_manager if used_manager version_info = get_package_manager_version(used_manager) deprecation_note = get_deprecation_note(used_manager, version_info) = "✅ Package manager in use: #{used_manager} #{version_info}" += deprecation_note if deprecation_note add_success() else add_success("✅ Package managers available: #{available_managers.join(', ')}") add_info("ℹ️ No lock file detected - run npm/yarn/pnpm install to establish which manager is used") end true end |
#check_package_version_sync ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/react_on_rails/system_checker.rb', line 207 def check_package_version_sync return unless File.exist?("package.json") begin package_json = JSON.parse(File.read("package.json")) package_name, npm_version = react_on_rails_npm_package_details(package_json) return unless npm_version && defined?(ReactOnRails::VERSION) # Normalize NPM version format to Ruby gem format for comparison # Uses existing VersionSyntaxConverter to handle dash/dot differences # (e.g., "16.2.0-beta.10" → "16.2.0.beta.10") converter = ReactOnRails::VersionSyntaxConverter.new normalized_npm_version = converter.npm_to_rubygem(npm_version) gem_version = ReactOnRails::VERSION if normalized_npm_version == gem_version add_success("✅ React on Rails gem and #{package_name} NPM package versions match (#{gem_version})") check_version_patterns(npm_version, gem_version) else # Check for major version differences gem_major = gem_version.split(".")[0].to_i npm_major = normalized_npm_version.split(".")[0].to_i if gem_major != npm_major # rubocop:disable Style/NegatedIfElseCondition add_error(<<~MSG.strip) 🚫 Major version mismatch detected: • Gem version: #{gem_version} (major: #{gem_major}) • #{package_name} version: #{npm_version} (major: #{npm_major}) Major version differences can cause serious compatibility issues. Update both packages to use the same major version immediately. MSG else add_warning(<<~MSG.strip) ⚠️ Version mismatch detected: • Gem version: #{gem_version} • #{package_name} version: #{npm_version} Consider updating to exact, fixed matching versions of gem and npm package for best compatibility. MSG end end rescue JSON::ParserError # Ignore parsing errors, already handled elsewhere rescue StandardError # Handle other errors gracefully end end |
#check_react_dependencies ⇒ Object
React dependencies validation
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/react_on_rails/system_checker.rb', line 258 def check_react_dependencies return unless File.exist?("package.json") package_json = parse_package_json return unless package_json # Check core React dependencies required_deps = required_react_dependencies missing_deps = find_missing_dependencies(package_json, required_deps) report_dependency_status(required_deps, missing_deps, package_json) # Check additional build dependencies (informational) check_build_dependencies(package_json) # Report versions report_dependency_versions(package_json) end |
#check_react_on_rails_gem ⇒ Object
172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/react_on_rails/system_checker.rb', line 172 def check_react_on_rails_gem require "react_on_rails" add_success("✅ React on Rails gem #{ReactOnRails::VERSION} is loaded") rescue LoadError add_error(<<~MSG.strip) 🚫 React on Rails gem is not available. Add to your Gemfile: gem 'react_on_rails' Then run: bundle install MSG end |
#check_react_on_rails_initializer ⇒ Object
Rails integration validation
278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/react_on_rails/system_checker.rb', line 278 def check_react_on_rails_initializer initializer_path = "config/initializers/react_on_rails.rb" if File.exist?(initializer_path) add_success("✅ React on Rails initializer exists") else add_warning(<<~MSG.strip) ⚠️ React on Rails initializer not found. Create: config/initializers/react_on_rails.rb Or run: rails generate react_on_rails:install MSG end end |
#check_react_on_rails_npm_package ⇒ Object
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/react_on_rails/system_checker.rb', line 186 def check_react_on_rails_npm_package package_json_path = "package.json" return unless File.exist?(package_json_path) package_json = JSON.parse(File.read(package_json_path)) package_name, npm_version = react_on_rails_npm_package_details(package_json) if package_name add_success("✅ #{package_name} NPM package #{npm_version} is declared") else add_warning(<<~MSG.strip) ⚠️ Neither react-on-rails nor react-on-rails-pro NPM package found in package.json. Install it with: npm install react-on-rails MSG end rescue JSON::ParserError add_warning("⚠️ Could not parse package.json") end |
#check_react_on_rails_packages ⇒ Object
React on Rails package validation
165 166 167 168 169 170 |
# File 'lib/react_on_rails/system_checker.rb', line 165 def check_react_on_rails_packages check_react_on_rails_gem check_react_on_rails_npm_package check_package_version_sync check_gemfile_version_patterns end |
#check_shakapacker_configuration ⇒ Object
Shakapacker validation
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/react_on_rails/system_checker.rb', line 128 def check_shakapacker_configuration unless shakapacker_configured? add_error(<<~MSG.strip) 🚫 Shakapacker is not properly configured. Missing one or more required files: • bin/shakapacker • bin/shakapacker-dev-server • config/shakapacker.yml • config/webpack/webpack.config.js Run: bundle exec rails shakapacker:install MSG return false end report_shakapacker_version_with_threshold check_shakapacker_in_gemfile true end |
#check_shakapacker_in_gemfile ⇒ Object
149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/react_on_rails/system_checker.rb', line 149 def check_shakapacker_in_gemfile if shakapacker_in_gemfile? add_success("✅ Shakapacker is declared in Gemfile") else add_warning(<<~MSG.strip) ⚠️ Shakapacker not found in Gemfile. While Shakapacker might be available as a dependency, it's recommended to add it explicitly to your Gemfile: bundle add shakapacker --strict MSG end end |
#check_webpack_config_content ⇒ Object
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/react_on_rails/system_checker.rb', line 351 def check_webpack_config_content webpack_config_path = "config/webpack/webpack.config.js" content = File.read(webpack_config_path) if react_on_rails_config?(content) add_success("✅ Webpack config includes React on Rails environment configuration") add_info(" ℹ️ Environment-specific configs detected for optimal React on Rails integration") elsif standard_shakapacker_config?(content) add_warning(<<~MSG.strip) ⚠️ Standard Shakapacker webpack config detected. React on Rails works better with environment-specific configuration. Consider running: rails generate react_on_rails:install --force This adds client and server environment configs for better performance. MSG else add_info("ℹ️ Custom webpack config detected") add_info(" 💡 Ensure config supports both client and server rendering") add_info(" 💡 Verify React JSX transformation is configured") add_info(" 💡 Check that asset output paths match Rails expectations") end end |
#check_webpack_configuration ⇒ Object
Webpack configuration validation
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/react_on_rails/system_checker.rb', line 293 def check_webpack_configuration webpack_config_path = "config/webpack/webpack.config.js" if File.exist?(webpack_config_path) add_success("✅ Webpack configuration exists") check_webpack_config_content suggest_webpack_inspection else add_error(<<~MSG.strip) 🚫 Webpack configuration not found. Expected: config/webpack/webpack.config.js Run: rails generate react_on_rails:install MSG end end |
#errors? ⇒ Boolean
34 35 36 |
# File 'lib/react_on_rails/system_checker.rb', line 34 def errors? @messages.any? { |msg| msg[:type] == :error } end |
#suggest_webpack_inspection ⇒ Object
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/react_on_rails/system_checker.rb', line 309 def suggest_webpack_inspection add_info("💡 To debug webpack builds:") add_info(" bin/shakapacker --mode=development --progress") add_info(" bin/shakapacker --mode=production --progress") add_info(" bin/shakapacker --debug-shakapacker # Debug Shakapacker configuration") add_info("💡 Advanced webpack debugging:") add_info(" 1. Add 'debugger;' before 'module.exports' in config/webpack/webpack.config.js") add_info(" 2. Run: ./bin/shakapacker --debug-shakapacker") add_info(" 3. Open Chrome DevTools to inspect config object") add_info(" 📖 See: https://github.com/shakacode/shakapacker/blob/main/docs/troubleshooting.md#debugging-your-webpack-config") add_info("💡 To analyze bundle size:") if bundle_analyzer_available? add_info(" ANALYZE=true bin/shakapacker") add_info(" This opens webpack-bundle-analyzer in your browser") else add_info(" 1. yarn add --dev webpack-bundle-analyzer") add_info(" 2. Add to config/webpack/webpack.config.js:") add_info(" const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');") add_info(" // Add to plugins array when process.env.ANALYZE") add_info(" 3. ANALYZE=true bin/shakapacker") add_info(" Or use Shakapacker's built-in support if available") end add_info("💡 Generate webpack stats for analysis:") add_info(" bin/shakapacker --json > webpack-stats.json") add_info(" Upload to webpack.github.io/analyse or webpack-bundle-analyzer.com") end |
#warnings? ⇒ Boolean
38 39 40 |
# File 'lib/react_on_rails/system_checker.rb', line 38 def warnings? @messages.any? { |msg| msg[:type] == :warning } end |