Skip to content

Commit

Permalink
pass rsc path to RSC Client Root and move the config to RORP
Browse files Browse the repository at this point in the history
  • Loading branch information
AbanoubGhadban committed Jan 13, 2025
1 parent a761735 commit 1f3e921
Show file tree
Hide file tree
Showing 9 changed files with 101 additions and 40 deletions.
11 changes: 3 additions & 8 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ def self.configure
end

DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
DEFAULT_RSC_RENDERING_URL = "rsc/".freeze

def self.configuration
@configuration ||= Configuration.new(
Expand Down Expand Up @@ -43,9 +42,7 @@ def self.configuration
make_generated_server_bundle_the_entrypoint: false,
defer_generated_component_packs: true,
# forces the loading of React components
force_load: false,
auto_load_server_components: true,
rsc_rendering_url: DEFAULT_RSC_RENDERING_URL
force_load: false
)
end

Expand All @@ -60,7 +57,7 @@ class Configuration
:same_bundle_for_client_and_server, :rendering_props_extension,
:make_generated_server_bundle_the_entrypoint,
:defer_generated_component_packs, :rsc_bundle_js_file,
:force_load, :auto_load_server_components, :rsc_rendering_url
:force_load

# rubocop:disable Metrics/AbcSize
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
Expand All @@ -76,7 +73,7 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil,
rsc_bundle_js_file: nil, auto_load_server_components: nil, rsc_rendering_url: nil)
rsc_bundle_js_file: nil)
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
self.generated_assets_dirs = generated_assets_dirs
self.generated_assets_dir = generated_assets_dir
Expand Down Expand Up @@ -116,8 +113,6 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
self.make_generated_server_bundle_the_entrypoint = make_generated_server_bundle_the_entrypoint
self.defer_generated_component_packs = defer_generated_component_packs
self.force_load = force_load
self.auto_load_server_components = auto_load_server_components
self.rsc_rendering_url = rsc_rendering_url
end
# rubocop:enable Metrics/AbcSize

Expand Down
40 changes: 26 additions & 14 deletions lib/react_on_rails/packs_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,30 +46,30 @@ def create_pack(file_path)

def first_js_statement_in_code(content)
return "" if content.nil? || content.empty?

start_index = 0
content_length = content.length

while start_index < content_length
# Skip whitespace
while start_index < content_length && content[start_index].match?(/\s/)
start_index += 1
end

start_index += 1 while start_index < content_length && content[start_index].match?(/\s/)

break if start_index >= content_length

current_chars = content[start_index, 2]

case current_chars
when '//'
when "//"
# Single-line comment
newline_index = content.index("\n", start_index)
return "" if newline_index.nil?

start_index = newline_index + 1
when '/*'
when "/*"
# Multi-line comment
comment_end = content.index('*/', start_index)
comment_end = content.index("*/", start_index)
return "" if comment_end.nil?

start_index = comment_end + 2
else
# Found actual content
Expand All @@ -89,9 +89,21 @@ def is_client_entrypoint?(file_path)

def pack_file_contents(file_path)
registered_component_name = component_name(file_path)
register_as_server_component = ReactOnRails.configuration.auto_load_server_components && !is_client_entrypoint?(file_path)
import_statement = register_as_server_component ? "" : "import #{registered_component_name} from '#{relative_component_path_from_generated_pack(file_path)}';"
register_call = register_as_server_component ? "registerServerComponent(\"#{registered_component_name}\")" : "register({#{registered_component_name}})";
load_server_components = ReactOnRails::Utils.react_on_rails_pro? && ReactOnRailsPro.configuration.enable_rsc_support

if load_server_components && !is_client_entrypoint?(file_path)
import_statement = ""
rsc_rendering_url_path = ReactOnRailsPro.configuration.rsc_rendering_url_path
register_call = <<~REGISTER_CALL.strip
registerServerComponent({
rscRenderingUrlPath: "#{rsc_rendering_url_path}",
}, "#{registered_component_name}")
REGISTER_CALL
else
relative_component_path = relative_component_path_from_generated_pack(file_path)
import_statement = "import #{registered_component_name} from '#{relative_component_path}';"
register_call = "register({#{registered_component_name}})"
end

<<~FILE_CONTENT
import ReactOnRails from 'react-on-rails';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def reset_pool
def reset_pool_if_server_bundle_was_modified
return unless ReactOnRails.configuration.development_mode

