react_on_rails_pro 16.5.0 → 16.5.1
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -4
- data/app/helpers/react_on_rails_pro_helper.rb +29 -36
- data/lib/react_on_rails_pro/request.rb +8 -1
- data/lib/react_on_rails_pro/version.rb +1 -1
- data/lib/tasks/assets.rake +16 -0
- data/lib/tasks/license.rake +21 -0
- data/lib/tasks/v8_log_processor.rake +20 -0
- data/react_on_rails_pro.gemspec +2 -2
- metadata +9 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 555e14ff0b3a9fe0dbdf0d03195d25512f535ce488f426f8258af5dde9e93fa3
|
|
4
|
+
data.tar.gz: 2aa2508ce583c9b6c3907f990d8a07ce151c122a610524f89ea8a4b5fc75218c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58c950e2ace03c47a86777a398e8260d1ab67a0d28a9838431be74e181c6345af08e8ecf99d8500a179a4c62c9e871af9aa1ceef5991f199452cc2c3cdea0b6a
|
|
7
|
+
data.tar.gz: 8df15aa0b502450842d744049f7f17aff8843b0afddccf0d97cdb926d0497fdf26cb6e834ca781ec4bd532e9ddf01bc237d14643a088eb8f854d1ea969bb840f
|
data/Gemfile.lock
CHANGED
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.5.
|
|
12
|
+
react_on_rails (16.5.1)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,16 +20,16 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: .
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.5.
|
|
23
|
+
react_on_rails_pro (16.5.1)
|
|
24
24
|
addressable
|
|
25
|
-
async (>= 2.
|
|
25
|
+
async (>= 2.29)
|
|
26
26
|
connection_pool
|
|
27
27
|
execjs (~> 2.9)
|
|
28
28
|
http-2 (>= 1.1.1)
|
|
29
29
|
httpx (~> 1.5)
|
|
30
30
|
jwt (~> 2.7)
|
|
31
31
|
rainbow
|
|
32
|
-
react_on_rails (= 16.5.
|
|
32
|
+
react_on_rails (= 16.5.1)
|
|
33
33
|
|
|
34
34
|
GEM
|
|
35
35
|
remote: https://rubygems.org/
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# 2. Keep all #{some_var} fully to the left so that all indentation is done evenly in that var
|
|
6
6
|
|
|
7
7
|
require "react_on_rails/helper"
|
|
8
|
+
require "async/promise"
|
|
8
9
|
|
|
9
10
|
# rubocop:disable Metrics/ModuleLength
|
|
10
11
|
module ReactOnRailsProHelper
|
|
@@ -428,71 +429,63 @@ module ReactOnRailsProHelper
|
|
|
428
429
|
end
|
|
429
430
|
|
|
430
431
|
def consumer_stream_async(on_complete:)
|
|
431
|
-
require "async/variable"
|
|
432
|
-
|
|
433
432
|
if @async_barrier.nil?
|
|
434
433
|
raise ReactOnRails::Error,
|
|
435
434
|
"You must call stream_view_containing_react_components to render the view containing the react component"
|
|
436
435
|
end
|
|
437
436
|
|
|
438
|
-
# Create a
|
|
439
|
-
|
|
437
|
+
# Create a promise to hold the first chunk for synchronous return.
|
|
438
|
+
# Async::Promise replaces Async::Variable (deprecated in async v2.29.0).
|
|
439
|
+
first_chunk_promise = Async::Promise.new
|
|
440
440
|
all_chunks = [] if on_complete # Only collect if callback provided
|
|
441
441
|
|
|
442
442
|
# Start an async task on the barrier to stream all chunks
|
|
443
443
|
@async_barrier.async do
|
|
444
444
|
stream = yield
|
|
445
|
-
fully_consumed = process_stream_chunks(stream,
|
|
445
|
+
fully_consumed = process_stream_chunks(stream, first_chunk_promise, all_chunks)
|
|
446
446
|
on_complete&.call(all_chunks) if fully_consumed
|
|
447
447
|
rescue StandardError => e
|
|
448
|
-
# Propagate the error to the calling fiber via the
|
|
449
|
-
#
|
|
450
|
-
#
|
|
451
|
-
#
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
448
|
+
# Propagate the error to the calling fiber via the promise.
|
|
449
|
+
# A promise can only be resolved/rejected once — check before acting.
|
|
450
|
+
# resolved? returns true for both fulfilled and rejected states ("settled").
|
|
451
|
+
# Safe without a lock: only this task can reject here, and Async uses
|
|
452
|
+
# cooperative scheduling so no fiber switch can occur between resolved?
|
|
453
|
+
# and reject/raise below.
|
|
454
|
+
# If already settled, the first chunk was returned successfully.
|
|
455
|
+
# This is a post-first-chunk error. Re-raise so barrier.wait propagates it
|
|
456
|
+
# (the response is already committed at that point, so only JS redirect is possible).
|
|
457
|
+
raise if first_chunk_promise.resolved?
|
|
458
|
+
|
|
459
|
+
# Promise not yet resolved — this is a pre-first-chunk failure (e.g., shell error).
|
|
460
|
+
# Reject the promise so .wait auto-raises in the caller,
|
|
461
|
+
# BEFORE the response is committed, enabling a proper HTTP redirect.
|
|
462
|
+
# Do NOT re-raise here: the caller owns the error now.
|
|
463
|
+
first_chunk_promise.reject(e)
|
|
464
464
|
end
|
|
465
465
|
|
|
466
466
|
# Wait for and return the first chunk (blocking).
|
|
467
|
-
# Async::
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
# If the async task stored an exception (pre-first-chunk error), raise it now.
|
|
471
|
-
# This happens BEFORE response.stream.write(template_string) in
|
|
472
|
-
# stream_view_containing_react_components, so the response is NOT yet committed
|
|
473
|
-
# and rescue_from can perform a proper HTTP redirect.
|
|
474
|
-
raise result if result.is_a?(StandardError)
|
|
475
|
-
|
|
476
|
-
result
|
|
467
|
+
# Async::Promise#wait blocks until resolved, then returns the stored value.
|
|
468
|
+
# If the promise was rejected, .wait automatically re-raises the exception.
|
|
469
|
+
first_chunk_promise.wait
|
|
477
470
|
end
|
|
478
471
|
|
|
479
472
|
# Returns true if the stream was fully consumed, false if aborted (client disconnect).
|
|
480
473
|
# When false, callers must NOT invoke on_complete to avoid caching partial data.
|
|
481
|
-
def process_stream_chunks(stream,
|
|
474
|
+
def process_stream_chunks(stream, first_chunk_promise, all_chunks)
|
|
482
475
|
is_first = true
|
|
483
476
|
|
|
484
477
|
stream.each_chunk do |chunk|
|
|
485
478
|
# Client disconnected — abort without caching partial results
|
|
486
479
|
if response.stream.closed?
|
|
487
|
-
|
|
480
|
+
first_chunk_promise.resolve(nil) if is_first
|
|
488
481
|
return false
|
|
489
482
|
end
|
|
490
483
|
|
|
491
484
|
all_chunks&.push(chunk)
|
|
492
485
|
|
|
493
486
|
if is_first
|
|
494
|
-
# Store first chunk in
|
|
495
|
-
|
|
487
|
+
# Store first chunk in promise for synchronous return
|
|
488
|
+
first_chunk_promise.resolve(chunk)
|
|
496
489
|
is_first = false
|
|
497
490
|
else
|
|
498
491
|
# Enqueue remaining chunks to main output queue
|
|
@@ -501,7 +494,7 @@ module ReactOnRailsProHelper
|
|
|
501
494
|
end
|
|
502
495
|
|
|
503
496
|
# Handle case where stream has no chunks
|
|
504
|
-
|
|
497
|
+
first_chunk_promise.resolve(nil) if is_first
|
|
505
498
|
true
|
|
506
499
|
end
|
|
507
500
|
|
|
@@ -44,7 +44,8 @@ module ReactOnRailsPro
|
|
|
44
44
|
def upload_assets
|
|
45
45
|
Rails.logger.info { "[ReactOnRailsPro] Uploading assets" }
|
|
46
46
|
|
|
47
|
-
#
|
|
47
|
+
# Early checks with descriptive messages. add_bundle_to_form(check_bundle: true) also
|
|
48
|
+
# validates existence, but these provide clearer context for the rake task user.
|
|
48
49
|
server_bundle_path = ReactOnRails::Utils.server_bundle_js_file_path
|
|
49
50
|
unless File.exist?(server_bundle_path)
|
|
50
51
|
raise ReactOnRailsPro::Error, "Server bundle not found at #{server_bundle_path}. " \
|
|
@@ -66,6 +67,12 @@ module ReactOnRailsPro
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
form = form_with_assets_and_bundle
|
|
70
|
+
# TODO: targetBundles is only kept for backward compatibility with older node renderers
|
|
71
|
+
# (protocol 2.0.0) that require it. The new node renderer derives target directories from
|
|
72
|
+
# the bundle_<hash> form keys and ignores this field. Remove at the next breaking version.
|
|
73
|
+
# Note: it's not mandatory to keep this until then — users are expected to upgrade the
|
|
74
|
+
# node renderer and react_on_rails gem to the same version together — but it's an easy
|
|
75
|
+
# backward compatibility safeguard.
|
|
69
76
|
form["targetBundles"] = target_bundles
|
|
70
77
|
|
|
71
78
|
perform_request("/upload-assets", form: form)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support"
|
|
4
|
+
|
|
5
|
+
namespace :react_on_rails_pro do
|
|
6
|
+
desc "Copy assets to local node-renderer"
|
|
7
|
+
task pre_stage_bundle_for_node_renderer: :environment do
|
|
8
|
+
ReactOnRailsPro::PrepareNodeRenderBundles.call
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
desc "Copy assets to remote node-renderer"
|
|
12
|
+
task copy_assets_to_remote_vm_renderer: :environment do
|
|
13
|
+
puts "[ReactOnRailsPro] Copying assets to remote node-renderer #{ReactOnRailsPro.configuration.renderer_url}"
|
|
14
|
+
ReactOnRailsPro::Request.upload_assets
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "react_on_rails_pro/license_task_formatter"
|
|
4
|
+
|
|
5
|
+
namespace :react_on_rails_pro do
|
|
6
|
+
desc "Verify the React on Rails Pro license and display its status"
|
|
7
|
+
task verify_license: :environment do
|
|
8
|
+
format = ENV.fetch("FORMAT", "text")
|
|
9
|
+
info = ReactOnRailsPro::LicenseValidator.license_info
|
|
10
|
+
result = ReactOnRailsPro::LicenseTaskFormatter.build_result(info)
|
|
11
|
+
|
|
12
|
+
if format.casecmp("json").zero?
|
|
13
|
+
require "json"
|
|
14
|
+
puts JSON.pretty_generate(result)
|
|
15
|
+
else
|
|
16
|
+
ReactOnRailsPro::LicenseTaskFormatter.print_text(result, info)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
raise "License verification failed: #{info[:status]}" if info[:status] != :valid
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "react_on_rails_pro/v8_log_processor"
|
|
4
|
+
|
|
5
|
+
namespace :react_on_rails_pro do
|
|
6
|
+
desc <<-DESC
|
|
7
|
+
Processes V8 log files by moving them to a specified directory, generating a combined
|
|
8
|
+
V8 profile, and optionally deleting the original log files. The resulting profile.v8log.json file
|
|
9
|
+
can be analyzed using tools like Speed Scope (https://www.speedscope.app) or Chrome Developer Tools
|
|
10
|
+
to visualize and analyze performance metrics.
|
|
11
|
+
|
|
12
|
+
@param keep_files [String] 'true' to keep the original log files, 'false' to delete them.
|
|
13
|
+
@param output_dir [String] The directory where log files are moved and the profile is saved.
|
|
14
|
+
DESC
|
|
15
|
+
task :process_v8_logs, %i[keep_files output_dir] => [:environment] do |_, args|
|
|
16
|
+
args.with_defaults(keep_files: "false", output_dir: "v8_profiles")
|
|
17
|
+
keep_files = args.keep_files == "true"
|
|
18
|
+
ReactOnRailsPro::V8LogProcessor.process_v8_logs(keep_files, args.output_dir)
|
|
19
|
+
end
|
|
20
|
+
end
|
data/react_on_rails_pro.gemspec
CHANGED
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
|
|
|
22
22
|
|
|
23
23
|
s.files = Dir.chdir(__dir__) do
|
|
24
24
|
`git ls-files -z`.split("\x0").reject do |f|
|
|
25
|
-
f.match(%r{^(test|spec|features|tmp|node_modules|packages|coverage|Gemfile.lock
|
|
25
|
+
f.match(%r{^(test|spec|features|tmp|node_modules|packages|coverage|Gemfile.lock)/})
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
s.bindir = "exe"
|
|
@@ -39,7 +39,7 @@ Gem::Specification.new do |s|
|
|
|
39
39
|
# https://github.com/HoneyryderChuck/httpx/issues/118
|
|
40
40
|
s.add_runtime_dependency "http-2", ">= 1.1.1"
|
|
41
41
|
s.add_runtime_dependency "jwt", "~> 2.7"
|
|
42
|
-
s.add_runtime_dependency "async", ">= 2.
|
|
42
|
+
s.add_runtime_dependency "async", ">= 2.29"
|
|
43
43
|
s.add_runtime_dependency "rainbow"
|
|
44
44
|
s.add_runtime_dependency "react_on_rails", ReactOnRails::VERSION
|
|
45
45
|
s.add_development_dependency "bundler"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: react_on_rails_pro
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 16.5.
|
|
4
|
+
version: 16.5.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: 2026-03-
|
|
11
|
+
date: 2026-03-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -100,14 +100,14 @@ dependencies:
|
|
|
100
100
|
requirements:
|
|
101
101
|
- - ">="
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: '2.
|
|
103
|
+
version: '2.29'
|
|
104
104
|
type: :runtime
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: '2.
|
|
110
|
+
version: '2.29'
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
112
|
name: rainbow
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -128,14 +128,14 @@ dependencies:
|
|
|
128
128
|
requirements:
|
|
129
129
|
- - '='
|
|
130
130
|
- !ruby/object:Gem::Version
|
|
131
|
-
version: 16.5.
|
|
131
|
+
version: 16.5.1
|
|
132
132
|
type: :runtime
|
|
133
133
|
prerelease: false
|
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
135
135
|
requirements:
|
|
136
136
|
- - '='
|
|
137
137
|
- !ruby/object:Gem::Version
|
|
138
|
-
version: 16.5.
|
|
138
|
+
version: 16.5.1
|
|
139
139
|
- !ruby/object:Gem::Dependency
|
|
140
140
|
name: bundler
|
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -254,6 +254,9 @@ files:
|
|
|
254
254
|
- lib/react_on_rails_pro/utils.rb
|
|
255
255
|
- lib/react_on_rails_pro/v8_log_processor.rb
|
|
256
256
|
- lib/react_on_rails_pro/version.rb
|
|
257
|
+
- lib/tasks/assets.rake
|
|
258
|
+
- lib/tasks/license.rake
|
|
259
|
+
- lib/tasks/v8_log_processor.rake
|
|
257
260
|
- package-scripts.yml
|
|
258
261
|
- package.json
|
|
259
262
|
- rakelib/dummy_apps.rake
|