react_on_rails 16.4.0.rc.1 → 16.4.0.rc.2

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/Gemfile.lock +1 -1
  4. data/lib/generators/react_on_rails/base_generator.rb +30 -10
  5. data/lib/generators/react_on_rails/dev_tests_generator.rb +9 -1
  6. data/lib/generators/react_on_rails/generator_helper.rb +101 -0
  7. data/lib/generators/react_on_rails/generator_messages.rb +2 -2
  8. data/lib/generators/react_on_rails/install_generator.rb +55 -19
  9. data/lib/generators/react_on_rails/js_dependency_manager.rb +115 -8
  10. data/lib/generators/react_on_rails/pro/USAGE +21 -0
  11. data/lib/generators/react_on_rails/pro_generator.rb +97 -0
  12. data/lib/generators/react_on_rails/pro_setup.rb +314 -0
  13. data/lib/generators/react_on_rails/rsc/USAGE +23 -0
  14. data/lib/generators/react_on_rails/rsc_generator.rb +100 -0
  15. data/lib/generators/react_on_rails/rsc_setup.rb +471 -0
  16. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +3 -3
  17. data/lib/generators/react_on_rails/templates/base/base/config/webpack/{generateWebpackConfigs.js.tt → ServerClientOrBoth.js.tt} +28 -3
  18. data/lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt +8 -0
  19. data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +2 -2
  20. data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +2 -2
  21. data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +54 -0
  22. data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +2 -2
  23. data/lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_server_spec.rb +17 -0
  24. data/lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js +41 -0
  25. data/lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt +25 -0
  26. data/lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb +25 -0
  27. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx +80 -0
  28. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx +90 -0
  29. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.jsx +54 -0
  30. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.tsx +54 -0
  31. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.jsx +10 -0
  32. data/lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.tsx +10 -0
  33. data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb +37 -0
  34. data/lib/generators/react_on_rails/templates/rsc/base/config/webpack/rscWebpackConfig.js.tt +64 -0
  35. data/lib/react_on_rails/engine.rb +5 -1
  36. data/lib/react_on_rails/version.rb +1 -1
  37. data/lib/react_on_rails/version_checker.rb +6 -1
  38. metadata +21 -3
@@ -1,9 +1,9 @@
1
1
  <%= add_documentation_reference(config[:message], "// https://github.com/shakacode/react_on_rails_demo_ssr_hmr/blob/master/config/webpack/test.js") %>
2
2
 
3
- const generateWebpackConfigs = require('./generateWebpackConfigs')
3
+ const serverClientOrBoth = require('./ServerClientOrBoth')
4
4
 
5
5
  const testOnly = (_clientWebpackConfig, _serverWebpackConfig) => {
6
6
  // place any code here that is for test only
7
7
  }
8
8
 