# RSC (React Server Components) bundle changes are not monitored here since:
# 1. RSC is only supported in the Pro version of React on Rails
# 2. This RubyEmbeddedJavaScript pool is used exclusively in the non-Pro version
# 3. This pool uses ExecJS for JavaScript evaluation which does not support RSC
if ReactOnRails::Utils.server_bundle_path_is_http?
return if @server_bundle_url == ReactOnRails::Utils.server_bundle_js_file_path

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ def stale_generated_files(files)
def all_compiled_assets
@all_compiled_assets ||= begin
webpack_generated_files = @webpack_generated_files.map do |bundle_name|
if bundle_name == ReactOnRails.configuration.server_bundle_js_file
ReactOnRails::Utils.server_bundle_js_file_path
if bundle_name == ReactOnRails.configuration.react_client_manifest_file
ReactOnRails::Utils.react_client_manifest_file_path
else
ReactOnRails::Utils.bundle_js_file_path(bundle_name)
end
Expand Down
11 changes: 9 additions & 2 deletions node_package/src/ComponentRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
type ReactComponentOrRenderFunction,
type RenderFunction,
type ItemRegistrationCallback,
type RegisterServerComponentOptions,
} from './types';
import isRenderFunction from './isRenderFunction';
import CallbackRegistry from './CallbackRegistry';
Expand Down Expand Up @@ -49,12 +50,18 @@ export default {
});
},

registerServerComponent(...componentNames: string[]): void {
registerServerComponent(options: RegisterServerComponentOptions, ...componentNames: string[]): void {
// eslint-disable-next-line global-require, @typescript-eslint/no-var-requires
const RSCClientRoot = (require('./RSCClientRoot') as typeof import('./RSCClientRoot')).default;

const componentsWrappedInRSCClientRoot = componentNames.reduce(
(acc, name) => ({ ...acc, [name]: () => React.createElement(RSCClientRoot, { componentName: name }) }),
(acc, name) => ({
...acc,
[name]: () => React.createElement(RSCClientRoot, {
componentName: name,
rscRenderingUrlPath: options.rscRenderingUrlPath
})
}),
{}
);
this.register(componentsWrappedInRSCClientRoot);
Expand Down
14 changes: 11 additions & 3 deletions node_package/src/RSCClientRoot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,21 @@ const { use } = React;

const renderCache: Record<string, Promise<React.ReactNode>> = {};

const fetchRSC = ({ componentName }: { componentName: string }) => {
export type RSCClientRootProps = {
componentName: string;
rscRenderingUrlPath: string;
}

const fetchRSC = ({ componentName, rscRenderingUrlPath }: RSCClientRootProps) => {
if (!renderCache[componentName]) {
renderCache[componentName] = RSDWClient.createFromFetch(fetch(`/rsc/${componentName}`)) as Promise<React.ReactNode>;
renderCache[componentName] = RSDWClient.createFromFetch(fetch(`${rscRenderingUrlPath}/${componentName}`)) as Promise<React.ReactNode>;
}
return renderCache[componentName];
}

const RSCClientRoot = ({ componentName }: { componentName: string }) => use(fetchRSC({ componentName }));
const RSCClientRoot = ({
componentName,
rscRenderingUrlPath,
}: RSCClientRootProps) => use(fetchRSC({ componentName, rscRenderingUrlPath }));

export default RSCClientRoot;
5 changes: 3 additions & 2 deletions node_package/src/ReactOnRails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
AuthenticityHeaders,
Store,
StoreGenerator,
RegisterServerComponentOptions,
} from './types';
import reactHydrateOrRender from './reactHydrateOrRender';

Expand Down Expand Up @@ -62,8 +63,8 @@ ctx.ReactOnRails = {
* When it's rendered, a call will be made to the server to render it.
* @param componentNames
*/
registerServerComponent(...componentNames: string[]): void {
ComponentRegistry.registerServerComponent(...componentNames);
registerServerComponent(options: RegisterServerComponentOptions, ...componentNames: string[]): void {
ComponentRegistry.registerServerComponent(options, ...componentNames);
},

registerStore(stores: { [id: string]: StoreGenerator }): void {
Expand Down
6 changes: 5 additions & 1 deletion node_package/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export interface RegisteredComponent {
isRenderer: boolean;
}

export interface RegisterServerComponentOptions {
rscRenderingUrlPath: string;
}

export type ItemRegistrationCallback<T> = (component: T) => void;

interface Params {
Expand Down Expand Up @@ -156,7 +160,7 @@ export type RenderReturnType = void | Element | Component | Root;

export interface ReactOnRails {
register(components: { [id: string]: ReactComponentOrRenderFunction }): void;
registerServerComponent(...componentNames: string[]): void;
registerServerComponent(options: RegisterServerComponentOptions, ...componentNames: string[]): void;
/** @deprecated Use registerStoreGenerators instead */
registerStore(stores: { [id: string]: StoreGenerator }): void;
registerStoreGenerators(storeGenerators: { [id: string]: StoreGenerator }): void;
Expand Down
Loading

0 comments on commit 1f3e921

Please sign in to comment.