react_on_rails 14.0.5 → 14.1.0.rc.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca8ba0235b9256e1b24f5afc2c874f258cf239d78ad6490e86ce4d918b26ecf4
4
- data.tar.gz: 54796b7b8067b98180bf0e41eb20c4d6bb0a4ea54594af8365eb95c74158d1b7
3
+ metadata.gz: fa19667ad2e9a246bdfa0fbe76ccd2df1c44a571c0c5adb74e66c2f0775e384a
4
+ data.tar.gz: aa0703cfe098dff2d85950936e58c9cb2affc08ac776402a78ac9bb61f294ac9
5
5
  SHA512:
6
- metadata.gz: c081c9e1b626d9c986f212c2c351fd1774fddaa9be301ae05d6c890b41c30f21871acb56002001b2bf64584da3932457ffc9da522463f3d49f7b73dd62852032
7
- data.tar.gz: 005f0dc9f274c6ba9edc8784efb679e6ba5bc7610b708c7c072f4301f4fe25d3a4bf887ad2e9449284f2bbce346dfec54f0e7bd54192ab8d3532c7d5b3004267
6
+ metadata.gz: 6758816cdedf80c7071be8c686a495e70338c39b18d613999fc46fb31d372bf21448b9f99d24f3e5d0c1f56809e1813bdeb1be4ffc8ecdd6a6d7654f8a74c62d
7
+ data.tar.gz: 3cb8d9ea6c601b29bf6baa9ebde16fdfe88ee6ad7243e3709efdb42c6ca485ba7affd9f6b0dc2836f3544af0f9a6c0639b50419f2e1312dd7f4a4927b0bc31c1
data/CHANGELOG.md CHANGED
@@ -18,6 +18,30 @@ 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
+ #### Fixed
22
+
23
+ - 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).
24
+ - Changed the ReactOnRails' version checker to use `ReactOnRails.configuration.node_modules_location` to determine the location of the package.json that the `react-on-rails` dependency is expected to be set by.
25
+ - Also, all errors that would be raised by the version checking have been converted to `Rails.Logger` warnings to avoid any breaking changes. [PR 1657](https://github.com/shakacode/react_on_rails/pull/1657) by [judahmeek](https://github.com/judahmeek).
26
+ - Enable use as a `git:` dependency. [PR 1664](https://github.com/shakacode/react_on_rails/pull/1664) by [alexeyr-ci](https://github.com/alexeyr-ci).
27
+
28
+ #### Added
29
+ - Added streaming server rendering support:
30
+ - [PR #1633](https://github.com/shakacode/react_on_rails/pull/1633) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
31
+ - New `stream_react_component` helper for adding streamed components to views
32
+ - New `streamServerRenderedReactComponent` function in the react-on-rails package that uses React 18's `renderToPipeableStream` API
33
+ - Enables progressive page loading and improved performance for server-rendered React components
34
+ - 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).
35
+ - 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).
36
+ - Added support for passing options to `YAML.safe_load` when loading locale files with `config.i18n_yml_safe_load_options`. [PR #1668](https://github.com/shakacode/react_on_rails/pull/1668) by [dzirtusss](https://github.com/dzirtusss).
37
+
38
+ #### Changed
39
+ - 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).
40
+
41
+ ### [14.0.5] - 2024-08-20
42
+ #### Fixed
43
+ - 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).
44
+
21
45
  ### [14.0.4] - 2024-07-02
22
46
 
23
47
  #### Improved
@@ -1148,7 +1172,8 @@ Best done with Object destructing:
1148
1172
  ##### Fixed
1149
1173
  - Fix several generator-related issues.
1150
1174
 
1151
- [Unreleased]: https://github.com/shakacode/react_on_rails/compare/14.0.4...master
1175
+ [Unreleased]: https://github.com/shakacode/react_on_rails/compare/14.0.5...master
1176
+ [14.0.5]: https://github.com/shakacode/react_on_rails/compare/14.0.4...14.0.5
1152
1177
  [14.0.4]: https://github.com/shakacode/react_on_rails/compare/14.0.3...14.0.4