9
- module.exports = generateWebpackConfigs(testOnly)
9
+ module.exports = serverClientOrBoth(testOnly)
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../rails_helper"
4
+
5
+ describe "Hello Server", :js do
6
+ it "renders the React Server Component" do
7
+ visit "/hello_server"
8
+ expect(page).to have_text("Hello, React on Rails Pro!")
9
+ expect(page).to have_text("How is this different from SSR?")
10
+ end
11
+
12
+ it "renders the interactive LikeButton client component" do
13
+ visit "/hello_server"
14
+ expect(page).to have_button("👍 Like")
15
+ expect(page).to have_text("0 likes")
16
+ end
17
+ end
@@ -0,0 +1,41 @@
1
+ const path = require('path');
2
+ const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
3
+
4
+ const { env } = process;
5
+
6
+ const config = {
7
+ serverBundleCachePath: path.resolve(__dirname, '../.node-renderer-bundles'),
8
+ port: Number(env.RENDERER_PORT) || 3800,
9
+ logLevel: env.RENDERER_LOG_LEVEL || 'info',
10
+
11
+ // See value in /config/initializers/react_on_rails_pro.rb
12
+ password: env.RENDERER_PASSWORD || 'devPassword',
13
+
14
+ // Number of Node.js worker threads for SSR rendering
15
+ // Set NODE_RENDERER_CONCURRENCY env var to override (e.g., for production tuning)
16
+ workersCount: env.NODE_RENDERER_CONCURRENCY != null ? Number(env.NODE_RENDERER_CONCURRENCY) : 3,
17
+
18
+ // If set to true, `supportModules` enables the server-bundle code to call a default set of NodeJS modules
19
+ // that get added to the VM context: { Buffer, process, setTimeout, setInterval, clearTimeout, clearInterval }.
20
+ // This option is required to equal `true` if you want to use loadable components.
21
+ // Setting this value to false causes the NodeRenderer to behave like ExecJS
22
+ supportModules: true,
23
+
24
+ // Additional Node.js globals to add to the VM context.
25
+ additionalContext: { URL, AbortController },
26
+
27
+ // Required to use setTimeout, setInterval, & clearTimeout during server rendering
28
+ stubTimers: false,
29
+
30
+ // Replay console logs from async server operations
31
+ replayServerAsyncOperationLogs: true,
32
+ };
33
+
34
+ // Renderer detects a total number of CPUs on virtual hostings like Heroku or CircleCI instead
35
+ // of CPUs number allocated for current container. This results in spawning many workers while
36
+ // only 1-2 of them really needed.
37
+ if (env.CI) {
38
+ config.workersCount = 2;
39
+ }
40
+
41
+ reactOnRailsProNodeRenderer(config);
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # See https://www.shakacode.com/react-on-rails-pro/docs/configuration/
4
+ # License: Set REACT_ON_RAILS_PRO_LICENSE environment variable
5
+ ReactOnRailsPro.configure do |config|
6
+ config.server_renderer = "NodeRenderer"
7
+ config.renderer_url = ENV.fetch("REACT_RENDERER_URL", "http://localhost:3800")
8
+
9
+ # See value in client/node-renderer.js
10
+ config.renderer_password = ENV.fetch("RENDERER_PASSWORD", "devPassword")
11
+
12
+ config.ssr_timeout = 5
13
+ config.renderer_request_retry_limit = 1
14
+ config.renderer_use_fallback_exec_js = Rails.env.development?
15
+
16
+ # If you want Honeybadger or Sentry on the Node renderer side to report rendering errors
17
+ config.throw_js_errors = false
18
+
19
+ # If true, then cache the evaluation of JS for prerendering using the standard Rails cache.
20
+ # Applies to all rendering engines.
21
+ config.prerender_caching = true
22
+
23
+ # Get timing of server render calls
24
+ config.tracing = Rails.env.development?
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # HelloServer Controller - React Server Components
4
+ # This controller demonstrates how to render RSC pages with streaming SSR.
5
+ # It's the RSC counterpart to HelloWorldController.
6
+ #
7
+ # ReactOnRailsPro::Stream provides:
8
+ # - stream_view_containing_react_components: Streams the view with RSC support
9
+ # - Streaming HTML chunks as components render
10
+ # - Automatic hydration on the client
11
+ #
12
+ # For more information, see:
13
+ # https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
14
+
15
+ class HelloServerController < ApplicationController
16
+ include ReactOnRailsPro::Stream
17
+
18
+ def index
19
+ @hello_server_props = {
20
+ name: "React on Rails Pro"
21
+ }
22
+
23
+ stream_view_containing_react_components(template: "hello_server/index")
24
+ end
25
+ end
@@ -0,0 +1,80 @@
1
+ // HelloServer - React Server Component
2
+ //
3
+ // This component runs ONLY on the server. No JavaScript for it is sent to the browser.
4
+ // It demonstrates key RSC capabilities:
5
+ //
6
+ // 1. Async data fetching — use await directly in the component (no useEffect needed)
7
+ // 2. Server-only code — access databases, file systems, or secrets safely
8
+ // 3. Zero client JS — heavy libraries used here don't increase your bundle size
9
+ // 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
10
+ //
11
+ // For more information, see:
12
+ // https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
13
+
14
+ import React from 'react';
15
+ import LikeButton from './LikeButton';
16
+
17
+ // Simulate an async data fetch (replace with a real API call or DB query)
18
+ async function fetchGreeting(name) {
19
+ // In a real app, you could do:
20
+ // const data = await db.query('SELECT greeting FROM greetings WHERE name = ?', [name]);
21
+ // const file = await fs.readFile('./data/greeting.txt', 'utf-8');
22
+ // const res = await fetch('http://internal-api/greeting');
23
+ // eslint-disable-next-line no-promise-executor-return
24
+ await new Promise((resolve) => setTimeout(resolve, 100));
25
+
26
+ const now = new Date();
27
+ return {
28
+ message: `Hello, ${name}!`,
29
+ serverTime: now.toLocaleString('en-US', {
30
+ weekday: 'long',
31
+ year: 'numeric',
32
+ month: 'long',
33
+ day: 'numeric',
34
+ hour: '2-digit',
35
+ minute: '2-digit',
36
+ second: '2-digit',
37
+ timeZoneName: 'short',
38
+ }),
39
+ facts: [
40
+ 'This component rendered entirely on the server — zero JS was sent to the browser for it.',
41
+ 'The date formatting above used server-side Intl APIs — no date library shipped to the client.',
42
+ 'The "Like" button below IS a client component — only its JS is sent to the browser.',
43
+ ],
44
+ };
45
+ }
46
+
47
+ const HelloServer = async ({ name = 'World' }) => {
48
+ const { message, serverTime, facts } = await fetchGreeting(name);
49
+
50
+ return (
51
+ <div style={{ fontFamily: 'system-ui, sans-serif', maxWidth: 600, margin: '0 auto' }}>
52
+ <h2>{message}</h2>
53
+ <p style={{ color: '#666', fontSize: '0.9em' }}>Server-rendered at: {serverTime}</p>
54
+
55
+ <div
56
+ style={{
57
+ background: '#f0f9ff',
58
+ border: '1px solid #bae6fd',
59
+ borderRadius: 8,
60
+ padding: 16,
61
+ margin: '16px 0',
62
+ }}
63
+ >
64
+ <h3 style={{ margin: '0 0 12px' }}>How is this different from SSR?</h3>
65
+ <ul style={{ margin: 0, paddingLeft: 20 }}>
66
+ {facts.map((fact) => (
67
+ <li key={fact} style={{ marginBottom: 8 }}>
68
+ {fact}
69
+ </li>
70
+ ))}
71
+ </ul>
72
+ </div>
73
+
74
+ {/* LikeButton is a client component — it ships JS for interactivity */}
75
+ <LikeButton />
76
+ </div>
77
+ );
78
+ };
79
+
80
+ export default HelloServer;
@@ -0,0 +1,90 @@
1
+ // HelloServer - React Server Component
2
+ //
3
+ // This component runs ONLY on the server. No JavaScript for it is sent to the browser.
4
+ // It demonstrates key RSC capabilities:
5
+ //
6
+ // 1. Async data fetching — use await directly in the component (no useEffect needed)
7
+ // 2. Server-only code — access databases, file systems, or secrets safely
8
+ // 3. Zero client JS — heavy libraries used here don't increase your bundle size
9
+ // 4. Streaming — wrapped in <Suspense>, this component streams HTML as it resolves
10
+ //
11
+ // For more information, see:
12
+ // https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
13
+
14
+ import React from 'react';
15
+ import LikeButton from './LikeButton';
16
+
17
+ interface HelloServerProps {
18
+ name?: string;
19
+ }
20
+
21
+ interface GreetingData {
22
+ message: string;
23
+ serverTime: string;
24
+ facts: string[];
25
+ }
26
+
27
+ // Simulate an async data fetch (replace with a real API call or DB query)
28
+ async function fetchGreeting(name: string): Promise<GreetingData> {
29
+ // In a real app, you could do:
30
+ // const data = await db.query('SELECT greeting FROM greetings WHERE name = ?', [name]);
31
+ // const file = await fs.readFile('./data/greeting.txt', 'utf-8');
32
+ // const res = await fetch('http://internal-api/greeting');
33
+ // eslint-disable-next-line no-promise-executor-return
34
+ await new Promise((resolve) => setTimeout(resolve, 100));
35
+
36
+ const now = new Date();
37
+ return {
38
+ message: `Hello, ${name}!`,
39
+ serverTime: now.toLocaleString('en-US', {
40
+ weekday: 'long',
41
+ year: 'numeric',
42
+ month: 'long',
43
+ day: 'numeric',
44
+ hour: '2-digit',
45
+ minute: '2-digit',
46
+ second: '2-digit',
47
+ timeZoneName: 'short',
48
+ }),
49
+ facts: [
50
+ 'This component rendered entirely on the server — zero JS was sent to the browser for it.',
51
+ 'The date formatting above used server-side Intl APIs — no date library shipped to the client.',
52
+ 'The "Like" button below IS a client component — only its JS is sent to the browser.',
53
+ ],
54
+ };
55
+ }
56
+
57
+ const HelloServer = async ({ name = 'World' }: HelloServerProps) => {
58
+ const { message, serverTime, facts } = await fetchGreeting(name);
59
+
60
+ return (
61
+ <div style={{ fontFamily: 'system-ui, sans-serif', maxWidth: 600, margin: '0 auto' }}>
62
+ <h2>{message}</h2>
63
+ <p style={{ color: '#666', fontSize: '0.9em' }}>Server-rendered at: {serverTime}</p>
64
+
65
+ <div
66
+ style={{
67
+ background: '#f0f9ff',
68
+ border: '1px solid #bae6fd',
69
+ borderRadius: 8,
70
+ padding: 16,
71
+ margin: '16px 0',
72
+ }}
73
+ >
74
+ <h3 style={{ margin: '0 0 12px' }}>How is this different from SSR?</h3>
75
+ <ul style={{ margin: 0, paddingLeft: 20 }}>
76
+ {facts.map((fact) => (
77
+ <li key={fact} style={{ marginBottom: 8 }}>
78
+ {fact}
79
+ </li>
80
+ ))}
81
+ </ul>
82
+ </div>
83
+
84
+ {/* LikeButton is a client component — it ships JS for interactivity */}
85
+ <LikeButton />
86
+ </div>
87
+ );
88
+ };
89
+
90
+ export default HelloServer;
@@ -0,0 +1,54 @@
1
+ 'use client';
2
+
3
+ // LikeButton - Client Component
4
+ //
5
+ // This component has the 'use client' directive, so its JavaScript IS sent to the browser.
6
+ // It demonstrates how client components work alongside server components:
7
+ //
8
+ // - Only this component's JS is included in the client bundle
9
+ // - The parent HelloServer component sends ZERO JS to the browser
10
+ // - React hydrates just this interactive island within the server-rendered HTML
11
+
12
+ import React, { useState } from 'react';
13
+
14
+ const LikeButton = () => {
15
+ const [likes, setLikes] = useState(0);
16
+
17
+ return (
18
+ <div
19
+ style={{
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ gap: 12,
23
+ marginTop: 16,
24
+ padding: '12px 16px',
25
+ background: '#fefce8',
26
+ border: '1px solid #fde68a',
27
+ borderRadius: 8,
28
+ }}
29
+ >
30
+ <button
31
+ type="button"
32
+ onClick={() => setLikes((prev) => prev + 1)}
33
+ style={{
34
+ padding: '8px 16px',
35
+ fontSize: '1em',
36
+ cursor: 'pointer',
37
+ borderRadius: 6,
38
+ border: '1px solid #d1d5db',
39
+ background: '#fff',
40
+ }}
41
+ >
42
+ 👍 Like
43
+ </button>
44
+ <span>
45
+ {likes} {likes === 1 ? 'like' : 'likes'}
46
+ </span>
47
+ <span style={{ color: '#92400e', fontSize: '0.85em' }}>
48
+ ← This button is a client component (check your browser&apos;s Network tab — only its JS was sent)
49
+ </span>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default LikeButton;
@@ -0,0 +1,54 @@
1
+ 'use client';
2
+
3
+ // LikeButton - Client Component
4
+ //
5
+ // This component has the 'use client' directive, so its JavaScript IS sent to the browser.
6
+ // It demonstrates how client components work alongside server components:
7
+ //
8
+ // - Only this component's JS is included in the client bundle
9
+ // - The parent HelloServer component sends ZERO JS to the browser
10
+ // - React hydrates just this interactive island within the server-rendered HTML
11
+
12
+ import React, { useState } from 'react';
13
+
14
+ const LikeButton: React.FC = () => {
15
+ const [likes, setLikes] = useState(0);
16
+
17
+ return (
18
+ <div
19
+ style={{
20
+ display: 'flex',
21
+ alignItems: 'center',
22
+ gap: 12,
23
+ marginTop: 16,
24
+ padding: '12px 16px',
25
+ background: '#fefce8',
26
+ border: '1px solid #fde68a',
27
+ borderRadius: 8,
28
+ }}
29
+ >
30
+ <button
31
+ type="button"
32
+ onClick={() => setLikes((prev) => prev + 1)}
33
+ style={{
34
+ padding: '8px 16px',
35
+ fontSize: '1em',
36
+ cursor: 'pointer',
37
+ borderRadius: 6,
38
+ border: '1px solid #d1d5db',
39
+ background: '#fff',
40
+ }}
41
+ >
42
+ 👍 Like
43
+ </button>
44
+ <span>
45
+ {likes} {likes === 1 ? 'like' : 'likes'}
46
+ </span>
47
+ <span style={{ color: '#92400e', fontSize: '0.85em' }}>
48
+ ← This button is a client component (check your browser&apos;s Network tab — only its JS was sent)
49
+ </span>
50
+ </div>
51
+ );
52
+ };
53
+
54
+ export default LikeButton;
@@ -0,0 +1,10 @@
1
+ // HelloServer Entry Point - Re-exports the server component for auto_load_bundle
2
+ // This file is discovered by React on Rails' auto_load_bundle feature
3
+ // and registered automatically in both client and server bundles.
4
+ //
5
+ // Note: No 'use client' directive here - this is a Server Component.
6
+ // The actual component in ../components/HelloServer.jsx runs only on the server.
7
+
8
+ import HelloServer from '../components/HelloServer';
9
+
10
+ export default HelloServer;
@@ -0,0 +1,10 @@
1
+ // HelloServer Entry Point - Re-exports the server component for auto_load_bundle
2
+ // This file is discovered by React on Rails' auto_load_bundle feature
3
+ // and registered automatically in both client and server bundles.
4
+ //
5
+ // Note: No 'use client' directive here - this is a Server Component.
6
+ // The actual component in ../components/HelloServer.tsx runs only on the server.
7
+
8
+ import HelloServer from '../components/HelloServer';
9
+
10
+ export default HelloServer;
@@ -0,0 +1,37 @@
1
+ <h1>React Server Components Demo</h1>
2
+
3
+ <p>
4
+ This page demonstrates <strong>React Server Components (RSC)</strong> with React on Rails Pro.
5
+ The component below is an <em>async server component</em> that fetches data on the server
6
+ and streams HTML to the browser. No component JavaScript is sent to the client.
7
+ </p>
8
+
9
+ <%#
10
+ stream_react_component renders the RSC with streaming support.
11
+
12
+ Key points:
13
+ - prerender: true enables server-side rendering with streaming
14
+ - Props are passed from the controller (@hello_server_props)
15
+ - The component streams as it resolves (async data fetching happens server-side)
16
+ - Only the interactive LikeButton client component ships JS to the browser
17
+ - Open DevTools Network tab to verify — no HelloServer.js in the client bundle
18
+ %>
19
+ <%= stream_react_component('HelloServer', props: @hello_server_props, prerender: true) %>
20
+
21
+ <hr>
22
+
23
+ <details style="margin-top: 16px;">
24
+ <summary><strong>What makes this different from traditional SSR?</strong></summary>
25
+ <ul style="margin-top: 8px;">
26
+ <li><strong>Traditional SSR:</strong> Server renders HTML, then ships ALL component JS to the browser for hydration. Every library used in rendering is in your bundle.</li>
27
+ <li><strong>RSC:</strong> Server components stay on the server permanently. Only client components (marked with <code>'use client'</code>) ship JS. Libraries used in server components are never bundled for the client.</li>
28
+ <li><strong>Async by default:</strong> Server components can be async functions that <code>await</code> data directly — no <code>useEffect</code>, no loading states for initial render, no client-side fetch waterfalls.</li>
29
+ </ul>
30
+ </details>
31
+
32
+ <p style="margin-top: 16px;">
33
+ <strong>Learn more:</strong>
34
+ <a href="https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/">
35
+ React Server Components Documentation
36
+ </a>
37
+ </p>
@@ -0,0 +1,64 @@
1
+ // React Server Components webpack configuration
2
+ // This creates the RSC bundle based on the server webpack config
3
+ // See: https://www.shakacode.com/react-on-rails-pro/docs/react-server-components/
4
+
5
+ const serverWebpackModule = require('./serverWebpackConfig');
6
+
7
+ // Backward compatibility:
8
+ // - New Pro config exports: { default: configureServer, extractLoader }
9
+ // - Legacy config exports: module.exports = configureServer
10
+ const serverWebpackConfig = serverWebpackModule.default || serverWebpackModule;
11
+ const extractLoader = serverWebpackModule.extractLoader || ((rule, loaderName) => {
12
+ if (!Array.isArray(rule.use)) return null;
13
+ return rule.use.find((item) => {
14
+ const testValue = typeof item === 'string' ? item : item.loader;
15
+ return testValue && testValue.includes(loaderName);
16
+ });
17
+ });
18
+
19
+ const configureRsc = () => {
20
+ // Pass true to skip RSCWebpackPlugin - RSC bundle doesn't need it
21
+ const rscConfig = serverWebpackConfig(true);
22
+
23
+ // Update the entry name to be `rsc-bundle` instead of `server-bundle`
24
+ const rscEntry = {
25
+ 'rsc-bundle': rscConfig.entry['server-bundle'],
26
+ };
27
+ rscConfig.entry = rscEntry;
28
+
29
+ // Add the RSC loader before the JS loader (babel-loader or swc-loader)
30
+ // This loader properly excludes client components from the RSC bundle
31
+ const { rules } = rscConfig.module;
32
+ rules.forEach((rule) => {
33
+ if (Array.isArray(rule.use)) {
34
+ // Find the JS loader (could be babel-loader or swc-loader depending on configuration)
35
+ const jsLoader = extractLoader(rule, 'babel-loader') || extractLoader(rule, 'swc-loader');
36
+ if (jsLoader) {
37
+ rule.use.push({
38
+ loader: 'react-on-rails-rsc/WebpackLoader',
39
+ });
40
+ }
41
+ }
42
+ });
43
+
44
+ // Add the `react-server` condition to the resolve config
45
+ // This condition is used by React and React on Rails to identify RSC bundles
46
+ // The `...` tells webpack to retain the default conditions (e.g., `node` for server target)
47
+ rscConfig.resolve = {
48
+ ...rscConfig.resolve,
49
+ conditionNames: ['react-server', '...'],
50
+ alias: {
51
+ ...rscConfig.resolve?.alias,
52
+ // Ignore react-dom/server in RSC bundle - it's not needed for RSC payload generation
53
+ // Not removing it will cause a runtime error
54
+ 'react-dom/server': false,
55
+ },
56
+ };
57
+
58
+ // Update the output bundle name to be `rsc-bundle.js` instead of `server-bundle.js`
59
+ rscConfig.output.filename = 'rsc-bundle.js';
60
+
61
+ return rscConfig;
62
+ };
63
+
64
+ module.exports = configureRsc;
@@ -69,8 +69,12 @@ module ReactOnRails
69
69
 
70
70
  # Check if we're running a Rails generator
71
71
  # @return [Boolean] true if running a generator
72
+ #
73
+ # Heuristic: Rails::Generators is typically only defined during generator
74
+ # commands. It could be defined by test helpers or gems that require
75
+ # "rails/generators", but this is a fallback behind the ENV check above.
72
76
  def self.running_generator?
73
- !ARGV.empty? && ARGV.first&.in?(%w[generate g])
77
+ defined?(Rails::Generators)
74
78
  end
75
79
 
76
80
  # Check if package.json doesn't exist yet
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "16.4.0.rc.1"
4
+ VERSION = "16.4.0.rc.2"
5
5
  end
@@ -121,7 +121,12 @@ module ReactOnRails
121
121
 
122
122
  When using React on Rails Pro, you must use the 'react-on-rails-pro' npm package.
123
123
 
124
- Fix:
124
+ If you're upgrading from React on Rails to Pro, run the generator with validation skipped:
125
+ REACT_ON_RAILS_SKIP_VALIDATION=true rails g react_on_rails:install --pro
126
+
127
+ The generator will automatically replace the base package with the Pro package.
128
+
129
+ Or fix manually:
125
130
  1. Remove the base package: #{remove_cmd}
126
131
  2. Install the Pro package: #{install_cmd}
127
132
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.4.0.rc.1
4
+ version: 16.4.0.rc.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-02-13 00:00:00.000000000 Z
11
+ date: 2026-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -131,8 +131,14 @@ files:
131
131
  - lib/generators/react_on_rails/generator_messages.rb
132
132
  - lib/generators/react_on_rails/install_generator.rb
133
133
  - lib/generators/react_on_rails/js_dependency_manager.rb
134
+ - lib/generators/react_on_rails/pro/USAGE
135
+ - lib/generators/react_on_rails/pro_generator.rb
136
+ - lib/generators/react_on_rails/pro_setup.rb
134
137
  - lib/generators/react_on_rails/react_no_redux_generator.rb
135
138
  - lib/generators/react_on_rails/react_with_redux_generator.rb
139
+ - lib/generators/react_on_rails/rsc/USAGE
140
+ - lib/generators/react_on_rails/rsc_generator.rb
141
+ - lib/generators/react_on_rails/rsc_setup.rb
136
142
  - lib/generators/react_on_rails/templates/.eslintrc
137
143
  - lib/generators/react_on_rails/templates/base/base/.dev-services.yml.example
138
144
  - lib/generators/react_on_rails/templates/base/base/Procfile.dev
@@ -156,10 +162,10 @@ files:
156
162
  - lib/generators/react_on_rails/templates/base/base/bin/switch-bundler
157
163
  - lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt
158
164
  - lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml.tt
165
+ - lib/generators/react_on_rails/templates/base/base/config/webpack/ServerClientOrBoth.js.tt
159
166
  - lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt
160
167
  - lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt
161
168
  - lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt
162
- - lib/generators/react_on_rails/templates/base/base/config/webpack/generateWebpackConfigs.js.tt
163
169
  - lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt
164
170
  - lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt
165
171
  - lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt
@@ -169,7 +175,10 @@ files:
169
175
  - lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb
170
176
  - lib/generators/react_on_rails/templates/dev_tests/spec/simplecov_helper.rb
171
177
  - lib/generators/react_on_rails/templates/dev_tests/spec/spec_helper.rb
178
+ - lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_server_spec.rb
172
179
  - lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb
180
+ - lib/generators/react_on_rails/templates/pro/base/client/node-renderer.js
181
+ - lib/generators/react_on_rails/templates/pro/base/config/initializers/react_on_rails_pro.rb.tt
173
182
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/actions/helloWorldActionCreators.js
174
183
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/actions/helloWorldActionCreators.ts
175
184
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx
@@ -187,6 +196,15 @@ files:
187
196
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.tsx
188
197
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.js
189
198
  - lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.ts
199
+ - lib/generators/react_on_rails/templates/rsc/base/app/controllers/hello_server_controller.rb
200
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.jsx
201
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/HelloServer.tsx
202
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.jsx
203
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/components/LikeButton.tsx
204
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.jsx
205
+ - lib/generators/react_on_rails/templates/rsc/base/app/javascript/src/HelloServer/ror_components/HelloServer.tsx
206
+ - lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb
207
+ - lib/generators/react_on_rails/templates/rsc/base/config/webpack/rscWebpackConfig.js.tt
190
208
  - lib/react_on_rails.rb
191
209
  - lib/react_on_rails/configuration.rb
192
210
  - lib/react_on_rails/controller.rb