Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ After a release, run `/update-changelog` in Claude Code to analyze commits, writ
so Rspack v1 remains allowed for non-RSC apps, and bundler detection now honors `SHAKAPACKER_ASSETS_BUNDLER`
before `config/shakapacker.yml`.
[PR 4289](https://github.com/shakacode/react_on_rails/pull/4289) by [justin808](https://github.com/justin808).
- **Redux is now hidden from the V17 install generator path**: The `react_on_rails:install --redux` option is no longer shown in install generator help or usage text, and recovery guidance no longer recommends `--redux` for new installs. The hidden legacy path and direct `react_on_rails:react_with_redux` generator now warn that Redux scaffolding is legacy while keeping runtime Redux APIs available. Closes [Issue 4272](https://github.com/shakacode/react_on_rails/issues/4272) and [Issue 4273](https://github.com/shakacode/react_on_rails/issues/4273). [PR 4277](https://github.com/shakacode/react_on_rails/pull/4277) by [justin808](https://github.com/justin808).

- **`create-react-on-rails-app` now defaults to Pro for React 19.2 support**: Running
`npx create-react-on-rails-app my-app` no longer asks setup questions and generates the recommended
React on Rails Pro scaffold by default. Automation note: non-TTY environments, including CI and piped
Expand Down
6 changes: 0 additions & 6 deletions react_on_rails/lib/generators/USAGE
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ Description:

The react_on_rails:install generator integrates a React frontend, including SSR, with Rails.

* Redux (Optional)

Passing the --redux generator option causes the generated Hello World example
to integrate the Redux state container framework. The necessary node modules
will be automatically included for you.

* Tailwind CSS v4 (Optional)

Passing the --tailwind generator option installs Tailwind CSS v4, configures
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ class BaseGenerator < Rails::Generators::Base
Rails::Generators.hide_namespace(namespace)
source_root(File.expand_path("templates", __dir__))

# --redux
# Internal hidden legacy Redux plumbing for install_generator.
class_option :redux,
type: :boolean,
default: false,
desc: "Install Redux package and Redux version of Hello World Example",
aliases: "-R"
desc: "Internal legacy Redux scaffolding flag",
aliases: "-R",
hide: true

# --rspack / --no-rspack (Rspack is the default on fresh installs; --no-rspack selects Webpack)
# IMPORTANT: do NOT add a `default:` here. The absence of a default is load-bearing — Thor
Expand Down
105 changes: 88 additions & 17 deletions react_on_rails/lib/generators/react_on_rails/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ class InstallGenerator < Rails::Generators::Base
# fetch USAGE file for details generator description
source_root(File.expand_path(__dir__))

# --redux
# Hidden legacy --redux escape hatch for existing scripted installs.
class_option :redux,
type: :boolean,
default: false,
desc: "Install Redux package and Redux version of Hello World Example. Default: false",
aliases: "-R"
desc: "Deprecated legacy Redux install path; use react_on_rails:react_with_redux directly.",
aliases: "-R",
hide: true
Comment thread
justin808 marked this conversation as resolved.

# --typescript
class_option :typescript,
Expand Down Expand Up @@ -220,6 +221,8 @@ def run_generators
# print_generator_messages raises an exception. This prevents ENV pollution
# that could affect subsequent processes.
ENV.delete("REACT_ON_RAILS_SKIP_VALIDATION")
# Keep primary failure details first; the legacy Redux advisory is best-effort.
add_legacy_redux_install_warning_once_safely
Comment thread
justin808 marked this conversation as resolved.
print_generator_messages
Comment thread
justin808 marked this conversation as resolved.
end

Expand Down Expand Up @@ -252,9 +255,9 @@ def invoke_generators
end

# Component generator logic:
# - --rsc without --redux: Skip HelloWorld, HelloServer will be generated in setup_rsc
# - --rsc with --redux: Generate HelloWorldApp (user explicitly wants Redux) + HelloServer
# - Without --rsc: Normal behavior (HelloWorld or HelloWorldApp based on --redux)
# - --rsc without hidden legacy Redux: Skip HelloWorld; setup_rsc generates HelloServer.
# - Hidden legacy --redux: Generate HelloWorldApp as a one-major escape hatch.
# - Without --rsc: Generate the default HelloWorld example unless the legacy flag is present.
if options.redux?
invoke "react_on_rails:react_with_redux", [], { typescript: options.typescript?,
tailwind: use_tailwind?,
Expand Down Expand Up @@ -781,26 +784,92 @@ def shakapacker_setup_incomplete?
@shakapacker_setup_incomplete == true
end

def add_legacy_redux_install_warning
return unless options.redux?

legacy_docs_url = "https://reactonrails.com/docs/api-reference/generator-details/"
Comment thread
justin808 marked this conversation as resolved.
legacy_guidance, legacy_command =
if use_tailwind?
[
"Existing apps that need Redux with Tailwind should keep using the hidden install path:",
recovery_install_command
]
else
[
"Existing apps that need the legacy Redux scaffold can use the hidden react_with_redux generator. " \
"That generator is also legacy and emits its own warning:",
legacy_redux_generator_command
]
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
end

GeneratorMessages.add_warning(<<~MSG.strip)
The install --redux option is a hidden legacy Redux generator path and is not recommended
for new React on Rails apps.
Use the default install generator for new apps. #{legacy_guidance}

#{legacy_command}

Comment thread
coderabbitai[bot] marked this conversation as resolved.
For legacy Redux recovery details, see #{legacy_docs_url}.
Comment thread
justin808 marked this conversation as resolved.
Runtime Redux APIs such as redux_store remain supported.
MSG
end

def add_legacy_redux_install_warning_once
return if @legacy_redux_install_warning_added

Comment thread
justin808 marked this conversation as resolved.
# Set only after enqueueing; safe callers may retry if the warning helper fails.
add_legacy_redux_install_warning
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
@legacy_redux_install_warning_added = true
end
Comment thread
justin808 marked this conversation as resolved.

def add_legacy_redux_install_warning_once_safely
add_legacy_redux_install_warning_once
rescue StandardError => e
warn "[react_on_rails] Skipped legacy Redux warning: #{e.message}"
nil
end

def recovery_install_command
flags = optional_install_flags
flags << explicit_bundler_install_flag
flags << product_stack_install_flag

# Preserve an explicit agent-files opt-out so the suggested re-run doesn't emit
# AGENTS.md/editor files a user deliberately skipped (--agent-files defaults to on).
flags << "--no-agent-files" unless options.agent_files?

["rails generate react_on_rails:install", *flags.compact].join(" ")
end

def legacy_redux_generator_command
flags = []
flags << "--redux" if options.redux?
flags << "--typescript" if options.typescript?

["rails generate react_on_rails:react_with_redux", *flags].join(" ")
end

def optional_install_flags
[
["--redux", options.redux?],
["--typescript", options.typescript?],
["--tailwind", use_tailwind?]
].filter_map { |flag, enabled| flag if enabled }
end

def explicit_bundler_install_flag
# Echo the resolved bundler choice (normalized to --rspack/--no-rspack, so a --webpack
# alias re-runs as --no-rspack) only when the user passed one explicitly. An unset choice
# re-resolves to the fresh-install default on re-run, so we don't pin it here.
flags << (using_rspack? ? "--rspack" : "--no-rspack") if bundler_flag_given?
return unless bundler_flag_given?

if options.rsc?
flags << "--rsc"
elsif options.pro?
flags << "--pro"
end
using_rspack? ? "--rspack" : "--no-rspack"
end

# Preserve an explicit agent-files opt-out so the suggested re-run doesn't emit
# AGENTS.md/editor files a user deliberately skipped (--agent-files defaults to on).
flags << "--no-agent-files" unless options.agent_files?
def product_stack_install_flag
return "--rsc" if options.rsc?
return "--pro" if options.pro?

["rails generate react_on_rails:install", *flags].join(" ")
nil
Comment thread
justin808 marked this conversation as resolved.
end

def rsc_verification_message
Expand Down Expand Up @@ -1064,6 +1133,7 @@ def handle_shakapacker_gemfile_error
Then re-run: #{recovery_install_command}
MSG
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
GeneratorMessages.add_error(error)
Comment thread
justin808 marked this conversation as resolved.
add_legacy_redux_install_warning_once_safely
raise Thor::Error, error unless options.ignore_warnings?
end

Expand All @@ -1088,6 +1158,7 @@ def handle_shakapacker_install_error
Need help? Visit: https://github.com/shakacode/shakapacker/blob/main/docs/installation.md
MSG
GeneratorMessages.add_error(error)
add_legacy_redux_install_warning_once_safely
raise Thor::Error, error unless options.ignore_warnings?
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,37 @@ class ReactWithReduxGenerator < Rails::Generators::Base

Rails::Generators.hide_namespace(namespace)
source_root(File.expand_path("templates", __dir__))
# Keep the runtime API compatibility sentence aligned with InstallGenerator#add_legacy_redux_install_warning.
# The install path adds recovery docs and command guidance that this standalone warning intentionally omits.
LEGACY_REDUX_GENERATOR_WARNING = <<~MSG.strip.freeze
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
The react_on_rails:react_with_redux generator is a hidden legacy Redux generator path and is not
recommended for new React on Rails apps.
New apps should use the default React on Rails installer without Redux. Runtime Redux APIs such as
redux_store remain supported.
MSG
Comment thread
justin808 marked this conversation as resolved.
private_constant :LEGACY_REDUX_GENERATOR_WARNING

class_option :typescript, type: :boolean, default: false, desc: "Generate TypeScript files", aliases: "-T"
class_option :invoked_by_install, type: :boolean, default: false, hide: true
class_option :new_app, type: :boolean, default: false, hide: true
class_option :rsc, type: :boolean, default: false, hide: true
class_option :tailwind, type: :boolean, default: false, hide: true

Comment thread
justin808 marked this conversation as resolved.
# Only this public method is dispatched by Rails; helpers below stay private.
def run_generator
add_legacy_redux_generator_warning
validate_standalone_tailwind
Comment thread
justin808 marked this conversation as resolved.
create_redux_directories
copy_base_files
copy_base_redux_files
create_appropriate_templates
add_redux_npm_dependencies
add_redux_specific_messages
Comment thread
justin808 marked this conversation as resolved.
ensure
Comment thread
justin808 marked this conversation as resolved.
Comment thread
justin808 marked this conversation as resolved.
print_generator_messages unless options[:invoked_by_install]
end
Comment thread
justin808 marked this conversation as resolved.

class_option :typescript,
type: :boolean,
default: false,
desc: "Generate TypeScript files",
aliases: "-T"

class_option :invoked_by_install,
type: :boolean,
default: false,
hide: true

class_option :new_app,
type: :boolean,
default: false,
hide: true

class_option :rsc,
type: :boolean,
default: false,
hide: true

class_option :tailwind,
type: :boolean,
default: false,
hide: true
private

def validate_standalone_tailwind
return unless unsupported_standalone_tailwind?
Expand Down Expand Up @@ -128,10 +133,15 @@ def add_redux_npm_dependencies
install_packages_with_fallback(regular_packages, dev: false, package_manager:)
end

Comment thread
justin808 marked this conversation as resolved.
def add_legacy_redux_generator_warning
return if options[:invoked_by_install]

GeneratorMessages.add_warning(LEGACY_REDUX_GENERATOR_WARNING)
end

def add_redux_specific_messages
return if options.invoked_by_install?
return if options[:invoked_by_install]

# Append Redux-specific post-install instructions
GeneratorMessages.add_info(
GeneratorMessages.helpful_message_after_installation(component_name: "HelloWorldApp", route: "hello_world",
pro: Gem.loaded_specs.key?("react_on_rails_pro"),
Expand All @@ -140,21 +150,21 @@ def add_redux_specific_messages
)
end

private

def unsupported_standalone_tailwind?
return false unless use_tailwind?
return false if options[:invoked_by_install]

GeneratorMessages.add_error(<<~MSG.strip)
🚫 The standalone react_on_rails:react_with_redux generator does not support --tailwind.

Tailwind setup requires the base React on Rails installer so it can create the
react_on_rails_tailwind pack, stylesheet, dependencies, and webpack/Rspack config.

Use the install generator for Redux + Tailwind setup:
Use the hidden legacy installer path if you intentionally need the Redux scaffold with Tailwind:

rails generate react_on_rails:install --redux --tailwind

For new apps, run the default installer without Redux:

rails generate react_on_rails:install --tailwind
MSG
Comment thread
justin808 marked this conversation as resolved.
true
end
Expand Down
Loading
Loading