1153
1178
  [14.0.3]: https://github.com/shakacode/react_on_rails/compare/14.0.2...14.0.3
1154
1179
  [14.0.2]: https://github.com/shakacode/react_on_rails/compare/14.0.1...14.0.2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (14.0.4)
4
+ react_on_rails (15.0.0.alpha.1)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
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).
@@ -52,6 +52,7 @@ module ReactOnRails
52
52
  :generated_assets_dirs, :generated_assets_dir, :components_subdirectory,
53
53
  :webpack_generated_files, :rendering_extension, :build_test_command,
54
54
  :build_production_command, :i18n_dir, :i18n_yml_dir, :i18n_output_format,
55
+ :i18n_yml_safe_load_options,
55
56
  :server_render_method, :random_dom_id, :auto_load_bundle,
56
57
  :same_bundle_for_client_and_server, :rendering_props_extension,
57
58
  :make_generated_server_bundle_the_entrypoint,
@@ -69,7 +70,7 @@ module ReactOnRails
69
70
  rendering_extension: nil, build_test_command: nil,
70
71
  build_production_command: nil, defer_generated_component_packs: nil,
71
72
  same_bundle_for_client_and_server: nil,
72
- i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil,
73
+ i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil, i18n_yml_safe_load_options: nil,
73
74
  random_dom_id: nil, server_render_method: nil, rendering_props_extension: nil,
74
75
  components_subdirectory: nil, auto_load_bundle: nil, force_load: nil)
75
76
  self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
@@ -80,6 +81,7 @@ module ReactOnRails
80
81
  self.i18n_dir = i18n_dir
81
82
  self.i18n_yml_dir = i18n_yml_dir
82
83
  self.i18n_output_format = i18n_output_format
84
+ self.i18n_yml_safe_load_options = i18n_yml_safe_load_options
83
85
 
84
86
  self.random_dom_id = random_dom_id
85
87
  self.prerender = prerender
@@ -5,9 +5,7 @@ require "rails/railtie"
5
5
  module ReactOnRails
6
6
  class Engine < ::Rails::Engine
7
7
  config.to_prepare do
8
- if File.exist?(VersionChecker::NodePackageVersion.package_json_path)
9
- VersionChecker.build.raise_if_gem_and_node_package_versions_differ
10
- end
8
+ VersionChecker.build.log_if_gem_and_node_package_versions_differ
11
9
  ReactOnRails::ServerRenderingPool.reset_pool
12
10
  end
13
11
  end
@@ -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.html_safe
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
- # prepend the rails_context if not yet applied
408
- def prepend_render_rails_context(render_value)
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
- rails_context_content = content_tag(:script,
416
- json_safe_and_pretty(data).html_safe,
417
- type: "application/json",
418
- id: "js-react-on-rails-context")
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
- "#{rails_context_content}\n#{render_value}".html_safe
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 = {})
@@ -473,6 +570,25 @@ ReactOnRails.reactOnRailsComponentLoaded('#{render_options.dom_id}');
473
570
  props.is_a?(String) ? props : props.to_json
474
571
  end
475
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
+
476
592
  # Returns object with values that are NOT html_safe!
477
593
  def server_rendered_react_component(render_options)
478
594
  return { "html" => "", "consoleReplayScript" => "" } unless render_options.prerender
@@ -520,16 +636,18 @@ ReactOnRails.reactOnRailsComponentLoaded('#{render_options.dom_id}');
520
636
  js_code: js_code)
521
637
  end
522
638
 
523
- if result["hasErrors"] && render_options.raise_on_prerender_error
524
- # We caught this exception on our backtrace handler
525
- raise ReactOnRails::PrerenderError.new(component_name: react_component_name,
526
- # Sanitize as this might be browser logged
527
- props: sanitized_props_string(props),
528
- err: nil,
529
- js_code: js_code,
530
- console_messages: result["consoleReplayScript"])
531
-
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)
532
649
  end
