Skip to content

Commit 56ee2bd

Browse files
should force load react-components which send over turbo-stream (#1620)
* should force load react-components which send over turbo-stream * fix navigation error in spec
1 parent 4cdc686 commit 56ee2bd

File tree

20 files changed

+158
-6
lines changed

20 files changed

+158
-6
lines changed

Gemfile.development_dependencies

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ gem "sprockets", "~> 4.0"
2222

2323
gem "amazing_print"
2424

25+
gem "turbo-rails"
26+
2527
group :development, :test do
2628
gem "package_json"
2729
gem "listen"

Gemfile.lock

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
react_on_rails (14.0.3)
4+
react_on_rails (14.0.4)
55
addressable
66
connection_pool
77
execjs (~> 2.5)
@@ -369,6 +369,10 @@ GEM
369369
tins (1.33.0)
370370
bigdecimal
371371
sync
372+
turbo-rails (2.0.6)
373+
actionpack (>= 6.0.0)
374+
activejob (>= 6.0.0)
375+
railties (>= 6.0.0)
372376
turbolinks (5.2.1)
373377
turbolinks-source (~> 5.2)
374378
turbolinks-source (5.2.0)
@@ -431,6 +435,7 @@ DEPENDENCIES
431435
spring (~> 4.0)
432436
sprockets (~> 4.0)
433437
sqlite3 (~> 1.6)
438+
turbo-rails
434439
turbolinks
435440
uglifier
436441
webdrivers (= 5.3.0)

lib/react_on_rails/configuration.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ def self.configuration
3939
i18n_output_format: nil,
4040
components_subdirectory: nil,
4141
make_generated_server_bundle_the_entrypoint: false,
42-
defer_generated_component_packs: true
42+
defer_generated_component_packs: true,
43+
# forces the loading of React components
44+
force_load: false
4345
)
4446
end
4547

@@ -53,7 +55,8 @@ class Configuration
5355
:server_render_method, :random_dom_id, :auto_load_bundle,
5456
:same_bundle_for_client_and_server, :rendering_props_extension,
5557
:make_generated_server_bundle_the_entrypoint,
56-
:defer_generated_component_packs
58+
:defer_generated_component_packs,
59+
:force_load
5760

5861
# rubocop:disable Metrics/AbcSize
5962
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
@@ -68,7 +71,7 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
6871
same_bundle_for_client_and_server: nil,
6972
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
7073
random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
71-
components_subdirectory: nil, auto_load_bundle: nil)
74+
components_subdirectory: nil, auto_load_bundle: nil, force_load: nil)
7275
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
7376
self.generated_assets_dirs = generated_assets_dirs
7477
self.generated_assets_dir = generated_assets_dir
@@ -106,6 +109,7 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
106109
self.auto_load_bundle = auto_load_bundle
107110
self.make_generated_server_bundle_the_entrypoint = make_generated_server_bundle_the_entrypoint
108111
self.defer_generated_component_packs = defer_generated_component_packs
112+
self.force_load = force_load
109113
end
110114
# rubocop:enable Metrics/AbcSize
111115

lib/react_on_rails/helper.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,14 @@ def internal_react_component(react_component_name, options = {})
441441
"data-trace" => (render_options.trace ? true : nil),
442442
"data-dom-id" => render_options.dom_id)
443443

444+
if render_options.force_load
445+
component_specification_tag.concat(
446+
content_tag(:script, %(
447+
ReactOnRails.reactOnRailsComponentLoaded('#{render_options.dom_id}');
448+
).html_safe)
449+
)
450+
end
451+
444452
load_pack_for_generated_component(react_component_name, render_options)
445453
# Create the HTML rendering part
446454
result = server_rendered_react_component(render_options)

lib/react_on_rails/react_component/render_options.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ def logging_on_server
9191
retrieve_configuration_value_for(:logging_on_server)
9292
end
9393

94+
def force_load
95+
retrieve_configuration_value_for(:force_load)
96+
end
97+
9498
def to_s
9599
"{ react_component_name = #{react_component_name}, options = #{options}, request_digest = #{request_digest}"
96100
end

node_package/src/ReactOnRails.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ ctx.ReactOnRails = {
133133
ClientStartup.reactOnRailsPageLoaded();
134134
},
135135

136+
reactOnRailsComponentLoaded(domId: string): void {
137+
ClientStartup.reactOnRailsComponentLoaded(domId);
138+
},
139+
136140
/**
137141
* Returns CSRF authenticity token inserted by Rails csrf_meta_tags
138142
* @returns String or null

node_package/src/clientStartup.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,25 @@ export function reactOnRailsPageLoaded(): void {
218218
forEachReactOnRailsComponentRender(context, railsContext);
219219
}
220220

221+
export function reactOnRailsComponentLoaded(domId: string): void {
222+
debugTurbolinks(`reactOnRailsComponentLoaded ${domId}`);
223+
224+
const railsContext = parseRailsContext();
225+
226+
// If no react on rails components
227+
if (!railsContext) return;
228+
229+
const context = findContext();
230+
if (supportsRootApi) {
231+
context.roots = [];
232+
}
233+
234+
const el = document.querySelector(`[data-dom-id=${domId}]`);
235+
if (!el) return;
236+
237+
render(el, context, railsContext);
238+
}
239+
221240
function unmount(el: Element): void {
222241
const domNodeId = domNodeIdForEl(el);
223242
const domNode = document.getElementById(domNodeId);

node_package/src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export interface ReactOnRails {
126126
setOptions(newOptions: {traceTurbolinks: boolean}): void;
127127
reactHydrateOrRender(domNode: Element, reactElement: ReactElement, hydrate: boolean): RenderReturnType;
128128
reactOnRailsPageLoaded(): void;
129+
reactOnRailsComponentLoaded(domId: string): void;
129130
authenticityToken(): string | null;
130131
authenticityHeaders(otherHeaders: { [id: string]: string }): AuthenticityHeaders;
131132
option(key: string): string | number | boolean | undefined;

spec/dummy/Gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,10 @@ GEM
362362
timeout (0.4.1)
363363
tins (1.32.1)
364364
sync
365+
turbo-rails (2.0.6)
366+
actionpack (>= 6.0.0)
367+
activejob (>= 6.0.0)
368+
railties (>= 6.0.0)
365369
turbolinks (5.2.1)
366370
turbolinks-source (~> 5.2)
367371
turbolinks-source (5.2.0)
@@ -423,6 +427,7 @@ DEPENDENCIES
423427
spring (~> 4.0)
424428
sprockets (~> 4.0)
425429
sqlite3 (~> 1.6)
430+
turbo-rails
426431
turbolinks
427432
uglifier
428433
webdrivers (= 5.3.0)

spec/dummy/app/controllers/pages_controller.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ def data
3636
}.merge(xss_payload)
3737
}
3838

39+
@app_props_hello_from_turbo_stream = {
40+
helloTurboStreamData: {
41+
name: "Mrs. Client Side Rendering From Turbo Stream"
42+
}.merge(xss_payload)
43+
}
44+
3945
@app_props_hello_again = {
4046
helloWorldData: {
4147
name: "Mrs. Client Side Hello Again"

0 commit comments

Comments
 (0)