Skip to content
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ After a release, run `/update-changelog` in Claude Code to analyze commits, writ

Changes since the last non-beta release.

#### Changed

- **Generator layout renamed**: The layout file generated by `rails g react_on_rails:install` has been renamed from `hello_world.html.erb` to `react_on_rails_default.html.erb`, and controller templates now declare `layout "react_on_rails_default"`. The layout's only purpose is to provide empty `javascript_pack_tag` and `stylesheet_pack_tag` calls for React on Rails auto-registration — it has no connection to the HelloWorld demo. This only affects newly generated apps; existing apps are unchanged. [PR 2482](https://github.com/shakacode/react_on_rails/pull/2482) by [ihabadham](https://github.com/ihabadham).

#### Fixed

- **RSC Generator Layout Wiring**: Fixed `MissingEntryError` on fresh RSC installs where `HelloServerController` fell back to Rails' `application.html.erb` (which uses `javascript_pack_tag "application"` that is not created by the RSC flow). The generator now always copies `hello_world.html.erb`, `HelloServerController` explicitly uses `layout "hello_world"`, and post-install output now shows `stream_react_component` for RSC installs. [PR 2429](https://github.com/shakacode/react_on_rails/pull/2429) by [justin808](https://github.com/justin808).
- **RSC Generator Layout Wiring**: Fixed `MissingEntryError` on fresh RSC installs where `HelloServerController` fell back to Rails' `application.html.erb` (which uses `javascript_pack_tag "application"` that is not created by the RSC flow). The generator now always copies `react_on_rails_default.html.erb`, `HelloServerController` explicitly uses `layout "react_on_rails_default"`, and post-install output now shows `stream_react_component` for RSC installs. [PR 2429](https://github.com/shakacode/react_on_rails/pull/2429) by [justin808](https://github.com/justin808).

#### Pro

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ def copy_base_files
.dev-services.yml.example
bin/shakapacker-precompile-hook]

# HelloServer uses the hello_world layout so React on Rails can inject generated
# packs without requiring a hardcoded application.js pack entry.
base_files << "app/views/layouts/hello_world.html.erb"
# react_on_rails_default layout provides empty pack tags so React on Rails can
# inject generated packs without requiring a hardcoded application.js pack entry.
base_files << "app/views/layouts/react_on_rails_default.html.erb"

# HelloWorld controller only when not using RSC (RSC uses HelloServer)
# Exception: Redux still needs the HelloWorld controller even with RSC
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,7 @@ def helpful_message_after_installation(component_name: "HelloWorld", route: "hel
package_manager = detect_package_manager
shakapacker_status = build_shakapacker_status_section
render_example = build_render_example(component_name: component_name, route: route, rsc: rsc)
render_label = if rsc
"• Streaming server rendering in app/views/#{route}/index.html.erb:"
else
"• Server-side rendering - Enabled with prerender option in app/views/#{route}/index.html.erb:"
end
render_label = build_render_label(route: route, rsc: rsc)

<<~MSG

Expand Down Expand Up @@ -97,6 +93,11 @@ def build_render_example(component_name:, route:, rsc:)
end
end

def build_render_label(route:, rsc:)
prefix = rsc ? "Streaming server rendering" : "Server-side rendering - Enabled with prerender option"
"• #{prefix} in app/views/#{route}/index.html.erb:"
end

def build_process_manager_section
process_manager = detect_process_manager
if process_manager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

class HelloWorldController < ApplicationController
layout "hello_world"
layout "react_on_rails_default"

def index
@hello_world_props = { name: "Stranger" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/

class HelloServerController < ApplicationController
layout "hello_world"
layout "react_on_rails_default"

include ReactOnRailsPro::Stream

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@
stream_react_component renders the RSC with streaming support.

Key points:
- prerender: true enables server-side rendering with streaming
- Props are passed from the controller (@hello_server_props)
- The component streams as it resolves (async data fetching happens server-side)
- Only the interactive LikeButton client component ships JS to the browser
- Open DevTools Network tab to verify — no HelloServer.js in the client bundle
%>
<%= stream_react_component('HelloServer', props: @hello_server_props, prerender: true) %>
<%= stream_react_component('HelloServer', props: @hello_server_props) %>

<hr>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@
Procfile.dev
Procfile.dev-static-assets
Procfile.dev-prod-assets
app/views/layouts/hello_world.html.erb].each { |file| assert_file(file) }
app/views/layouts/react_on_rails_default.html.erb].each { |file| assert_file(file) }
end

it "creates Pro initializer with RSC configuration" do
Expand Down Expand Up @@ -771,18 +771,7 @@
assert_file "app/javascript/src/HelloServer/components/LikeButton.jsx"
end

