Module: GeneratorHelper
- Included in:
- ReactOnRails::Generators::BaseGenerator, ReactOnRails::Generators::DevTestsGenerator, ReactOnRails::Generators::InstallGenerator, ReactOnRails::Generators::ProGenerator, ReactOnRails::Generators::ReactNoReduxGenerator, ReactOnRails::Generators::ReactWithReduxGenerator, ReactOnRails::Generators::RscGenerator
- Defined in:
- lib/generators/react_on_rails/generator_helper.rb
Overview
rubocop:disable Metrics/ModuleLength
Instance Method Summary collapse
- #absolute_generator_path(relative_path) ⇒ Object
- #absolute_path_relative_to_destination(pathname) ⇒ Object
- #add_documentation_reference(message, source) ⇒ Object
-
#add_npm_dependencies(packages, dev: false) ⇒ Object
Safe wrapper for package_json operations.
-
#bundler_flag_given? ⇒ Boolean
True when the user passed any explicit bundler flag (--rspack/--no-rspack/--webpack/--no-webpack).
- #component_extension(options) ⇒ Object
- #configured_shakapacker_relative_path(config_key, default, allow_root: false) ⇒ Object
-
#destination_config_path(path) ⇒ String
Remap a config path from config/webpack/ to config/rspack/ when using rspack.
-
#detect_react_version ⇒ String?
Detect the installed React version from package.json Uses VERSION_PARTS_REGEX pattern from VersionChecker for consistency.
- #example_component_source_directory(component_name) ⇒ Object
- #example_component_source_path(component_name) ⇒ Object
-
#explicit_bundler_choice ⇒ Object
Resolve the explicit bundler flags into a single choice.
- #extract_declared_layout_name(controller_content) ⇒ Object
-
#gem_in_lockfile?(gem_name) ⇒ Boolean
Check if a gem is present in Gemfile.lock Always checks the target app's Gemfile.lock, not inherited BUNDLE_GEMFILE See: https://github.com/shakacode/react_on_rails/issues/2287.
- #html_comment_ranges(content) ⇒ Object
- #inherited_application_layout_name ⇒ Object
- #javascript_relative_import_path(from_file, to_file) ⇒ Object
- #layout_destination_path(layout_name) ⇒ Object
- #layout_file_links_tailwind_pack?(layout_name) ⇒ Boolean
- #layout_links_tailwind_pack?(content) ⇒ Boolean
- #package_json ⇒ Object
- #path_inside_or_equal?(child_path, parent_path) ⇒ Boolean
- #print_generator_messages ⇒ Object
-
#pro_gem_installed? ⇒ Boolean
Check if React on Rails Pro gem is installed (real state — never "scheduled to be installed").
- #range_overlaps_any?(range, ranges) ⇒ Boolean
- #relative_tailwind_stylesheet_import_path ⇒ Object
-
#resolve_server_client_or_both_path ⇒ String?
Resolve the path to ServerClientOrBoth.js, handling the legacy name.
-
#root_route_present?(routes_path = File.join(destination_root, "config/routes.rb")) ⇒ Boolean
Detect whether config/routes.rb defines any non-commented root route.
-
#rsc_plugin_class_name ⇒ String
RSC client-manifest plugin class name for the active bundler.
-
#rsc_plugin_import_path ⇒ String
react-on-rails-rscsubpath that exports #rsc_plugin_class_name. -
#rspack_bundler_default ⇒ Object
Bundler to use when no explicit bundler flag was passed.
- #safe_generator_destination_path(path, default:, allow_root: false) ⇒ Object
- #shakapacker_entrypoint_path(filename) ⇒ Object
- #shakapacker_path_config_value(config, config_key) ⇒ Object
- #shakapacker_source_entry_path ⇒ Object
- #shakapacker_source_path ⇒ Object
- #shakapacker_stylesheet_path(filename) ⇒ Object
-
#shakapacker_version_9_or_higher? ⇒ Boolean
Check if Shakapacker 9.0 or higher is available Returns true if Shakapacker >= 9.0, false otherwise.
- #stylesheet_dir_relative_path(stylesheet_dir, source_path) ⇒ Object
- #tailwind_css_source_directives ⇒ Object
- #tailwind_css_string(value) ⇒ Object
- #tailwind_import_statement(source:) ⇒ Object
- #tailwind_pack_filename ⇒ Object
- #tailwind_pack_name ⇒ Object
- #tailwind_pack_path ⇒ Object
- #tailwind_source_statement(source) ⇒ Object
- #tailwind_stylesheet_path ⇒ Object
- #unsafe_generator_destination_path?(path) ⇒ Boolean
-
#use_pro? ⇒ Boolean
Check if Pro features should be enabled.
-
#use_rsc? ⇒ Boolean
Check if RSC (React Server Components) should be enabled.
-
#use_tailwind? ⇒ Boolean
Check if Tailwind CSS should be installed and wired into the generated example.
-
#using_rspack? ⇒ Boolean
Determine if the project is using rspack as the bundler.
-
#using_swc? ⇒ Boolean
Check if SWC is configured as the JavaScript transpiler in shakapacker.yml.
Instance Method Details
#absolute_generator_path(relative_path) ⇒ Object
274 275 276 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 274 def absolute_generator_path(relative_path) Pathname.new(File.join(destination_root, relative_path)).cleanpath end |
#absolute_path_relative_to_destination(pathname) ⇒ Object
267 268 269 270 271 272 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 267 def absolute_path_relative_to_destination(pathname) destination = Pathname.new(destination_root).cleanpath pathname.relative_path_from(destination).to_s rescue ArgumentError nil # Signals the caller to fall back to the default path. end |
#add_documentation_reference(message, source) ⇒ Object
87 88 89 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 87 def add_documentation_reference(, source) "#{} \n#{source}" end |
#add_npm_dependencies(packages, dev: false) ⇒ Object
Safe wrapper for package_json operations
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 56 def add_npm_dependencies(packages, dev: false) pj = package_json return false unless pj begin result = if dev pj.manager.add(packages, type: :dev, exact: true) else pj.manager.add(packages, exact: true) end # package_json#add can return nil for successful side-effect operations. result != false rescue StandardError => e say_status :warning, "Could not add packages via package_json gem: #{e.}", :yellow say_status :warning, "Will fall back to direct package manager commands.", :yellow false end end |
#bundler_flag_given? ⇒ Boolean
True when the user passed any explicit bundler flag (--rspack/--no-rspack/--webpack/--no-webpack).
425 426 427 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 425 def bundler_flag_given? .key?(:rspack) || .key?(:webpack) end |
#component_extension(options) ⇒ Object
100 101 102 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 100 def component_extension() .typescript? ? "tsx" : "jsx" end |
#configured_shakapacker_relative_path(config_key, default, allow_root: false) ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 223 def configured_shakapacker_relative_path(config_key, default, allow_root: false) config_path = File.join(destination_root, "config/shakapacker.yml") return default unless File.exist?(config_path) config = parse_shakapacker_yml(config_path) configured_path = shakapacker_path_config_value(config, config_key) safe_generator_destination_path(configured_path, default:, allow_root:) rescue Psych::SyntaxError default end |
#destination_config_path(path) ⇒ String
Remap a config path from config/webpack/ to config/rspack/ when using rspack. Source templates always live under config/webpack/ (template names are stable); this method handles the destination remapping.
443 444 445 446 447 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 443 def destination_config_path(path) return path unless using_rspack? path.sub(%r{\Aconfig/webpack/}, "config/rspack/") end |
#detect_react_version ⇒ String?
Detect the installed React version from package.json Uses VERSION_PARTS_REGEX pattern from VersionChecker for consistency
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 473 def detect_react_version pj = package_json return nil unless pj dependencies = pj.fetch("dependencies", {}) react_version = dependencies["react"] return nil unless react_version # Skip non-version strings (workspace:*, file:, link:, http://, etc.) return nil if react_version.include?("/") || react_version.start_with?("workspace:") # Extract version using the same regex pattern as VersionChecker # Handles: "19.0.3", "^19.0.3", "~19.0.3", "19.0.3-beta.1", etc. match = react_version.match(/(\d+)\.(\d+)\.(\d+)(?:[-.]([0-9A-Za-z.-]+))?/) return nil unless match # Return the matched version (without pre-release suffix for comparison) "#{match[1]}.#{match[2]}.#{match[3]}" rescue StandardError nil end |
#example_component_source_directory(component_name) ⇒ Object
214 215 216 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 214 def example_component_source_directory(component_name) File.join(shakapacker_source_path, "src", component_name) end |
#example_component_source_path(component_name) ⇒ Object
218 219 220 221 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 218 def example_component_source_path(component_name) # Trailing slash is intentional: this value is only for generated demo file hints. "#{example_component_source_directory(component_name)}/" end |
#explicit_bundler_choice ⇒ Object
Resolve the explicit bundler flags into a single choice.
--rspack selects Rspack; --no-rspack and --webpack select Webpack (--webpack is a friendly alias for --no-rspack, and the auto-generated --no-webpack mirrors --rspack). Returns true for Rspack, false for Webpack, or nil when no bundler flag was passed (so the caller falls back to rspack_bundler_default).
IMPORTANT: this relies on Thor NOT including a nil-defaulted option in the hash when the flag
is absent — options.key?(:rspack)/(:webpack) is true only when the user passed that flag.
Re-adding default: to either class_option would make the key always present and break both
the "no flag given" fallback and the conflict detection here.
(Thor's omit-when-no-default behavior verified against Thor 1.5.0; see Gemfile.lock.)
Passing contradictory flags (e.g. --rspack --webpack) raises a Thor::Error.
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 405 def explicit_bundler_choice choices = [] choices << [:rspack] if .key?(:rspack) # --webpack means "use Webpack" (rspack = false); --no-webpack means "use Rspack". # Name the inverted webpack flag so the rspack-boolean intent reads directly. rspack_via_webpack_flag = ![:webpack] choices << rspack_via_webpack_flag if .key?(:webpack) return nil if choices.empty? if choices.uniq.length > 1 raise Thor::Error, "Conflicting bundler flags: pass either Rspack (--rspack) or Webpack " \ "(--webpack / --no-rspack), not both." end choices.first end |
#extract_declared_layout_name(controller_content) ⇒ Object
191 192 193 194 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 191 def extract_declared_layout_name(controller_content) match = controller_content.match(CONTROLLER_LAYOUT_DECLARATION_PATTERN) match&.captures&.compact&.first end |
#gem_in_lockfile?(gem_name) ⇒ Boolean
Check if a gem is present in Gemfile.lock Always checks the target app's Gemfile.lock, not inherited BUNDLE_GEMFILE See: https://github.com/shakacode/react_on_rails/issues/2287
326 327 328 329 330 331 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 326 def gem_in_lockfile?(gem_name) File.file?("Gemfile.lock") && File.foreach("Gemfile.lock").any? { |line| line.match?(/^\s{4}#{Regexp.escape(gem_name)}\s\(/) } rescue StandardError false end |
#html_comment_ranges(content) ⇒ Object
179 180 181 182 183 184 185 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 179 def html_comment_ranges(content) content.to_enum(:scan, HTML_COMMENT_PATTERN).map do comment_match = Regexp.last_match comment_match.begin(0)...comment_match.end(0) end end |
#inherited_application_layout_name ⇒ Object
196 197 198 199 200 201 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 196 def inherited_application_layout_name application_controller_path = File.join(destination_root, "app/controllers/application_controller.rb") return "application" unless File.exist?(application_controller_path) extract_declared_layout_name(File.read(application_controller_path)) || "application" end |
#javascript_relative_import_path(from_file, to_file) ⇒ Object
282 283 284 285 286 287 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 282 def javascript_relative_import_path(from_file, to_file) from_dir = absolute_generator_path(from_file).dirname relative_path = absolute_generator_path(to_file).relative_path_from(from_dir).to_s relative_path.start_with?(".") ? relative_path : "./#{relative_path}" end |
#layout_destination_path(layout_name) ⇒ Object
203 204 205 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 203 def layout_destination_path(layout_name) "app/views/layouts/#{layout_name}.html.erb" end |
#layout_file_links_tailwind_pack?(layout_name) ⇒ Boolean
207 208 209 210 211 212 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 207 def layout_file_links_tailwind_pack?(layout_name) layout_full_path = File.join(destination_root, layout_destination_path(layout_name)) return false unless File.exist?(layout_full_path) layout_links_tailwind_pack?(File.read(layout_full_path)) end |
#layout_links_tailwind_pack?(content) ⇒ Boolean
168 169 170 171 172 173 174 175 176 177 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 168 def layout_links_tailwind_pack?(content) comment_ranges = html_comment_ranges(content) return content.match?(TAILWIND_LAYOUT_PACK_HELPER_BLOCK_PATTERN) if comment_ranges.empty? content.to_enum(:scan, TAILWIND_LAYOUT_PACK_HELPER_BLOCK_PATTERN).any? do helper_match = Regexp.last_match !range_overlaps_any?(helper_match.begin(0)...helper_match.end(0), comment_ranges) end end |
#package_json ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 36 def package_json # Lazy load package_json gem only when actually needed for dependency management require "package_json" unless defined?(PackageJson) @package_json ||= PackageJson.read rescue LoadError unless @package_json_unavailable_warned say_status :warning, "package_json gem not available. This is expected before Shakapacker installation.", :yellow say_status :warning, "Dependencies will be installed using the default package manager after Shakapacker setup.", :yellow @package_json_unavailable_warned = true end nil rescue StandardError => e say_status :warning, "Could not read package.json: #{e.}", :yellow say_status :warning, "This is normal before Shakapacker creates the package.json file.", :yellow nil end |
#path_inside_or_equal?(child_path, parent_path) ⇒ Boolean
289 290 291 292 293 294 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 289 def path_inside_or_equal?(child_path, parent_path) relative_path = child_path.relative_path_from(parent_path).to_s relative_path == "." || (relative_path != ".." && !relative_path.start_with?("../")) rescue ArgumentError false end |
#print_generator_messages ⇒ Object
91 92 93 94 95 96 97 98 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 91 def # GeneratorMessages stores pre-colored strings, so we strip ANSI manually for --no-color output. no_color = !shell.is_a?(Thor::Shell::Color) GeneratorMessages..each do || say(no_color ? .to_s.gsub(/\e\[[0-9;]*m/, "") : ) say "" # Blank line after each message for readability end end |
#pro_gem_installed? ⇒ Boolean
Check if React on Rails Pro gem is installed (real state — never "scheduled to be installed").
Detection priority:
- Gem.loaded_specs - gem is loaded in current Ruby process (most reliable)
- Gemfile.lock - gem is resolved and installed
Use #pro_gem_install_deferred? for the broader "present, or will be installed by this generator run" meaning. Use #invalidate_pro_gem_installed_cache! after an operation that changes real state (e.g., bundle add) so the next call re-reads the lockfile.
344 345 346 347 348 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 344 def pro_gem_installed? return @pro_gem_installed if defined?(@pro_gem_installed) @pro_gem_installed = Gem.loaded_specs.key?("react_on_rails_pro") || gem_in_lockfile?("react_on_rails_pro") end |
#range_overlaps_any?(range, ranges) ⇒ Boolean
187 188 189 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 187 def range_overlaps_any?(range, ranges) ranges.any? { |candidate| range.begin < candidate.end && candidate.begin < range.end } end |
#relative_tailwind_stylesheet_import_path ⇒ Object
147 148 149 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 147 def relative_tailwind_stylesheet_import_path javascript_relative_import_path(tailwind_pack_path, tailwind_stylesheet_path) end |
#resolve_server_client_or_both_path ⇒ String?
Resolve the path to ServerClientOrBoth.js, handling the legacy name. Old installs may still use generateWebpackConfigs.js; this renames it and updates references in environment configs so downstream transforms can rely on the canonical name.
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 551 def resolve_server_client_or_both_path new_path = destination_config_path("config/webpack/ServerClientOrBoth.js") old_path = destination_config_path("config/webpack/generateWebpackConfigs.js") full_new = File.join(destination_root, new_path) full_old = File.join(destination_root, old_path) if File.exist?(full_new) new_path elsif File.exist?(full_old) FileUtils.mv(full_old, full_new) %w[development.js production.js test.js].each do |env_file| env_path = destination_config_path("config/webpack/#{env_file}") if File.exist?(File.join(destination_root, env_path)) gsub_file(env_path, /generateWebpackConfigs/, "ServerClientOrBoth") end end new_path end end |
#root_route_present?(routes_path = File.join(destination_root, "config/routes.rb")) ⇒ Boolean
Detect whether config/routes.rb defines any non-commented root route.
79 80 81 82 83 84 85 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 79 def root_route_present?(routes_path = File.join(destination_root, "config/routes.rb")) return false unless File.file?(routes_path) File.foreach(routes_path).any? do |line| !line.match?(/^\s*#/) && line.match?(/^\s*root\b/) end end |
#rsc_plugin_class_name ⇒ String
RSC client-manifest plugin class name for the active bundler.
Rspack uses the native RSCRspackPlugin; webpack uses RSCWebpackPlugin.
Both expose the same { isServer, clientReferences } API and emit the same
manifest schema, so only the import path and class name differ.
Shared by the base webpack-config templates and the standalone RSC migration
so both paths scaffold the bundler-correct plugin from one source of truth.
457 458 459 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 457 def rsc_plugin_class_name using_rspack? ? "RSCRspackPlugin" : "RSCWebpackPlugin" end |
#rsc_plugin_import_path ⇒ String
react-on-rails-rsc subpath that exports #rsc_plugin_class_name.
465 466 467 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 465 def rsc_plugin_import_path using_rspack? ? "react-on-rails-rsc/RspackPlugin" : "react-on-rails-rsc/WebpackPlugin" end |
#rspack_bundler_default ⇒ Object
Bundler to use when no explicit bundler flag was passed. Default (standalone generators like RscGenerator/ProGenerator): respect the existing project's shakapacker.yml and never impose a bundler. InstallGenerator/BaseGenerator override this to default fresh installs to Rspack.
433 434 435 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 433 def rspack_bundler_default rspack_configured_in_project? end |
#safe_generator_destination_path(path, default:, allow_root: false) ⇒ Object
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 246 def safe_generator_destination_path(path, default:, allow_root: false) candidate = path.to_s.strip return default if candidate.empty? pathname = Pathname.new(candidate).cleanpath # Shakapacker uses "/" to mean entrypoints live directly under source_path. return "" if allow_root && pathname.to_s == "/" relative_path = if pathname.absolute? absolute_path_relative_to_destination(pathname) else pathname.to_s end return default if unsafe_generator_destination_path?(relative_path) relative_path rescue ArgumentError # Pathname.new raises on null bytes in path strings. default end |
#shakapacker_entrypoint_path(filename) ⇒ Object
118 119 120 121 122 123 124 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 118 def shakapacker_entrypoint_path(filename) filename = filename.to_s raise ArgumentError, "filename must be present" if filename.empty? entry_dir = shakapacker_source_entry_path # "" means entrypoints live directly under source_path. File.join(*[shakapacker_source_path, entry_dir, filename].reject(&:empty?)) end |
#shakapacker_path_config_value(config, config_key) ⇒ Object
235 236 237 238 239 240 241 242 243 244 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 235 def shakapacker_path_config_value(config, config_key) # Generators run in the development context, so prefer that section before falling back to shared defaults. %w[development default].each do |section_name| section = shakapacker_config_section(config, section_name) value = shakapacker_config_value(section, config_key) return value unless value.to_s.strip.empty? end nil end |
#shakapacker_source_entry_path ⇒ Object
110 111 112 113 114 115 116 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 110 def shakapacker_source_entry_path @shakapacker_source_entry_path ||= configured_shakapacker_relative_path( "source_entry_path", DEFAULT_SHAKAPACKER_SOURCE_ENTRY_PATH, allow_root: true ) end |
#shakapacker_source_path ⇒ Object
104 105 106 107 108 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 104 def shakapacker_source_path # These helpers memoize config-backed paths. Install generators must copy or # overwrite config/shakapacker.yml before any path-dependent copy action runs. @shakapacker_source_path ||= configured_shakapacker_relative_path("source_path", DEFAULT_SHAKAPACKER_SOURCE_PATH) end |
#shakapacker_stylesheet_path(filename) ⇒ Object
126 127 128 129 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 126 def shakapacker_stylesheet_path(filename) # "stylesheets" is a generated demo convention, not a Shakapacker config key. File.join(shakapacker_source_path, "stylesheets", filename) end |
#shakapacker_version_9_or_higher? ⇒ Boolean
Default behavior: Returns true when Shakapacker is not yet installed
Rationale: During fresh installations, we optimistically assume users will install
the latest Shakapacker version. This ensures new projects get best-practice configs.
If users later install an older version, the generated webpack config includes
fallback logic (e.g., config.privateOutputPath || hardcodedPath) that prevents
breakage, and validation warnings guide them to fix any misconfigurations.
Check if Shakapacker 9.0 or higher is available Returns true if Shakapacker >= 9.0, false otherwise
This method is used during code generation to determine which configuration patterns to use in generated files (e.g., config.privateOutputPath vs hardcoded paths).
509 510 511 512 513 514 515 516 517 518 519 520 521 522 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 509 def shakapacker_version_9_or_higher? return @shakapacker_version_9_or_higher if defined?(@shakapacker_version_9_or_higher) @shakapacker_version_9_or_higher = begin # If Shakapacker is not available yet (fresh install), default to true # since we're likely installing the latest version return true unless defined?(ReactOnRails::PackerUtils) ReactOnRails::PackerUtils.shakapacker_version_requirement_met?("9.0.0") rescue StandardError # If we can't determine version, assume latest true end end |
#stylesheet_dir_relative_path(stylesheet_dir, source_path) ⇒ Object
278 279 280 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 278 def stylesheet_dir_relative_path(stylesheet_dir, source_path) source_path.relative_path_from(stylesheet_dir).to_s end |
#tailwind_css_source_directives ⇒ Object
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 151 def tailwind_css_source_directives stylesheet_dir = absolute_generator_path(tailwind_stylesheet_path).dirname rails_app_source = absolute_generator_path(RAILS_APP_SOURCE_PATH) shakapacker_source = absolute_generator_path(shakapacker_source_path) if path_inside_or_equal?(shakapacker_source, rails_app_source) rails_app_relative_source = stylesheet_dir_relative_path(stylesheet_dir, rails_app_source) tailwind_import_statement(source: rails_app_relative_source) else sources = [shakapacker_source, rails_app_source].uniq.map do |source_path| tailwind_source_statement(stylesheet_dir_relative_path(stylesheet_dir, source_path)) end [tailwind_import_statement(source: "none"), *sources].join("\n") end end |
#tailwind_css_string(value) ⇒ Object
306 307 308 309 310 311 312 313 314 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 306 def tailwind_css_string(value) css_string = value.to_s if css_string.match?(/[[:cntrl:]\u2028\u2029]/) raise ArgumentError, "Tailwind source paths cannot contain control characters" end # JSON quoting keeps CSS punctuation inside the string literal. JSON.generate(css_string) end |
#tailwind_import_statement(source:) ⇒ Object
296 297 298 299 300 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 296 def tailwind_import_statement(source:) css_source = source == "none" ? "none" : tailwind_css_string(source) %( @import "tailwindcss" source(#{css_source});).strip end |
#tailwind_pack_filename ⇒ Object
135 136 137 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 135 def tailwind_pack_filename "#{tailwind_pack_name}.js" end |
#tailwind_pack_name ⇒ Object
131 132 133 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 131 def tailwind_pack_name TAILWIND_PACK_NAME end |
#tailwind_pack_path ⇒ Object
139 140 141 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 139 def tailwind_pack_path shakapacker_entrypoint_path(tailwind_pack_filename) end |
#tailwind_source_statement(source) ⇒ Object
302 303 304 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 302 def tailwind_source_statement(source) %( @source #{tailwind_css_string(source)};).strip end |
#tailwind_stylesheet_path ⇒ Object
143 144 145 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 143 def tailwind_stylesheet_path shakapacker_stylesheet_path(TAILWIND_STYLESHEET_NAME) end |
#unsafe_generator_destination_path?(path) ⇒ Boolean
316 317 318 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 316 def unsafe_generator_destination_path?(path) path.nil? || path == "." || path == ".." || path.start_with?("../") end |
#use_pro? ⇒ Boolean
Check if Pro features should be enabled. Returns true if --pro or --rsc is set (RSC implies Pro).
354 355 356 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 354 def use_pro? [:pro] || [:rsc] end |
#use_rsc? ⇒ Boolean
Check if RSC (React Server Components) should be enabled. Returns true if --rsc is set.
362 363 364 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 362 def use_rsc? [:rsc] end |
#use_tailwind? ⇒ Boolean
Check if Tailwind CSS should be installed and wired into the generated example.
369 370 371 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 369 def use_tailwind? [:tailwind] end |
#using_rspack? ⇒ Boolean
Determine if the project is using rspack as the bundler.
Detection priority:
- Explicit --rspack option (most reliable during fresh installs)
- config/shakapacker.yml assets_bundler setting (for standalone generators
like
rails g react_on_rails:rscon an existing rspack project)
381 382 383 384 385 386 387 388 389 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 381 def using_rspack? return @using_rspack if defined?(@using_rspack) # An explicit bundler flag always wins. When none was passed (or the generator doesn't # declare the flags, e.g. RscGenerator/ProGenerator), fall back to the bundler default, # which each generator defines for its own context. explicit = explicit_bundler_choice @using_rspack = explicit.nil? ? rspack_bundler_default : explicit end |
#using_swc? ⇒ Boolean
This method is used to determine whether to install SWC dependencies (@swc/core, swc-loader) instead of Babel dependencies during generation.
Caching: The result is memoized for the lifetime of the generator instance. If shakapacker.yml changes during generator execution (unlikely), the cached value will not update. This is acceptable since generators run quickly.
Check if SWC is configured as the JavaScript transpiler in shakapacker.yml
Detection logic:
- If shakapacker.yml exists and specifies javascript_transpiler: parse it
- For Shakapacker 9.3.0+, SWC is the default if not specified
- Returns true for fresh installations (SWC is recommended default)
539 540 541 542 543 |
# File 'lib/generators/react_on_rails/generator_helper.rb', line 539 def using_swc? return @using_swc if defined?(@using_swc) @using_swc = detect_swc_configuration end |