react_on_rails 16.2.0.beta.3 → 16.2.0.beta.8
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/CHANGELOG.md +42 -5
- data/CLAUDE.md +59 -0
- data/CONTRIBUTING.md +49 -1
- data/Gemfile.development_dependencies +1 -1
- data/Gemfile.lock +25 -10
- data/SWITCHING_CI_CONFIGS.md +55 -6
- data/Steepfile +51 -0
- data/bin/ci-rerun-failures +68 -22
- data/bin/ci-run-failed-specs +26 -2
- data/bin/ci-switch-config +262 -34
- data/bin/lefthook/check-trailing-newlines +2 -12
- data/bin/lefthook/eslint-lint +0 -10
- data/bin/lefthook/prettier-format +0 -10
- data/bin/lefthook/ruby-autofix +3 -6
- data/knip.ts +35 -9
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +32 -52
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +5 -1
- data/lib/react_on_rails/configuration.rb +56 -12
- data/lib/react_on_rails/controller.rb +3 -3
- data/lib/react_on_rails/dev/server_manager.rb +11 -4
- data/lib/react_on_rails/doctor.rb +249 -2
- data/lib/react_on_rails/helper.rb +12 -3
- data/lib/react_on_rails/pro_helper.rb +2 -44
- data/lib/react_on_rails/react_component/render_options.rb +7 -7
- data/lib/react_on_rails/utils.rb +40 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/react_on_rails_pro/CHANGELOG.md +142 -29
- data/react_on_rails_pro/CONTRIBUTING.md +2 -13
- data/react_on_rails_pro/Gemfile.development_dependencies +1 -0
- data/react_on_rails_pro/Gemfile.lock +24 -3
- data/react_on_rails_pro/README.md +559 -38
- data/react_on_rails_pro/docs/code-splitting-loadable-components.md +1 -1
- data/react_on_rails_pro/docs/contributors-info/releasing.md +2 -2
- data/react_on_rails_pro/docs/installation.md +129 -109
- data/react_on_rails_pro/docs/node-renderer/basics.md +29 -22
- data/react_on_rails_pro/docs/node-renderer/error-reporting-and-tracing.md +8 -8
- data/react_on_rails_pro/docs/node-renderer/js-configuration.md +25 -23
- data/react_on_rails_pro/docs/node-renderer/troubleshooting.md +2 -0
- data/react_on_rails_pro/docs/updating.md +209 -15
- data/react_on_rails_pro/lib/react_on_rails_pro/concerns/stream.rb +58 -4
- data/react_on_rails_pro/lib/react_on_rails_pro/configuration.rb +17 -3
- data/react_on_rails_pro/lib/react_on_rails_pro/license_public_key.rb +9 -9
- data/react_on_rails_pro/lib/react_on_rails_pro/request.rb +41 -25
- data/react_on_rails_pro/lib/react_on_rails_pro/stream_request.rb +27 -7
- data/react_on_rails_pro/lib/react_on_rails_pro/utils.rb +3 -3
- data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
- data/react_on_rails_pro/package-scripts.yml +1 -1
- data/react_on_rails_pro/package.json +5 -8
- data/react_on_rails_pro/packages/node-renderer/src/integrations/api.ts +1 -1
- data/react_on_rails_pro/packages/node-renderer/src/master/restartWorkers.ts +39 -17
- data/react_on_rails_pro/packages/node-renderer/src/master.ts +15 -4
- data/react_on_rails_pro/packages/node-renderer/src/shared/configBuilder.ts +44 -5
- data/react_on_rails_pro/packages/node-renderer/src/shared/utils.ts +4 -2
- data/react_on_rails_pro/packages/node-renderer/src/worker/handleGracefulShutdown.ts +49 -0
- data/react_on_rails_pro/packages/node-renderer/src/worker/vm.ts +3 -3
- data/react_on_rails_pro/packages/node-renderer/src/worker.ts +5 -2
- data/react_on_rails_pro/packages/node-renderer/tests/helper.ts +8 -8
- data/react_on_rails_pro/packages/node-renderer/tests/testingNodeRendererConfigs.js +1 -1
- data/react_on_rails_pro/packages/node-renderer/tests/worker.test.ts +19 -19
- data/react_on_rails_pro/rakelib/public_key_management.rake +6 -5
- data/react_on_rails_pro/rakelib/rbs.rake +47 -0
- data/react_on_rails_pro/react_on_rails_pro.gemspec +1 -0
- data/react_on_rails_pro/sig/react_on_rails_pro/cache.rbs +13 -0
- data/react_on_rails_pro/sig/react_on_rails_pro/configuration.rbs +100 -0
- data/react_on_rails_pro/sig/react_on_rails_pro/error.rbs +4 -0
- data/react_on_rails_pro/sig/react_on_rails_pro/utils.rbs +7 -0
- data/react_on_rails_pro/sig/react_on_rails_pro.rbs +5 -0
- data/react_on_rails_pro/spec/dummy/Gemfile.lock +23 -3
- data/react_on_rails_pro/spec/dummy/app/controllers/pages_controller.rb +3 -3
- data/react_on_rails_pro/spec/dummy/bin/dev +4 -8
- data/react_on_rails_pro/spec/dummy/client/node-renderer.js +4 -4
- data/react_on_rails_pro/spec/dummy/config/environments/production.rb +1 -1
- data/react_on_rails_pro/spec/dummy/config/initializers/react_on_rails.rb +28 -12
- data/react_on_rails_pro/spec/dummy/config.ru +1 -1
- data/react_on_rails_pro/spec/dummy/package.json +2 -2
- data/react_on_rails_pro/spec/dummy/spec/helpers/react_on_rails_pro_helper_spec.rb +40 -11
- data/react_on_rails_pro/spec/dummy/spec/rails_helper.rb +1 -1
- data/react_on_rails_pro/spec/dummy/spec/requests/renderer_console_logging_spec.rb +5 -5
- data/react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb +15 -10
- data/react_on_rails_pro/spec/dummy/spec/system/renderer_integration_spec.rb +3 -3
- data/react_on_rails_pro/spec/dummy/yarn.lock +4 -4
- data/react_on_rails_pro/spec/execjs-compatible-dummy/config/environments/production.rb +1 -1
- data/react_on_rails_pro/spec/execjs-compatible-dummy/config/initializers/react_on_rails.rb +16 -43
- data/react_on_rails_pro/spec/react_on_rails_pro/assets_precompile_spec.rb +15 -18
- data/react_on_rails_pro/spec/react_on_rails_pro/cache_spec.rb +1 -1
- data/react_on_rails_pro/spec/react_on_rails_pro/configuration_spec.rb +5 -3
- data/react_on_rails_pro/spec/react_on_rails_pro/license_validator_spec.rb +27 -12
- data/react_on_rails_pro/spec/react_on_rails_pro/request_spec.rb +0 -27
- data/react_on_rails_pro/spec/react_on_rails_pro/spec_helper.rb +1 -1
- data/react_on_rails_pro/spec/react_on_rails_pro/stream_decorator_spec.rb +89 -0
- data/react_on_rails_pro/spec/react_on_rails_pro/stream_spec.rb +144 -0
- data/react_on_rails_pro/spec/react_on_rails_pro/support/caching.rb +1 -1
- data/react_on_rails_pro/spec/react_on_rails_pro/support/mock_block_helper.rb +4 -2
- data/sig/react_on_rails/controller.rbs +1 -1
- data/sig/react_on_rails/error.rbs +4 -0
- data/sig/react_on_rails/helper.rbs +2 -2
- data/sig/react_on_rails/json_parse_error.rbs +10 -0
- data/sig/react_on_rails/prerender_error.rbs +21 -0
- data/sig/react_on_rails/smart_error.rbs +28 -0
- data/sig/react_on_rails.rbs +3 -24
- metadata +14 -4
- data/lib/react_on_rails/pro_utils.rb +0 -37
- data/react_on_rails_pro/spec/dummy/client/app/ror-auto-load-components/TestingStreamableComponent.jsx +0 -15
|
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
|
|
|
37
37
|
s.add_runtime_dependency "execjs", "~> 2.9"
|
|
38
38
|
s.add_runtime_dependency "httpx", "~> 1.5"
|
|
39
39
|
s.add_runtime_dependency "jwt", "~> 2.7"
|
|
40
|
+
s.add_runtime_dependency "async", ">= 2.6"
|
|
40
41
|
s.add_runtime_dependency "rainbow"
|
|
41
42
|
s.add_runtime_dependency "react_on_rails", ReactOnRails::VERSION
|
|
42
43
|
s.add_development_dependency "bundler"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module ReactOnRailsPro
|
|
2
|
+
class Cache
|
|
3
|
+
def self.fetch_react_component: (String component_name, Hash[Symbol, untyped] options) { () -> untyped } -> untyped
|
|
4
|
+
|
|
5
|
+
def self.use_cache?: (Hash[Symbol, untyped] options) -> bool
|
|
6
|
+
|
|
7
|
+
def self.base_cache_key: (String type, ?prerender: bool?) -> Array[String]
|
|
8
|
+
|
|
9
|
+
def self.dependencies_cache_key: () -> String?
|
|
10
|
+
|
|
11
|
+
def self.react_component_cache_key: (String component_name, Hash[Symbol, untyped] options) -> Array[untyped]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
module ReactOnRailsPro
|
|
2
|
+
class Configuration
|
|
3
|
+
DEFAULT_RENDERER_URL: String
|
|
4
|
+
DEFAULT_RENDERER_METHOD: String
|
|
5
|
+
DEFAULT_RENDERER_FALLBACK_EXEC_JS: bool
|
|
6
|
+
DEFAULT_RENDERER_HTTP_POOL_SIZE: Integer
|
|
7
|
+
DEFAULT_RENDERER_HTTP_POOL_TIMEOUT: Integer
|
|
8
|
+
DEFAULT_RENDERER_HTTP_POOL_WARN_TIMEOUT: Float
|
|
9
|
+
DEFAULT_SSR_TIMEOUT: Integer
|
|
10
|
+
DEFAULT_PRERENDER_CACHING: bool
|
|
11
|
+
DEFAULT_TRACING: bool
|
|
12
|
+
DEFAULT_DEPENDENCY_GLOBS: Array[String]
|
|
13
|
+
DEFAULT_EXCLUDED_DEPENDENCY_GLOBS: Array[String]
|
|
14
|
+
DEFAULT_REMOTE_BUNDLE_CACHE_ADAPTER: nil
|
|
15
|
+
DEFAULT_RENDERER_REQUEST_RETRY_LIMIT: Integer
|
|
16
|
+
DEFAULT_THROW_JS_ERRORS: bool
|
|
17
|
+
DEFAULT_RENDERING_RETURNS_PROMISES: bool
|
|
18
|
+
DEFAULT_PROFILE_SERVER_RENDERING_JS_CODE: bool
|
|
19
|
+
DEFAULT_RAISE_NON_SHELL_SERVER_RENDERING_ERRORS: bool
|
|
20
|
+
DEFAULT_ENABLE_RSC_SUPPORT: bool
|
|
21
|
+
DEFAULT_RSC_PAYLOAD_GENERATION_URL_PATH: String
|
|
22
|
+
DEFAULT_RSC_BUNDLE_JS_FILE: String
|
|
23
|
+
DEFAULT_REACT_CLIENT_MANIFEST_FILE: String
|
|
24
|
+
DEFAULT_REACT_SERVER_CLIENT_MANIFEST_FILE: String
|
|
25
|
+
|
|
26
|
+
attr_accessor renderer_url: String?
|
|
27
|
+
attr_accessor renderer_password: String?
|
|
28
|
+
attr_accessor tracing: bool?
|
|
29
|
+
attr_accessor server_renderer: String?
|
|
30
|
+
attr_accessor renderer_use_fallback_exec_js: bool?
|
|
31
|
+
attr_accessor prerender_caching: bool?
|
|
32
|
+
attr_accessor renderer_http_pool_size: Integer?
|
|
33
|
+
attr_accessor renderer_http_pool_timeout: Integer?
|
|
34
|
+
attr_accessor renderer_http_pool_warn_timeout: Float?
|
|
35
|
+
attr_accessor dependency_globs: Array[String]?
|
|
36
|
+
attr_accessor excluded_dependency_globs: Array[String]?
|
|
37
|
+
attr_accessor rendering_returns_promises: bool?
|
|
38
|
+
attr_accessor remote_bundle_cache_adapter: Module?
|
|
39
|
+
attr_accessor ssr_pre_hook_js: String?
|
|
40
|
+
attr_accessor assets_to_copy: Array[String]?
|
|
41
|
+
attr_accessor renderer_request_retry_limit: Integer?
|
|
42
|
+
attr_accessor throw_js_errors: bool?
|
|
43
|
+
attr_accessor ssr_timeout: Integer?
|
|
44
|
+
attr_accessor profile_server_rendering_js_code: bool?
|
|
45
|
+
attr_accessor raise_non_shell_server_rendering_errors: bool?
|
|
46
|
+
attr_accessor enable_rsc_support: bool?
|
|
47
|
+
attr_accessor rsc_payload_generation_url_path: String?
|
|
48
|
+
attr_accessor rsc_bundle_js_file: String?
|
|
49
|
+
attr_accessor react_client_manifest_file: String?
|
|
50
|
+
attr_accessor react_server_client_manifest_file: String?
|
|
51
|
+
|
|
52
|
+
def initialize: (
|
|
53
|
+
?renderer_url: String?,
|
|
54
|
+
?renderer_password: String?,
|
|
55
|
+
?server_renderer: String?,
|
|
56
|
+
?renderer_use_fallback_exec_js: bool?,
|
|
57
|
+
?prerender_caching: bool?,
|
|
58
|
+
?renderer_http_pool_size: Integer?,
|
|
59
|
+
?renderer_http_pool_timeout: Integer?,
|
|
60
|
+
?renderer_http_pool_warn_timeout: Float?,
|
|
61
|
+
?tracing: bool?,
|
|
62
|
+
?dependency_globs: Array[String]?,
|
|
63
|
+
?excluded_dependency_globs: Array[String]?,
|
|
64
|
+
?rendering_returns_promises: bool?,
|
|
65
|
+
?remote_bundle_cache_adapter: Module?,
|
|
66
|
+
?ssr_pre_hook_js: String?,
|
|
67
|
+
?assets_to_copy: Array[String]?,
|
|
68
|
+
?renderer_request_retry_limit: Integer?,
|
|
69
|
+
?throw_js_errors: bool?,
|
|
70
|
+
?ssr_timeout: Integer?,
|
|
71
|
+
?profile_server_rendering_js_code: bool?,
|
|
72
|
+
?raise_non_shell_server_rendering_errors: bool?,
|
|
73
|
+
?enable_rsc_support: bool?,
|
|
74
|
+
?rsc_payload_generation_url_path: String?,
|
|
75
|
+
?rsc_bundle_js_file: String?,
|
|
76
|
+
?react_client_manifest_file: String?,
|
|
77
|
+
?react_server_client_manifest_file: String?
|
|
78
|
+
) -> void
|
|
79
|
+
|
|
80
|
+
def setup_config_values: () -> void
|
|
81
|
+
|
|
82
|
+
def check_react_on_rails_support_for_rsc: () -> void
|
|
83
|
+
|
|
84
|
+
def setup_execjs_profiler_if_needed: () -> void
|
|
85
|
+
|
|
86
|
+
def node_renderer?: () -> bool
|
|
87
|
+
|
|
88
|
+
private
|
|
89
|
+
|
|
90
|
+
def setup_assets_to_copy: () -> void
|
|
91
|
+
|
|
92
|
+
def configure_default_url_if_not_provided: () -> void
|
|
93
|
+
|
|
94
|
+
def validate_url: () -> void
|
|
95
|
+
|
|
96
|
+
def validate_remote_bundle_cache_adapter: () -> void
|
|
97
|
+
|
|
98
|
+
def setup_renderer_password: () -> void
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ../../..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.2.0.beta.
|
|
12
|
+
react_on_rails (16.2.0.beta.8)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,14 +20,15 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: ../..
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.2.0.beta.
|
|
23
|
+
react_on_rails_pro (16.2.0.beta.8)
|
|
24
24
|
addressable
|
|
25
|
+
async (>= 2.6)
|
|
25
26
|
connection_pool
|
|
26
27
|
execjs (~> 2.9)
|
|
27
28
|
httpx (~> 1.5)
|
|
28
29
|
jwt (~> 2.7)
|
|
29
30
|
rainbow
|
|
30
|
-
react_on_rails (= 16.2.0.beta.
|
|
31
|
+
react_on_rails (= 16.2.0.beta.8)
|
|
31
32
|
|
|
32
33
|
GEM
|
|
33
34
|
remote: https://rubygems.org/
|
|
@@ -107,6 +108,12 @@ GEM
|
|
|
107
108
|
public_suffix (>= 2.0.2, < 7.0)
|
|
108
109
|
amazing_print (1.6.0)
|
|
109
110
|
ast (2.4.2)
|
|
111
|
+
async (2.34.0)
|
|
112
|
+
console (~> 1.29)
|
|
113
|
+
fiber-annotation
|
|
114
|
+
io-event (~> 1.11)
|
|
115
|
+
metrics (~> 0.12)
|
|
116
|
+
traces (~> 0.18)
|
|
110
117
|
base64 (0.2.0)
|
|
111
118
|
benchmark (0.4.0)
|
|
112
119
|
bigdecimal (3.1.9)
|
|
@@ -131,6 +138,10 @@ GEM
|
|
|
131
138
|
coderay (1.1.3)
|
|
132
139
|
concurrent-ruby (1.3.5)
|
|
133
140
|
connection_pool (2.5.0)
|
|
141
|
+
console (1.34.2)
|
|
142
|
+
fiber-annotation
|
|
143
|
+
fiber-local (~> 1.1)
|
|
144
|
+
json
|
|
134
145
|
coveralls (0.8.23)
|
|
135
146
|
json (>= 1.8, < 3)
|
|
136
147
|
simplecov (~> 0.16.1)
|
|
@@ -165,6 +176,9 @@ GEM
|
|
|
165
176
|
ffi (1.17.0-x86_64-darwin)
|
|
166
177
|
ffi (1.17.0-x86_64-linux-gnu)
|
|
167
178
|
ffi (1.17.0-x86_64-linux-musl)
|
|
179
|
+
fiber-annotation (0.2.0)
|
|
180
|
+
fiber-local (1.1.0)
|
|
181
|
+
fiber-storage
|
|
168
182
|
fiber-storage (1.0.0)
|
|
169
183
|
generator_spec (0.10.0)
|
|
170
184
|
activesupport (>= 3.0.0)
|
|
@@ -184,6 +198,7 @@ GEM
|
|
|
184
198
|
i18n (1.14.7)
|
|
185
199
|
concurrent-ruby (~> 1.0)
|
|
186
200
|
io-console (0.8.0)
|
|
201
|
+
io-event (1.14.2)
|
|
187
202
|
irb (1.15.1)
|
|
188
203
|
pp (>= 0.6.0)
|
|
189
204
|
rdoc (>= 4.0.0)
|
|
@@ -216,6 +231,7 @@ GEM
|
|
|
216
231
|
marcel (1.0.4)
|
|
217
232
|
matrix (0.4.2)
|
|
218
233
|
method_source (1.1.0)
|
|
234
|
+
metrics (0.15.0)
|
|
219
235
|
mini_mime (1.1.5)
|
|
220
236
|
mini_portile2 (2.8.8)
|
|
221
237
|
minitest (5.25.4)
|
|
@@ -327,6 +343,8 @@ GEM
|
|
|
327
343
|
rb-fsevent (0.11.2)
|
|
328
344
|
rb-inotify (0.11.1)
|
|
329
345
|
ffi (~> 1.0)
|
|
346
|
+
rbs (3.9.5)
|
|
347
|
+
logger
|
|
330
348
|
rdoc (6.12.0)
|
|
331
349
|
psych (>= 4.0.0)
|
|
332
350
|
redis (5.4.0)
|
|
@@ -445,6 +463,7 @@ GEM
|
|
|
445
463
|
tins (1.33.0)
|
|
446
464
|
bigdecimal
|
|
447
465
|
sync
|
|
466
|
+
traces (0.18.2)
|
|
448
467
|
turbolinks (5.2.1)
|
|
449
468
|
turbolinks-source (~> 5.2)
|
|
450
469
|
turbolinks-source (5.2.0)
|
|
@@ -524,6 +543,7 @@ DEPENDENCIES
|
|
|
524
543
|
pry-theme
|
|
525
544
|
puma (~> 6)
|
|
526
545
|
rails (~> 7.1)
|
|
546
|
+
rbs
|
|
527
547
|
react_on_rails!
|
|
528
548
|
react_on_rails_pro!
|
|
529
549
|
redis
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class PagesController < ApplicationController
|
|
3
|
+
class PagesController < ApplicationController # rubocop:disable Metrics/ClassLength
|
|
4
4
|
include ReactOnRailsPro::RSCPayloadRenderer
|
|
5
5
|
include RscPostsPageOverRedisHelper
|
|
6
6
|
|
|
@@ -85,8 +85,8 @@ class PagesController < ApplicationController
|
|
|
85
85
|
ensure
|
|
86
86
|
begin
|
|
87
87
|
redis&.close
|
|
88
|
-
rescue StandardError =>
|
|
89
|
-
Rails.logger.warn "Failed to close Redis: #{
|
|
88
|
+
rescue StandardError => e
|
|
89
|
+
Rails.logger.warn "Failed to close Redis: #{e.message}"
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
echo "Installing foreman..."
|
|
6
|
-
gem install foreman
|
|
7
|
-
fi
|
|
8
|
-
|
|
9
|
-
foreman start -f Procfile.dev
|
|
4
|
+
# This script calls the base dev script with a fixed route for the dummy app
|
|
5
|
+
exec File.join(__dir__, "../../../../lib/generators/react_on_rails/templates/base/base/bin/dev"), "--route=/", *ARGV
|
|
@@ -5,14 +5,14 @@ const Sentry = require('@sentry/node');
|
|
|
5
5
|
const { env } = process;
|
|
6
6
|
|
|
7
7
|
// Use this for package installation test:
|
|
8
|
-
const { reactOnRailsProNodeRenderer } = require('
|
|
8
|
+
const { reactOnRailsProNodeRenderer } = require('react-on-rails-pro-node-renderer');
|
|
9
9
|
|
|
10
10
|
Honeybadger.configure({
|
|
11
11
|
// This is a test account for React on Rails Pro. Substitute your own.
|
|
12
12
|
apiKey: 'a602365c',
|
|
13
13
|
environment: process.env.NODE_ENV ?? 'development',
|
|
14
14
|
});
|
|
15
|
-
require('
|
|
15
|
+
require('react-on-rails-pro-node-renderer/integrations/honeybadger').init();
|
|
16
16
|
|
|
17
17
|
// This is a test account for React on Rails Pro.
|
|
18
18
|
// Substitute your own DSN.
|
|
@@ -25,11 +25,11 @@ Sentry.init({
|
|
|
25
25
|
// Sentry recommends adjusting this value in production, or using tracesSampler for finer control
|
|
26
26
|
tracesSampleRate: 1.0,
|
|
27
27
|
});
|
|
28
|
-
require('
|
|
28
|
+
require('react-on-rails-pro-node-renderer/integrations/sentry').init({ tracing: true });
|
|
29
29
|
|
|
30
30
|
const config = {
|
|
31
31
|
// This is the default but avoids searching for the Rails root
|
|
32
|
-
|
|
32
|
+
serverBundleCachePath: path.resolve(__dirname, '../.node-renderer-bundles'),
|
|
33
33
|
port: env.RENDERER_PORT || 3800, // Listen at RENDERER_PORT env value or default port 3800
|
|
34
34
|
logLevel: env.RENDERER_LOG_LEVEL || 'info',
|
|
35
35
|
|
|
@@ -69,7 +69,7 @@ Rails.application.configure do
|
|
|
69
69
|
config.active_support.deprecation = :notify
|
|
70
70
|
|
|
71
71
|
# Use default logging formatter so that PID and timestamp are not suppressed.
|
|
72
|
-
config.log_formatter =
|
|
72
|
+
config.log_formatter = Logger::Formatter.new
|
|
73
73
|
|
|
74
74
|
# Use a different logger for distributed setups.
|
|
75
75
|
# require 'syslog/logger'
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# ⚠️ TEST CONFIGURATION - Do not copy directly for production apps
|
|
4
|
+
# This is the Pro dummy app configuration used for testing React on Rails Pro features.
|
|
5
|
+
# See docs/api-reference/configuration.md for production configuration guidance.
|
|
6
|
+
|
|
7
|
+
# Advanced: Custom rendering extension to add values to railsContext
|
|
4
8
|
module RenderingExtension
|
|
5
|
-
# Return a Hash that contains custom values from the view context that will get passed to
|
|
6
|
-
# all calls to react_component and redux_store for rendering
|
|
7
9
|
def self.custom_context(view_context)
|
|
8
10
|
if view_context.controller.is_a?(ActionMailer::Base)
|
|
9
11
|
{}
|
|
@@ -15,6 +17,7 @@ module RenderingExtension
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
20
|
+
# Advanced: Custom props extension for client-side hydration
|
|
18
21
|
module RenderingPropsExtension
|
|
19
22
|
def self.adjust_props_for_client_side_hydration(_component_name, props)
|
|
20
23
|
if props.instance_of?(Hash)
|
|
@@ -26,19 +29,32 @@ module RenderingPropsExtension
|
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
ReactOnRails.configure do |config|
|
|
32
|
+
################################################################################
|
|
33
|
+
# Essential Configuration
|
|
34
|
+
################################################################################
|
|
29
35
|
config.server_bundle_js_file = "server-bundle.js"
|
|
36
|
+
config.components_subdirectory = "ror-auto-load-components"
|
|
37
|
+
config.auto_load_bundle = true
|
|
38
|
+
|
|
39
|
+
################################################################################
|
|
40
|
+
# Pro Feature Testing: Server Bundle Security
|
|
41
|
+
################################################################################
|
|
42
|
+
# Testing private server bundle enforcement (recommended for production)
|
|
43
|
+
config.enforce_private_server_bundles = true
|
|
44
|
+
config.server_bundle_output_path = "ssr-generated"
|
|
45
|
+
|
|
46
|
+
################################################################################
|
|
47
|
+
# Test-specific Advanced Configuration
|
|
48
|
+
################################################################################
|
|
49
|
+
# Testing with fixed DOM IDs for easier test assertions
|
|
30
50
|
config.random_dom_id = false # default is true
|
|
31
51
|
|
|
32
|
-
#
|
|
33
|
-
# config.build_test_command = "yarn run build:test"
|
|
34
|
-
# config.webpack_generated_files = %w[server-bundle.js manifest.json]
|
|
52
|
+
# Testing advanced rendering customization
|
|
35
53
|
config.rendering_extension = RenderingExtension
|
|
36
|
-
|
|
37
54
|
config.rendering_props_extension = RenderingPropsExtension
|
|
38
55
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
config.
|
|
43
|
-
config.server_bundle_output_path = "ssr-generated"
|
|
56
|
+
# NOTE: build_test_command and webpack_generated_files are commented out
|
|
57
|
+
# because we've set test.compile to true in shakapacker.yml
|
|
58
|
+
# config.build_test_command = "yarn run build:test"
|
|
59
|
+
# config.webpack_generated_files = %w[server-bundle.js manifest.json]
|
|
44
60
|
end
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"@loadable/server": "^5.16.2",
|
|
18
18
|
"@loadable/webpack-plugin": "^5.15.2",
|
|
19
19
|
"@sentry/node": "^7.120.0",
|
|
20
|
-
"
|
|
20
|
+
"react-on-rails-pro-node-renderer": "link:.yalc/react-on-rails-pro-node-renderer",
|
|
21
21
|
"@shakacode/use-ssr-computation.macro": "^1.2.4",
|
|
22
22
|
"@shakacode/use-ssr-computation.runtime": "^2.0.0",
|
|
23
23
|
"@webpack-cli/serve": "^1.6.0",
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"test": "yarn run build:test && yarn run lint && rspec",
|
|
99
99
|
"lint": "cd ../.. && nps lint",
|
|
100
100
|
"e2e-test": "playwright test",
|
|
101
|
-
"preinstall": "yarn run link-source && yalc add --link react-on-rails-pro && cd .yalc/react-on-rails-pro && yalc add --link react-on-rails && cd ../.. && yalc add --link
|
|
101
|
+
"preinstall": "yarn run link-source && yalc add --link react-on-rails-pro && cd .yalc/react-on-rails-pro && yalc add --link react-on-rails && cd ../.. && yalc add --link react-on-rails-pro-node-renderer",
|
|
102
102
|
"link-source": "cd ../../.. && yarn && yarn run yalc:publish && cd react_on_rails_pro && yarn && yalc publish",
|
|
103
103
|
"postinstall": "test -f post-yarn-install.local && ./post-yarn-install.local || true",
|
|
104
104
|
"build:test": "rm -rf public/webpack/test && rm -rf ssr-generated && RAILS_ENV=test NODE_ENV=test bin/shakapacker",
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "async"
|
|
4
|
+
require "async/queue"
|
|
3
5
|
require "rails_helper"
|
|
4
6
|
require "support/script_tag_utils"
|
|
5
7
|
|
|
@@ -327,10 +329,10 @@ describe ReactOnRailsProHelper do
|
|
|
327
329
|
HTML
|
|
328
330
|
end
|
|
329
331
|
|
|
332
|
+
# mock_chunks can be an Async::Queue or an Array
|
|
330
333
|
def mock_request_and_response(mock_chunks = chunks, count: 1)
|
|
331
334
|
# Reset connection instance variables to ensure clean state for tests
|
|
332
335
|
ReactOnRailsPro::Request.instance_variable_set(:@connection, nil)
|
|
333
|
-
ReactOnRailsPro::Request.instance_variable_set(:@connection_without_retries, nil)
|
|
334
336
|
original_httpx_plugin = HTTPX.method(:plugin)
|
|
335
337
|
allow(HTTPX).to receive(:plugin) do |*args|
|
|
336
338
|
original_httpx_plugin.call(:mock_stream).plugin(*args)
|
|
@@ -340,9 +342,19 @@ describe ReactOnRailsProHelper do
|
|
|
340
342
|
chunks_read.clear
|
|
341
343
|
mock_streaming_response(%r{http://localhost:3800/bundles/[a-f0-9]{32}-test/render/[a-f0-9]{32}}, 200,
|
|
342
344
|
count: count) do |yielder|
|
|
343
|
-
mock_chunks.
|
|
344
|
-
|
|
345
|
-
|
|
345
|
+
if mock_chunks.is_a?(Async::Queue)
|
|
346
|
+
loop do
|
|
347
|
+
chunk = mock_chunks.dequeue
|
|
348
|
+
break if chunk.nil?
|
|
349
|
+
|
|
350
|
+
chunks_read << chunk
|
|
351
|
+
yielder.call("#{chunk.to_json}\n")
|
|
352
|
+
end
|
|
353
|
+
else
|
|
354
|
+
mock_chunks.each do |chunk|
|
|
355
|
+
chunks_read << chunk
|
|
356
|
+
yielder.call("#{chunk.to_json}\n")
|
|
357
|
+
end
|
|
346
358
|
end
|
|
347
359
|
end
|
|
348
360
|
end
|
|
@@ -429,18 +441,35 @@ describe ReactOnRailsProHelper do
|
|
|
429
441
|
|
|
430
442
|
allow(mocked_stream).to receive(:write) do |chunk|
|
|
431
443
|
written_chunks << chunk
|
|
432
|
-
# Ensures that any chunk received is written immediately to the stream
|
|
433
|
-
expect(written_chunks.count).to eq(chunks_read.count) # rubocop:disable RSpec/ExpectInHook
|
|
434
444
|
end
|
|
435
445
|
allow(mocked_stream).to receive(:close)
|
|
436
446
|
mocked_response = instance_double(ActionDispatch::Response)
|
|
437
447
|
allow(mocked_response).to receive(:stream).and_return(mocked_stream)
|
|
438
448
|
allow(self).to receive(:response).and_return(mocked_response)
|
|
439
|
-
|
|
449
|
+
end
|
|
450
|
+
|
|
451
|
+
def execute_stream_view_containing_react_components
|
|
452
|
+
queue = Async::Queue.new
|
|
453
|
+
mock_request_and_response(queue)
|
|
454
|
+
|
|
455
|
+
Sync do |parent|
|
|
456
|
+
parent.async { stream_view_containing_react_components(template: template_path) }
|
|
457
|
+
|
|
458
|
+
chunks_to_write = chunks.dup
|
|
459
|
+
while (chunk = chunks_to_write.shift)
|
|
460
|
+
queue.enqueue(chunk)
|
|
461
|
+
sleep 0.05
|
|
462
|
+
|
|
463
|
+
# Ensures that any chunk received is written immediately to the stream
|
|
464
|
+
expect(written_chunks.count).to eq(chunks_read.count)
|
|
465
|
+
end
|
|
466
|
+
queue.close
|
|
467
|
+
sleep 0.05
|
|
468
|
+
end
|
|
440
469
|
end
|
|
441
470
|
|
|
442
471
|
it "writes the chunk to stream as soon as it is received" do
|
|
443
|
-
|
|
472
|
+
execute_stream_view_containing_react_components
|
|
444
473
|
expect(self).to have_received(:render_to_string).once.with(template: template_path)
|
|
445
474
|
expect(chunks_read.count).to eq(chunks.count)
|
|
446
475
|
expect(written_chunks.count).to eq(chunks.count)
|
|
@@ -449,7 +478,7 @@ describe ReactOnRailsProHelper do
|
|
|
449
478
|
end
|
|
450
479
|
|
|
451
480
|
it "prepends the rails context to the first chunk only" do
|
|
452
|
-
|
|
481
|
+
execute_stream_view_containing_react_components
|
|
453
482
|
initial_result = written_chunks.first
|
|
454
483
|
expect(initial_result).to script_tag_be_included(rails_context_tag)
|
|
455
484
|
|
|
@@ -465,7 +494,7 @@ describe ReactOnRailsProHelper do
|
|
|
465
494
|
end
|
|
466
495
|
|
|
467
496
|
it "prepends the component specification tag to the first chunk only" do
|
|
468
|
-
|
|
497
|
+
execute_stream_view_containing_react_components
|
|
469
498
|
initial_result = written_chunks.first
|
|
470
499
|
expect(initial_result).to script_tag_be_included(react_component_specification_tag)
|
|
471
500
|
|
|
@@ -476,7 +505,7 @@ describe ReactOnRailsProHelper do
|
|
|
476
505
|
end
|
|
477
506
|
|
|
478
507
|
it "renders the rails view content in the first chunk" do
|
|
479
|
-
|
|
508
|
+
execute_stream_view_containing_react_components
|
|
480
509
|
initial_result = written_chunks.first
|
|
481
510
|
expect(initial_result).to include("<h1>Header Rendered In View</h1>")
|
|
482
511
|
written_chunks[1..].each do |chunk|
|
|
@@ -53,7 +53,7 @@ RSpec.configure do |config|
|
|
|
53
53
|
|
|
54
54
|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
|
55
55
|
# For React on Rails Pro, using loadable-stats.json
|
|
56
|
-
config.fixture_paths = ["#{
|
|
56
|
+
config.fixture_paths = ["#{Rails.root}/spec/fixtures"]
|
|
57
57
|
|
|
58
58
|
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
|
59
59
|
# examples within a transaction, remove the following line or assign false
|
|
@@ -15,11 +15,11 @@ describe "Console logging from server" do
|
|
|
15
15
|
html_nodes = Nokogiri::HTML(response.body)
|
|
16
16
|
expected = <<~JS
|
|
17
17
|
console.log.apply(console, ["[SERVER] RENDERED ReduxSharedStoreApp to dom node with id: ReduxSharedStoreApp-react-component-0"]);
|
|
18
|
-
console.log.apply(console, ["[SERVER] This is a script
|
|
19
|
-
console.log.apply(console, ["[SERVER] Script2
|
|
20
|
-
console.log.apply(console, ["[SERVER] Script3
|
|
21
|
-
console.log.apply(console, ["[SERVER] Script4
|
|
22
|
-
console.log.apply(console, ["[SERVER] Script5
|
|
18
|
+
console.log.apply(console, ["[SERVER] This is a script:\\"</div>\\"(/script> <script>alert('WTF1')(/script>"]);
|
|
19
|
+
console.log.apply(console, ["[SERVER] Script2:\\"</div>\\"(/script xx> <script>alert('WTF2')(/script xx>"]);
|
|
20
|
+
console.log.apply(console, ["[SERVER] Script3:\\"</div>\\"(/script xx> <script>alert('WTF3')(/script xx>"]);
|
|
21
|
+
console.log.apply(console, ["[SERVER] Script4\\"</div>\\"(/script <script>alert('WTF4')(/script>"]);
|
|
22
|
+
console.log.apply(console, ["[SERVER] Script5:\\"</div>\\"(/script> <script>alert('WTF5')(/script>"]);
|
|
23
23
|
console.log.apply(console, ["[SERVER] railsContext.serverSide is ","true"]);
|
|
24
24
|
JS
|
|
25
25
|
|
|
@@ -110,7 +110,7 @@ describe "Turbolinks across pages", :js do
|
|
|
110
110
|
it "changes name in message according to input" do
|
|
111
111
|
visit "/client_side_hello_world"
|
|
112
112
|
change_text_expect_dom_selector("#HelloWorld-react-component-0")
|
|
113
|
-
|
|
113
|
+
click_on "Hello World Component Server Rendered, with extra options"
|
|
114
114
|
change_text_expect_dom_selector("#my-hello-world-id")
|
|
115
115
|
end
|
|
116
116
|
end
|
|
@@ -174,19 +174,19 @@ describe "React Router", :js do
|
|
|
174
174
|
|
|
175
175
|
before do
|
|
176
176
|
visit "/"
|
|
177
|
-
|
|
177
|
+
click_on "React Router"
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
context "when rendering /react_router" do
|
|
181
181
|
it { is_expected.to have_text("Woohoo, we can use react-router here!") }
|
|
182
182
|
|
|
183
183
|
it "clicking links correctly renders other pages" do
|
|
184
|
-
|
|
184
|
+
click_on "Router First Page"
|
|
185
185
|
expect(page).to have_current_path("/react_router/first_page")
|
|
186
186
|
first_page_header_text = page.find(:css, "h2#first-page").text
|
|
187
187
|
expect(first_page_header_text).to eq("React Router First Page")
|
|
188
188
|
|
|
189
|
-
|
|
189
|
+
click_on "Router Second Page"
|
|
190
190
|
expect(page).to have_current_path("/react_router/second_page")
|
|
191
191
|
second_page_header_text = page.find(:css, "h2#second-page").text
|
|
192
192
|
expect(second_page_header_text).to eq("React Router Second Page")
|
|
@@ -244,7 +244,7 @@ describe "Manual client hydration", :js do
|
|
|
244
244
|
|
|
245
245
|
it "HelloWorldRehydratable onChange should trigger" do
|
|
246
246
|
within("form") do
|
|
247
|
-
|
|
247
|
+
click_on "refresh"
|
|
248
248
|
end
|
|
249
249
|
within("#HelloWorldRehydratable-react-component-1") do
|
|
250
250
|
find("input").set "Should update"
|
|
@@ -396,14 +396,14 @@ shared_examples "streamed component tests" do |path, selector|
|
|
|
396
396
|
|
|
397
397
|
it "hydrates the component" do
|
|
398
398
|
visit path
|
|
399
|
-
expect(page.html).to
|
|
399
|
+
expect(page.html).to match(/client-bundle[^"]*.js/)
|
|
400
400
|
change_text_expect_dom_selector(selector)
|
|
401
401
|
end
|
|
402
402
|
|
|
403
403
|
it "renders the page completely on server and displays content on client even without JavaScript" do
|
|
404
404
|
# Don't add client-bundle.js to the page to ensure that the app is not hydrated
|
|
405
405
|
visit "#{path}?skip_js_packs=true"
|
|
406
|
-
expect(page.html).not_to
|
|
406
|
+
expect(page.html).not_to match(/client-bundle[^"]*.js/)
|
|
407
407
|
# Ensure that the component state is not updated
|
|
408
408
|
change_text_expect_dom_selector(selector, expect_no_change: true)
|
|
409
409
|
|
|
@@ -422,13 +422,18 @@ shared_examples "streamed component tests" do |path, selector|
|
|
|
422
422
|
end
|
|
423
423
|
end
|
|
424
424
|
|
|
425
|
-
describe "Pages/stream_async_components_for_testing", :js
|
|
426
|
-
skip: "Flaky test replaced by Playwright E2E tests in e2e-tests/streaming.spec.ts" do
|
|
425
|
+
describe "Pages/stream_async_components_for_testing", :js do
|
|
427
426
|
it_behaves_like "streamed component tests", "/stream_async_components_for_testing",
|
|
428
427
|
"#AsyncComponentsTreeForTesting-react-component-0"
|
|
429
428
|
end
|
|
430
429
|
|
|
431
|
-
describe "React Router Sixth Page", :js
|
|
430
|
+
describe "React Router Sixth Page", :js do
|
|
432
431
|
it_behaves_like "streamed component tests", "/server_router/streaming-server-component",
|
|
433
432
|
"#ServerComponentRouter-react-component-0"
|
|
433
|
+
|
|
434
|
+
# Skip the test that fails without JavaScript - being addressed in another PR
|
|
435
|
+
it "renders the page completely on server and displays content on client even without JavaScript", # rubocop:disable RSpec/NoExpectationExample
|
|
436
|
+
skip: "Being addressed in another PR" do
|
|
437
|
+
# This test is overridden to skip it
|
|
438
|
+
end
|
|
434
439
|
end
|
|
@@ -9,14 +9,14 @@ describe "Shared Redux store example", :server_rendering do
|
|
|
9
9
|
|
|
10
10
|
context "with enabled JS", :js do
|
|
11
11
|
it "Has correct heading and text inside the text input" do
|
|
12
|
-
expect(page).to
|
|
13
|
-
expect(page).to
|
|
12
|
+
expect(page).to have_css("h3", text: /\ARedux Hello, Mr. Server Side Rendering!\z/)
|
|
13
|
+
expect(page).to have_css("input[type='text'][value='Mr. Server Side Rendering']")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it "updates header in reaction to text input changes" do
|
|
17
17
|
new_value = "new value"
|
|
18
18
|
all("input[type='text']")[0].set(new_value)
|
|
19
|
-
expect(page).to
|
|
19
|
+
expect(page).to have_css("h3", text: /\ARedux Hello, #{new_value}!\z/)
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|