react_on_rails 14.0.4 → 15.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -2
- data/Gemfile.development_dependencies +2 -0
- data/Gemfile.lock +6 -1
- data/README.md +1 -0
- data/SUMMARY.md +1 -0
- data/lib/react_on_rails/configuration.rb +7 -3
- data/lib/react_on_rails/helper.rb +144 -18
- data/lib/react_on_rails/react_component/render_options.rb +20 -0
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +34 -20
- data/lib/react_on_rails/version.rb +1 -1
- data/tsconfig.json +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d60051000fbd817b3499b1de6f13c9abeaf5627bee250c50bf0d748ce3532a5
|
4
|
+
data.tar.gz: 4eccfe81e12b647503fa6e690c514d4d14d6704ab1e5c7f64282cafa7709d6e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99004f6792fe209d21474c7b5b311ac8a02cce27740b69164e44079983a5852895aa99ed12530043ba64ad6920d189cb6b19ce3957aca83b6bab06f75bf702ee
|
7
|
+
data.tar.gz: 2be5eb3178a913c90c7b4e640812bccc479245d0052d95751317f543c80e7bf9429f9fd61cbc1c5edb917aafbead33502c75fb63fd8ab183480aaa44124f3dc5
|
data/CHANGELOG.md
CHANGED
@@ -18,6 +18,26 @@ Please follow the recommendations outlined at [keepachangelog.com](http://keepac
|
|
18
18
|
### [Unreleased]
|
19
19
|
Changes since the last non-beta release.
|
20
20
|
|
21
|
+
#### Added(https://github.com/AbanoubGhadban).
|
22
|
+
- Added streaming server rendering support:
|
23
|
+
- [PR #1633](https://github.com/shakacode/react_on_rails/pull/1633) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
24
|
+
- New `stream_react_component` helper for adding streamed components to views
|
25
|
+
- New `streamServerRenderedReactComponent` function in the react-on-rails package that uses React 18's `renderToPipeableStream` API
|
26
|
+
- Enables progressive page loading and improved performance for server-rendered React components
|
27
|
+
- Added support for replaying console logs that occur during server rendering of streamed React components. This enables debugging of server-side rendering issues by capturing and displaying console output on the client and on the server output. [PR #1647](https://github.com/shakacode/react_on_rails/pull/1647) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
28
|
+
- Added support for handling errors happening during server rendering of streamed React components. It handles errors that happen during the initial render and errors that happen inside suspense boundaries. [PR #1648](https://github.com/shakacode/react_on_rails/pull/1648) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
29
|
+
|
30
|
+
#### Changed
|
31
|
+
- Console replay script generation now awaits the render request promise before generating, allowing it to capture console logs from asynchronous operations. This requires using a version of the Node renderer that supports replaying async console logs. [PR #1649](https://github.com/shakacode/react_on_rails/pull/1649) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
32
|
+
|
33
|
+
#### Fixed
|
34
|
+
- Incorrect type and confusing name for `ReactOnRails.registerStore`, use `registerStoreGenerators` instead. [PR 1651](https://github.com/shakacode/react_on_rails/pull/1651) by [alexeyr-ci](https://github.com/alexeyr-ci).
|
35
|
+
|
36
|
+
### [14.0.5] - 2024-08-20
|
37
|
+
#### Fixed
|
38
|
+
- Should force load react-components which send over turbo-stream [PR #1620](https://github.com/shakacode/react_on_rails/pull/1620) by [theforestvn88](https://github.com/theforestvn88).
|
39
|
+
|
40
|
+
### [14.0.4] - 2024-07-02
|
21
41
|
|
22
42
|
#### Improved
|
23
43
|
- Improved dependency management by integrating package_json. [PR 1639](https://github.com/shakacode/react_on_rails/pull/1639) by [vaukalak](https://github.com/vaukalak).
|
@@ -25,7 +45,6 @@ Changes since the last non-beta release.
|
|
25
45
|
#### Changed
|
26
46
|
- Update outdated GitHub Actions to use Node.js 20.0 versions instead [PR 1623](https://github.com/shakacode/react_on_rails/pull/1623) by [adriangohjw](https://github.com/adriangohjw).
|
27
47
|
|
28
|
-
|
29
48
|
### [14.0.3] - 2024-06-28
|
30
49
|
|
31
50
|
#### Fixed
|
@@ -1148,7 +1167,9 @@ Best done with Object destructing:
|
|
1148
1167
|
##### Fixed
|
1149
1168
|
- Fix several generator-related issues.
|
1150
1169
|
|
1151
|
-
[Unreleased]: https://github.com/shakacode/react_on_rails/compare/14.0.
|
1170
|
+
[Unreleased]: https://github.com/shakacode/react_on_rails/compare/14.0.5...master
|
1171
|
+
[14.0.5]: https://github.com/shakacode/react_on_rails/compare/14.0.4...14.0.5
|
1172
|
+
[14.0.4]: https://github.com/shakacode/react_on_rails/compare/14.0.3...14.0.4
|
1152
1173
|
[14.0.3]: https://github.com/shakacode/react_on_rails/compare/14.0.2...14.0.3
|
1153
1174
|
[14.0.2]: https://github.com/shakacode/react_on_rails/compare/14.0.1...14.0.2
|
1154
1175
|
[14.0.1]: https://github.com/shakacode/react_on_rails/compare/14.0.0...14.0.1
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
react_on_rails (14.0.
|
4
|
+
react_on_rails (14.0.5)
|
5
5
|
addressable
|
6
6
|
connection_pool
|
7
7
|
execjs (~> 2.5)
|
@@ -369,6 +369,10 @@ GEM
|
|
369
369
|
tins (1.33.0)
|
370
370
|
bigdecimal
|
371
371
|
sync
|
372
|
+
turbo-rails (2.0.6)
|
373
|
+
actionpack (>= 6.0.0)
|
374
|
+
activejob (>= 6.0.0)
|
375
|
+
railties (>= 6.0.0)
|
372
376
|
turbolinks (5.2.1)
|
373
377
|
turbolinks-source (~> 5.2)
|
374
378
|
turbolinks-source (5.2.0)
|
@@ -431,6 +435,7 @@ DEPENDENCIES
|
|
431
435
|
spring (~> 4.0)
|
432
436
|
sprockets (~> 4.0)
|
433
437
|
sqlite3 (~> 1.6)
|
438
|
+
turbo-rails
|
434
439
|
turbolinks
|
435
440
|
uglifier
|
436
441
|
webdrivers (= 5.3.0)
|
data/README.md
CHANGED
@@ -17,6 +17,7 @@
|
|
17
17
|
[![Linting](https://github.com/shakacode/react_on_rails/actions/workflows/lint-js-and-ruby.yml/badge.svg)](https://github.com/shakacode/react_on_rails/actions/workflows/lint-js-and-ruby.yml)
|
18
18
|
|
19
19
|
# News
|
20
|
+
* [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/) supports the latest features of React 18, including [React Server Components](https://react.dev/reference/rsc/server-components) and [streaming](https://react.dev/reference/react-dom/server/renderToPipeableStream). Contact [Justin Gordon](mailto:justin@shakacode.com) for more information.
|
20
21
|
* ShakaCode now maintains the official successor to `rails/webpacker`, [`shakapacker`](https://github.com/shakacode/shakapacker).
|
21
22
|
* Project is updated to support Rails 7 and Shakapacker v6+!
|
22
23
|
|
data/SUMMARY.md
CHANGED
@@ -17,6 +17,7 @@ Here is the new link:
|
|
17
17
|
+ [How React on Rails Works](docs/outdated/how-react-on-rails-works.md)
|
18
18
|
+ [Client vs. Server Rendering](./docs/guides/client-vs-server-rendering.md)
|
19
19
|
+ [React Server Rendering](./docs/guides/react-server-rendering.md)
|
20
|
+
+ [🚀 Next-Gen Server Rendering: Streaming with React 18's Latest APIs](./docs/guides/streaming-server-rendering.md)
|
20
21
|
+ [Render-Functions and the RailsContext](docs/guides/render-functions-and-railscontext.md)
|
21
22
|
+ [Caching and Performance: React on Rails Pro](https://github.com/shakacode/react_on_rails/wiki).
|
22
23
|
+ [Deployment](docs/guides/deployment.md).
|
@@ -39,7 +39,9 @@ module ReactOnRails
|
|
39
39
|
i18n_output_format: nil,
|
40
40
|
components_subdirectory: nil,
|
41
41
|
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
|
43
45
|
)
|
44
46
|
end
|
45
47
|
|
@@ -53,7 +55,8 @@ module ReactOnRails
|
|
53
55
|
:server_render_method, :random_dom_id, :auto_load_bundle,
|
54
56
|
:same_bundle_for_client_and_server, :rendering_props_extension,
|
55
57
|
:make_generated_server_bundle_the_entrypoint,
|
56
|
-
:defer_generated_component_packs
|
58
|
+
:defer_generated_component_packs,
|
59
|
+
:force_load
|
57
60
|
|
58
61
|
# rubocop:disable Metrics/AbcSize
|
59
62
|
def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
|
@@ -68,7 +71,7 @@ module ReactOnRails
|
|
68
71
|
same_bundle_for_client_and_server: nil,
|
69
72
|
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
|
70
73
|
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)
|
72
75
|
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
|
73
76
|
self.generated_assets_dirs = generated_assets_dirs
|
74
77
|
self.generated_assets_dir = generated_assets_dir
|
@@ -106,6 +109,7 @@ module ReactOnRails
|
|
106
109
|
self.auto_load_bundle = auto_load_bundle
|
107
110
|
self.make_generated_server_bundle_the_entrypoint = make_generated_server_bundle_the_entrypoint
|
108
111
|
self.defer_generated_component_packs = defer_generated_component_packs
|
112
|
+
self.force_load = force_load
|
109
113
|
end
|
110
114
|
# rubocop:enable Metrics/AbcSize
|
111
115
|
|
@@ -91,6 +91,64 @@ module ReactOnRails
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
# Streams a server-side rendered React component using React's `renderToPipeableStream`.
|
95
|
+
# Supports React 18 features like Suspense, concurrent rendering, and selective hydration.
|
96
|
+
# Enables progressive rendering and improved performance for large components.
|
97
|
+
#
|
98
|
+
# Note: This function can only be used with React on Rails Pro.
|
99
|
+
# The view that uses this function must be rendered using the
|
100
|
+
# `stream_view_containing_react_components` method from the React on Rails Pro gem.
|
101
|
+
#
|
102
|
+
# Example of an async React component that can benefit from streaming:
|
103
|
+
#
|
104
|
+
# const AsyncComponent = async () => {
|
105
|
+
# const data = await fetchData();
|
106
|
+
# return <div>{data}</div>;
|
107
|
+
# };
|
108
|
+
#
|
109
|
+
# function App() {
|
110
|
+
# return (
|
111
|
+
# <Suspense fallback={<div>Loading...</div>}>
|
112
|
+
# <AsyncComponent />
|
113
|
+
# </Suspense>
|
114
|
+
# );
|
115
|
+
# }
|
116
|
+
#
|
117
|
+
# @param [String] component_name Name of your registered component
|
118
|
+
# @param [Hash] options Options for rendering
|
119
|
+
# @option options [Hash] :props Props to pass to the react component
|
120
|
+
# @option options [String] :dom_id DOM ID of the component container
|
121
|
+
# @option options [Hash] :html_options Options passed to content_tag
|
122
|
+
# @option options [Boolean] :prerender Set to false to disable server-side rendering
|
123
|
+
# @option options [Boolean] :trace Set to true to add extra debugging information to the HTML
|
124
|
+
# @option options [Boolean] :raise_on_prerender_error Set to true to raise exceptions during server-side rendering
|
125
|
+
# Any other options are passed to the content tag, including the id.
|
126
|
+
def stream_react_component(component_name, options = {})
|
127
|
+
unless ReactOnRails::Utils.react_on_rails_pro?
|
128
|
+
raise ReactOnRails::Error,
|
129
|
+
"You must use React on Rails Pro to use the stream_react_component method."
|
130
|
+
end
|
131
|
+
|
132
|
+
if @rorp_rendering_fibers.nil?
|
133
|
+
raise ReactOnRails::Error,
|
134
|
+
"You must call stream_view_containing_react_components to render the view containing the react component"
|
135
|
+
end
|
136
|
+
|
137
|
+
rendering_fiber = Fiber.new do
|
138
|
+
stream = internal_stream_react_component(component_name, options)
|
139
|
+
stream.each_chunk do |chunk|
|
140
|
+
Fiber.yield chunk
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
@rorp_rendering_fibers << rendering_fiber
|
145
|
+
|
146
|
+
# return the first chunk of the fiber
|
147
|
+
# It contains the initial html of the component
|
148
|
+
# all updates will be appended to the stream sent to browser
|
149
|
+
rendering_fiber.resume
|
150
|
+
end
|
151
|
+
|
94
152
|
# react_component_hash is used to return multiple HTML strings for server rendering, such as for
|
95
153
|
# adding meta-tags to a page.
|
96
154
|
# It is exactly like react_component except for the following:
|
@@ -330,6 +388,16 @@ module ReactOnRails
|
|
330
388
|
|
331
389
|
private
|
332
390
|
|
391
|
+
def internal_stream_react_component(component_name, options = {})
|
392
|
+
options = options.merge(stream?: true)
|
393
|
+
result = internal_react_component(component_name, options)
|
394
|
+
build_react_component_result_for_server_streamed_content(
|
395
|
+
rendered_html_stream: result[:result],
|
396
|
+
component_specification_tag: result[:tag],
|
397
|
+
render_options: result[:render_options]
|
398
|
+
)
|
399
|
+
end
|
400
|
+
|
333
401
|
def generated_components_pack_path(component_name)
|
334
402
|
"#{ReactOnRails::PackerUtils.packer_source_entry_path}/generated/#{component_name}.js"
|
335
403
|
end
|
@@ -361,6 +429,32 @@ module ReactOnRails
|
|
361
429
|
prepend_render_rails_context(result)
|
362
430
|
end
|
363
431
|
|
432
|
+
def build_react_component_result_for_server_streamed_content(
|
433
|
+
rendered_html_stream:,
|
434
|
+
component_specification_tag:,
|
435
|
+
render_options:
|
436
|
+
)
|
437
|
+
is_first_chunk = true
|
438
|
+
rendered_html_stream.transform do |chunk_json_result|
|
439
|
+
if is_first_chunk
|
440
|
+
is_first_chunk = false
|
441
|
+
build_react_component_result_for_server_rendered_string(
|
442
|
+
server_rendered_html: chunk_json_result["html"],
|
443
|
+
component_specification_tag: component_specification_tag,
|
444
|
+
console_script: chunk_json_result["consoleReplayScript"],
|
445
|
+
render_options: render_options
|
446
|
+
)
|
447
|
+
else
|
448
|
+
result_console_script = render_options.replay_console ? chunk_json_result["consoleReplayScript"] : ""
|
449
|
+
# No need to prepend component_specification_tag or add rails context again
|
450
|
+
# as they're already included in the first chunk
|
451
|
+
compose_react_component_html_with_spec_and_console(
|
452
|
+
"", chunk_json_result["html"], result_console_script
|
453
|
+
)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
364
458
|
def build_react_component_result_for_server_rendered_hash(
|
365
459
|
server_rendered_html: required("server_rendered_html"),
|
366
460
|
component_specification_tag: required("component_specification_tag"),
|
@@ -397,27 +491,30 @@ module ReactOnRails
|
|
397
491
|
|
398
492
|
def compose_react_component_html_with_spec_and_console(component_specification_tag, rendered_output, console_script)
|
399
493
|
# IMPORTANT: Ensure that we mark string as html_safe to avoid escaping.
|
400
|
-
<<~HTML
|
494
|
+
html_content = <<~HTML
|
401
495
|
#{rendered_output}
|
402
496
|
#{component_specification_tag}
|
403
497
|
#{console_script}
|
404
498
|
HTML
|
499
|
+
html_content.strip.html_safe
|
405
500
|
end
|
406
501
|
|
407
|
-
|
408
|
-
|
409
|
-
return render_value if @rendered_rails_context
|
502
|
+
def rails_context_if_not_already_rendered
|
503
|
+
return "" if @rendered_rails_context
|
410
504
|
|
411
505
|
data = rails_context(server_side: false)
|
412
506
|
|
413
507
|
@rendered_rails_context = true
|
414
508
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
509
|
+
content_tag(:script,
|
510
|
+
json_safe_and_pretty(data).html_safe,
|
511
|
+
type: "application/json",
|
512
|
+
id: "js-react-on-rails-context")
|
513
|
+
end
|
419
514
|
|
420
|
-
|
515
|
+
# prepend the rails_context if not yet applied
|
516
|
+
def prepend_render_rails_context(render_value)
|
517
|
+
"#{rails_context_if_not_already_rendered}\n#{render_value}".strip.html_safe
|
421
518
|
end
|
422
519
|
|
423
520
|
def internal_react_component(react_component_name, options = {})
|
@@ -441,6 +538,14 @@ module ReactOnRails
|
|
441
538
|
"data-trace" => (render_options.trace ? true : nil),
|
442
539
|
"data-dom-id" => render_options.dom_id)
|
443
540
|
|
541
|
+
if render_options.force_load
|
542
|
+
component_specification_tag.concat(
|
543
|
+
content_tag(:script, %(
|
544
|
+
ReactOnRails.reactOnRailsComponentLoaded('#{render_options.dom_id}');
|
545
|
+
).html_safe)
|
546
|
+
)
|
547
|
+
end
|
548
|
+
|
444
549
|
load_pack_for_generated_component(react_component_name, render_options)
|
445
550
|
# Create the HTML rendering part
|
446
551
|
result = server_rendered_react_component(render_options)
|
@@ -465,6 +570,25 @@ module ReactOnRails
|
|
465
570
|
props.is_a?(String) ? props : props.to_json
|
466
571
|
end
|
467
572
|
|
573
|
+
def raise_prerender_error(json_result, react_component_name, props, js_code)
|
574
|
+
raise ReactOnRails::PrerenderError.new(
|
575
|
+
component_name: react_component_name,
|
576
|
+
props: sanitized_props_string(props),
|
577
|
+
err: nil,
|
578
|
+
js_code: js_code,
|
579
|
+
console_messages: json_result["consoleReplayScript"]
|
580
|
+
)
|
581
|
+
end
|
582
|
+
|
583
|
+
def should_raise_streaming_prerender_error?(chunk_json_result, render_options)
|
584
|
+
chunk_json_result["hasErrors"] &&
|
585
|
+
(if chunk_json_result["isShellReady"]
|
586
|
+
render_options.raise_non_shell_server_rendering_errors
|
587
|
+
else
|
588
|
+
render_options.raise_on_prerender_error
|
589
|
+
end)
|
590
|
+
end
|
591
|
+
|
468
592
|
# Returns object with values that are NOT html_safe!
|
469
593
|
def server_rendered_react_component(render_options)
|
470
594
|
return { "html" => "", "consoleReplayScript" => "" } unless render_options.prerender
|
@@ -512,16 +636,18 @@ module ReactOnRails
|
|
512
636
|
js_code: js_code)
|
513
637
|
end
|
514
638
|
|
515
|
-
if
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
639
|
+
if render_options.stream?
|
640
|
+
result.transform do |chunk_json_result|
|
641
|
+
if should_raise_streaming_prerender_error?(chunk_json_result, render_options)
|
642
|
+
raise_prerender_error(chunk_json_result, react_component_name, props, js_code)
|
643
|
+
end
|
644
|
+
# It doesn't make any transformation, it listens and raises error if a chunk has errors
|
645
|
+
chunk_json_result
|
646
|
+
end
|
647
|
+
elsif result["hasErrors"] && render_options.raise_on_prerender_error
|
648
|
+
raise_prerender_error(result, react_component_name, props, js_code)
|
524
649
|
end
|
650
|
+
|
525
651
|
result
|
526
652
|
end
|
527
653
|
|
@@ -87,10 +87,18 @@ module ReactOnRails
|
|
87
87
|
retrieve_configuration_value_for(:raise_on_prerender_error)
|
88
88
|
end
|
89
89
|
|
90
|
+
def raise_non_shell_server_rendering_errors
|
91
|
+
retrieve_react_on_rails_pro_config_value_for(:raise_non_shell_server_rendering_errors)
|
92
|
+
end
|
93
|
+
|
90
94
|
def logging_on_server
|
91
95
|
retrieve_configuration_value_for(:logging_on_server)
|
92
96
|
end
|
93
97
|
|
98
|
+
def force_load
|
99
|
+
retrieve_configuration_value_for(:force_load)
|
100
|
+
end
|
101
|
+
|
94
102
|
def to_s
|
95
103
|
"{ react_component_name = #{react_component_name}, options = #{options}, request_digest = #{request_digest}"
|
96
104
|
end
|
@@ -103,6 +111,10 @@ module ReactOnRails
|
|
103
111
|
options[key] = value
|
104
112
|
end
|
105
113
|
|
114
|
+
def stream?
|
115
|
+
options[:stream?]
|
116
|
+
end
|
117
|
+
|
106
118
|
private
|
107
119
|
|
108
120
|
attr_reader :options
|
@@ -120,6 +132,14 @@ module ReactOnRails
|
|
120
132
|
ReactOnRails.configuration.public_send(key)
|
121
133
|
end
|
122
134
|
end
|
135
|
+
|
136
|
+
def retrieve_react_on_rails_pro_config_value_for(key)
|
137
|
+
options.fetch(key) do
|
138
|
+
return nil unless ReactOnRails::Utils.react_on_rails_pro?
|
139
|
+
|
140
|
+
ReactOnRailsPro.configuration.public_send(key)
|
141
|
+
end
|
142
|
+
end
|
123
143
|
end
|
124
144
|
end
|
125
145
|
end
|
@@ -46,7 +46,7 @@ module ReactOnRails
|
|
46
46
|
# Note, js_code does not have to be based on React.
|
47
47
|
# js_code MUST RETURN json stringify Object
|
48
48
|
# Calling code will probably call 'html_safe' on return value before rendering to the view.
|
49
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
49
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
50
50
|
def exec_server_render_js(js_code, render_options, js_evaluator = nil)
|
51
51
|
js_evaluator ||= self
|
52
52
|
if render_options.trace
|
@@ -56,7 +56,11 @@ module ReactOnRails
|
|
56
56
|
@file_index += 1
|
57
57
|
end
|
58
58
|
begin
|
59
|
-
|
59
|
+
result = if render_options.stream?
|
60
|
+
js_evaluator.eval_streaming_js(js_code, render_options)
|
61
|
+
else
|
62
|
+
js_evaluator.eval_js(js_code, render_options)
|
63
|
+
end
|
60
64
|
rescue StandardError => err
|
61
65
|
msg = <<~MSG
|
62
66
|
Error evaluating server bundle. Check your webpack configuration.
|
@@ -71,26 +75,14 @@ module ReactOnRails
|
|
71
75
|
end
|
72
76
|
raise ReactOnRails::Error, msg, err.backtrace
|
73
77
|
end
|
74
|
-
result = nil
|
75
|
-
begin
|
76
|
-
result = JSON.parse(json_string)
|
77
|
-
rescue JSON::ParserError => e
|
78
|
-
raise ReactOnRails::JsonParseError.new(parse_error: e, json: json_string)
|
79
|
-
end
|
80
78
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
console_script_lines&.each do |line|
|
87
|
-
match = re.match(line)
|
88
|
-
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
89
|
-
end
|
90
|
-
end
|
91
|
-
result
|
79
|
+
return parse_result_and_replay_console_messages(result, render_options) unless render_options.stream?
|
80
|
+
|
81
|
+
# Streamed component is returned as stream of strings.
|
82
|
+
# We need to parse each chunk and replay the console messages.
|
83
|
+
result.transform { |chunk| parse_result_and_replay_console_messages(chunk, render_options) }
|
92
84
|
end
|
93
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
85
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
94
86
|
|
95
87
|
def trace_js_code_used(msg, js_code, file_name = "tmp/server-generated.js", force: false)
|
96
88
|
return unless ReactOnRails.configuration.trace || force
|
@@ -233,6 +225,28 @@ module ReactOnRails
|
|
233
225
|
msg = "file_url_to_string #{url} failed\nError is: #{e}"
|
234
226
|
raise ReactOnRails::Error, msg
|
235
227
|
end
|
228
|
+
|
229
|
+
def parse_result_and_replay_console_messages(result_string, render_options)
|
230
|
+
result = nil
|
231
|
+
begin
|
232
|
+
result = JSON.parse(result_string)
|
233
|
+
rescue JSON::ParserError => e
|
234
|
+
raise ReactOnRails::JsonParseError.new(parse_error: e, json: result_string)
|
235
|
+
end
|
236
|
+
|
237
|
+
if render_options.logging_on_server
|
238
|
+
console_script = result["consoleReplayScript"]
|
239
|
+
console_script_lines = console_script.split("\n")
|
240
|
+
# Regular expression to match console.log or console.error calls with SERVER prefix
|
241
|
+
re = /console\.(?:log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
|
242
|
+
console_script_lines&.each do |line|
|
243
|
+
match = re.match(line)
|
244
|
+
# Log matched messages to Rails logger with react_on_rails prefix
|
245
|
+
Rails.logger.info { "[react_on_rails] #{match[:msg]}" } if match
|
246
|
+
end
|
247
|
+
end
|
248
|
+
result
|
249
|
+
end
|
236
250
|
end
|
237
251
|
# rubocop:enable Metrics/ClassLength
|
238
252
|
end
|
data/tsconfig.json
CHANGED
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:
|
4
|
+
version: 15.0.0.alpha.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin Gordon
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|