it "creates HelloServer controller and view" do
assert_file "app/controllers/hello_server_controller.rb" do |content|
expect(content).to include("class HelloServerController")
expect(content).to include('layout "hello_world"')
expect(content).to include("ReactOnRailsPro::Stream")
end

assert_file "app/views/hello_server/index.html.erb" do |content|
expect(content).to include("HelloServer")
expect(content).to include("stream_react_component")
end
end
include_examples "rsc_hello_server_controller"

it "adds HelloServer route" do
assert_file "config/routes.rb" do |content|
Expand All @@ -808,7 +797,7 @@
Procfile.dev
Procfile.dev-static-assets
Procfile.dev-prod-assets
app/views/layouts/hello_world.html.erb].each { |file| assert_file(file) }
app/views/layouts/react_on_rails_default.html.erb].each { |file| assert_file(file) }
end

it "creates Pro initializer with RSC configuration" do
Expand Down Expand Up @@ -841,13 +830,7 @@
end
end

it "creates HelloServer controller with hello_world layout" do
assert_file "app/controllers/hello_server_controller.rb" do |content|
expect(content).to include("class HelloServerController")
expect(content).to include('layout "hello_world"')
expect(content).to include("ReactOnRailsPro::Stream")
end
end
include_examples "rsc_hello_server_controller"
end

context "with --rsc --typescript" do
Expand All @@ -858,7 +841,7 @@
Procfile.dev
Procfile.dev-static-assets
Procfile.dev-prod-assets
app/views/layouts/hello_world.html.erb].each { |file| assert_file(file) }
app/views/layouts/react_on_rails_default.html.erb].each { |file| assert_file(file) }
end

it "creates Pro initializer with RSC configuration" do
Expand Down Expand Up @@ -893,13 +876,7 @@
end
end

it "creates HelloServer controller with hello_world layout" do
assert_file "app/controllers/hello_server_controller.rb" do |content|
expect(content).to include("class HelloServerController")
expect(content).to include('layout "hello_world"')
expect(content).to include("ReactOnRailsPro::Stream")
end
end
include_examples "rsc_hello_server_controller"
end

context "with --rsc --rspack" do
Expand All @@ -910,7 +887,7 @@
Procfile.dev
Procfile.dev-static-assets
Procfile.dev-prod-assets
app/views/layouts/hello_world.html.erb].each { |file| assert_file(file) }
app/views/layouts/react_on_rails_default.html.erb].each { |file| assert_file(file) }
end

it "creates Pro initializer with RSC configuration" do
Expand All @@ -934,13 +911,7 @@
end
end

it "creates HelloServer controller with hello_world layout" do
assert_file "app/controllers/hello_server_controller.rb" do |content|
expect(content).to include("class HelloServerController")
expect(content).to include('layout "hello_world"')
expect(content).to include("ReactOnRailsPro::Stream")
end
end
include_examples "rsc_hello_server_controller"
end

context "when rscWebpackConfig.js already exists" do
Expand Down Expand Up @@ -977,10 +948,6 @@
end

context "with helpful message" do
let(:expected) do
GeneratorMessages.format_info(GeneratorMessages.helpful_message_after_installation)
end

before do
# Clear any previous messages to ensure clean test state
GeneratorMessages.clear
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,18 @@

it "copies common files" do
%w[app/controllers/hello_world_controller.rb
app/views/layouts/react_on_rails_default.html.erb
config/initializers/react_on_rails.rb
Procfile.dev
Procfile.dev-static-assets
Procfile.dev-prod-assets].each { |file| assert_file(file) }
end

it "creates HelloWorld controller with react_on_rails_default layout" do
assert_file "app/controllers/hello_world_controller.rb" do |content|
expect(content).to include('layout "react_on_rails_default"')
end
end
end

shared_examples "react_component_structure" do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

shared_examples "rsc_hello_server_controller" do
it "creates HelloServer controller with react_on_rails_default layout" do
assert_file "app/controllers/hello_server_controller.rb" do |content|
expect(content).to include("class HelloServerController")
expect(content).to include('layout "react_on_rails_default"')
expect(content).to include("ReactOnRailsPro::Stream")
end
end

it "creates HelloServer view with stream_react_component" do
assert_file "app/views/hello_server/index.html.erb" do |content|
expect(content).to include("HelloServer")
expect(content).to include("stream_react_component")
end
end
end
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# frozen_string_literal: true

class HelloWorldController < ApplicationController
layout "hello_world"
layout "react_on_rails_default"

def index
@hello_world_props = { name: "Stranger" }
Expand Down
Loading