650
+
533
651
  result
534
652
  end
535
653
 
@@ -115,11 +115,17 @@ module ReactOnRails
115
115
  translations = {}
116
116
  defaults = {}
117
117
  locale_files.each do |f|
118
- translation = YAML.safe_load(File.open(f))
118
+ safe_load_options = ReactOnRails.configuration.i18n_yml_safe_load_options || {}
119
+ translation = YAML.safe_load(File.open(f), **safe_load_options)
119
120
  key = translation.keys[0]
120
121
  val = flatten(translation[key])
121
122
  translations = translations.deep_merge(key => val)
122
123
  defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
124
+ rescue Psych::Exception => e
125
+ raise ReactOnRails::Error, <<~MSG
126
+ Error parsing #{f}: #{e.message}
127
+ Consider fixing unsafe YAML or permitting with config.i18n_yml_safe_load_options
128
+ MSG
123
129
  end
124
130
  [translations.to_json, defaults.to_json]
125
131
  end
@@ -87,6 +87,10 @@ 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
@@ -107,6 +111,10 @@ module ReactOnRails
107
111
  options[key] = value
108
112
  end
109
113
 
114
+ def stream?
115
+ options[:stream?]
116
+ end
117
+
110
118
  private
111
119
 
112
120
  attr_reader :options
@@ -124,6 +132,14 @@ module ReactOnRails
124
132
  ReactOnRails.configuration.public_send(key)
125
133
  end
126
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
127
143
  end
128
144
  end
129
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, Metrics/AbcSize, Metrics/PerceivedComplexity
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
- json_string = js_evaluator.eval_js(js_code, render_options)
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
- if render_options.logging_on_server
82
- console_script = result["consoleReplayScript"]
83
- console_script_lines = console_script.split("\n")
84
- console_script_lines = console_script_lines[2..-2]
85
- re = /console\.(?:log|error)\.apply\(console, \["\[SERVER\] (?<msg>.*)"\]\);/
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, Metrics/AbcSize, Metrics/PerceivedComplexity
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "14.0.5"
4
+ VERSION = "14.1.0.rc.0"
5
5
  end
@@ -19,8 +19,9 @@ module ReactOnRails
19
19
  # For compatibility, the gem and the node package versions should always match,
20
20
  # unless the user really knows what they're doing. So we will give a
21
21
  # warning if they do not.
22
- def raise_if_gem_and_node_package_versions_differ
23
- return if node_package_version.relative_path?
22
+ def log_if_gem_and_node_package_versions_differ
23
+ return if node_package_version.raw.nil? || node_package_version.local_path_or_url?
24
+ return log_node_semver_version_warning if node_package_version.semver_wildcard?
24
25
 
25
26
  node_major_minor_patch = node_package_version.major_minor_patch
26
27
  gem_major_minor_patch = gem_major_minor_patch_version
@@ -28,9 +29,7 @@ module ReactOnRails
28
29
  node_major_minor_patch[1] == gem_major_minor_patch[1] &&
29
30
  node_major_minor_patch[2] == gem_major_minor_patch[2]
30
31
 
31
- raise_differing_versions_warning unless versions_match
32
-
33
- raise_node_semver_version_warning if node_package_version.semver_wildcard?
32
+ log_differing_versions_warning unless versions_match
34
33
  end
35
34
 
36
35
  private
@@ -46,15 +45,15 @@ module ReactOnRails
46
45
  MSG
47
46
  end
48
47
 
49
- def raise_differing_versions_warning
50
- msg = "**ERROR** ReactOnRails: ReactOnRails gem and node package versions do not match\n#{common_error_msg}"
51
- raise ReactOnRails::Error, msg
48
+ def log_differing_versions_warning
49
+ msg = "**WARNING** ReactOnRails: ReactOnRails gem and node package versions do not match\n#{common_error_msg}"
50
+ Rails.logger.warn(msg)
52
51
  end
53
52
 
54
- def raise_node_semver_version_warning
55
- msg = "**ERROR** ReactOnRails: Your node package version for react-on-rails contains a " \
53
+ def log_node_semver_version_warning
54
+ msg = "**WARNING** ReactOnRails: Your node package version for react-on-rails contains a " \
56
55
  "^ or ~\n#{common_error_msg}"
57
- raise ReactOnRails::Error, msg
56
+ Rails.logger.warn(msg)
58
57
  end
59
58
 
60
59
  def gem_version
@@ -74,7 +73,7 @@ module ReactOnRails
74
73
  end
75
74
 
76
75
  def self.package_json_path
77
- Rails.root.join("client", "package.json")
76
+ Rails.root.join(ReactOnRails.configuration.node_modules_location, "package.json")
78
77
  end
79
78
 
80
79
  def initialize(package_json)
@@ -82,29 +81,41 @@ module ReactOnRails
82
81
  end
83
82
 
84
83
  def raw
85
- parsed_package_contents = JSON.parse(package_json_contents)
86
- if parsed_package_contents.key?("dependencies") &&
87
- parsed_package_contents["dependencies"].key?("react-on-rails")
88
- parsed_package_contents["dependencies"]["react-on-rails"]
89
- else
90
- raise ReactOnRails::Error, "No 'react-on-rails' entry in package.json dependencies"
84
+ return @raw if defined?(@raw)
85
+
86
+ if File.exist?(package_json)
87
+ parsed_package_contents = JSON.parse(package_json_contents)
88
+ if parsed_package_contents.key?("dependencies") &&
89
+ parsed_package_contents["dependencies"].key?("react-on-rails")
90
+ return @raw = parsed_package_contents["dependencies"]["react-on-rails"]
91
+ end
91
92
  end
93
+ msg = "No 'react-on-rails' entry in the dependencies of #{NodePackageVersion.package_json_path}, " \
94
+ "which is the expected location according to ReactOnRails.configuration.node_modules_location"
95
+ Rails.logger.warn(msg)
96
+ @raw = nil
92
97
  end
93
98
 
94
99
  def semver_wildcard?
95
- raw.match(/[~^]/).present?
100
+ # See https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies
101
+ # We want to disallow all expressions other than exact versions
102
+ # and the ones allowed by local_path_or_url?
103
+ raw.blank? || raw.match(/[~^><|*-]/).present?
96
104
  end
97
105
 
98
- def relative_path?
99
- raw.match(%r{(\.\.|\Afile:///)}).present?
106
+ def local_path_or_url?
107
+ # See https://docs.npmjs.com/cli/v10/configuring-npm/package-json#dependencies
108
+ # All path and protocol "version ranges" include / somewhere,
109
+ # but we want to make an exception for npm:@scope/pkg@version.
110
+ !raw.nil? && raw.include?("/") && !raw.start_with?("npm:")
100
111
  end
101
112
 
102
113
  def major_minor_patch
103
- return if relative_path?
114
+ return if local_path_or_url?
104
115
 
105
116
  match = raw.match(MAJOR_MINOR_PATCH_VERSION_REGEX)
106
117
  unless match
107
- raise ReactOnRails::Error, "Cannot parse version number '#{raw}' (wildcard versions are not supported)"
118
+ raise ReactOnRails::Error, "Cannot parse version number '#{raw}' (only exact versions are supported)"
108
119
  end
109
120
 
110
121
  [match[1], match[2], match[3]]
data/tsconfig.json CHANGED
@@ -8,6 +8,7 @@
8
8
  "noImplicitAny": true,
9
9
  "outDir": "node_package/lib",
10
10
  "strict": true,
11
+ "incremental": true,
11
12
  "target": "es5"
12
13
  },
13
14
  "include": ["node_package/src/**/*"]
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: 14.0.5
4
+ version: 14.1.0.rc.0
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-08-21 00:00:00.000000000 Z
11
+ date: 2025-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable