react_on_rails_pro 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 +7 -0
- data/.controlplane/Dockerfile +49 -0
- data/.controlplane/controlplane.yml +22 -0
- data/.controlplane/gvc.yml +25 -0
- data/.controlplane/postgres.yml +33 -0
- data/.controlplane/rails.yml +49 -0
- data/.controlplane/redis.yml +18 -0
- data/.gitignore +77 -0
- data/.prettierignore +12 -0
- data/.prettierrc +19 -0
- data/.rspec +2 -0
- data/.rubocop.yml +120 -0
- data/.scss-lint.yml +205 -0
- data/CHANGELOG.md +570 -0
- data/CI_SETUP.md +502 -0
- data/CONTRIBUTING.md +376 -0
- data/Dockerfile +63 -0
- data/Gemfile +8 -0
- data/Gemfile.development_dependencies +74 -0
- data/Gemfile.loader +32 -0
- data/Gemfile.lock +527 -0
- data/LICENSE +98 -0
- data/LICENSE_SETUP.md +272 -0
- data/README.md +577 -0
- data/Rakefile +13 -0
- data/app/controllers/react_on_rails_pro/rsc_payload_controller.rb +7 -0
- data/app/helpers/react_on_rails_pro_helper.rb +360 -0
- data/app/views/react_on_rails_pro/rsc_payload.html.erb +1 -0
- data/babel.config.js +4 -0
- data/docs/bundle-caching.md +205 -0
- data/docs/caching.md +234 -0
- data/docs/code-splitting-loadable-components.md +313 -0
- data/docs/code-splitting.md +349 -0
- data/docs/configuration.md +165 -0
- data/docs/contributors-info/onboarding-customers.md +6 -0
- data/docs/contributors-info/releasing.md +40 -0
- data/docs/contributors-info/style.md +33 -0
- data/docs/home-pro.md +146 -0
- data/docs/installation.md +203 -0
- data/docs/js-memory-leaks.md +22 -0
- data/docs/node-renderer/basics.md +92 -0
- data/docs/node-renderer/debugging.md +38 -0
- data/docs/node-renderer/error-reporting-and-tracing.md +160 -0
- data/docs/node-renderer/heroku.md +102 -0
- data/docs/node-renderer/js-configuration.md +91 -0
- data/docs/node-renderer/troubleshooting.md +5 -0
- data/docs/profiling-server-side-rendering-code.md +179 -0
- data/docs/react-server-components/add-streaming-and-interactivity.md +190 -0
- data/docs/react-server-components/create-without-ssr.md +448 -0
- data/docs/react-server-components/glossary.md +102 -0
- data/docs/react-server-components/how-react-server-components-work.md +243 -0
- data/docs/react-server-components/inside-client-components.md +332 -0
- data/docs/react-server-components/purpose-and-benefits.md +243 -0
- data/docs/react-server-components/rendering-flow.md +86 -0
- data/docs/react-server-components/selective-hydration-in-streamed-components.md +75 -0
- data/docs/react-server-components/server-side-rendering.md +72 -0
- data/docs/react-server-components/tutorial.md +19 -0
- data/docs/release-notes/4.0.md +94 -0
- data/docs/release-notes/v4-react-server-components.md +66 -0
- data/docs/ruby-api.md +11 -0
- data/docs/streaming-server-rendering.md +210 -0
- data/docs/troubleshooting.md +24 -0
- data/docs/updating.md +219 -0
- data/eslint.config.mjs +220 -0
- data/lib/react_on_rails_pro/assets_precompile.rb +230 -0
- data/lib/react_on_rails_pro/cache.rb +88 -0
- data/lib/react_on_rails_pro/concerns/rsc_payload_renderer.rb +38 -0
- data/lib/react_on_rails_pro/concerns/stream.rb +103 -0
- data/lib/react_on_rails_pro/configuration.rb +228 -0
- data/lib/react_on_rails_pro/constants.rb +8 -0
- data/lib/react_on_rails_pro/engine.rb +24 -0
- data/lib/react_on_rails_pro/error.rb +14 -0
- data/lib/react_on_rails_pro/license_public_key.rb +30 -0
- data/lib/react_on_rails_pro/license_validator.rb +188 -0
- data/lib/react_on_rails_pro/prepare_node_renderer_bundles.rb +40 -0
- data/lib/react_on_rails_pro/rendering_error.rb +5 -0
- data/lib/react_on_rails_pro/request.rb +318 -0
- data/lib/react_on_rails_pro/routes.rb +13 -0
- data/lib/react_on_rails_pro/server_rendering_js_code.rb +102 -0
- data/lib/react_on_rails_pro/server_rendering_pool/node_rendering_pool.rb +133 -0
- data/lib/react_on_rails_pro/server_rendering_pool/pro_rendering.rb +117 -0
- data/lib/react_on_rails_pro/stream_cache.rb +61 -0
- data/lib/react_on_rails_pro/stream_request.rb +170 -0
- data/lib/react_on_rails_pro/utils.rb +222 -0
- data/lib/react_on_rails_pro/v8_log_processor.rb +50 -0
- data/lib/react_on_rails_pro/version.rb +6 -0
- data/lib/react_on_rails_pro.rb +23 -0
- data/package-scripts.yml +109 -0
- data/package.json +159 -0
- data/rakelib/dummy_apps.rake +22 -0
- data/rakelib/lint.rake +32 -0
- data/rakelib/public_key_management.rake +155 -0
- data/rakelib/rbs.rake +47 -0
- data/rakelib/run_rspec.rake +81 -0
- data/rakelib/task_helpers.rb +45 -0
- data/rakelib/yard.rake +20 -0
- data/react_on_rails_pro.gemspec +47 -0
- data/readme-gen-docs.md +1 -0
- data/script/bootstrap +33 -0
- data/script/preinstall.js +31 -0
- data/script/setup +23 -0
- data/script/test +38 -0
- data/sig/react_on_rails_pro/cache.rbs +13 -0
- data/sig/react_on_rails_pro/configuration.rbs +100 -0
- data/sig/react_on_rails_pro/error.rbs +4 -0
- data/sig/react_on_rails_pro/utils.rbs +7 -0
- data/sig/react_on_rails_pro.rbs +5 -0
- data/yarn.lock +7599 -0
- metadata +319 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
# React on Rails Pro License Public Key Management Tasks
|
|
8
|
+
#
|
|
9
|
+
# Usage:
|
|
10
|
+
# rake react_on_rails_pro:update_public_key # From production (shakacode.com)
|
|
11
|
+
# rake react_on_rails_pro:update_public_key[local] # From localhost:8788
|
|
12
|
+
# rake react_on_rails_pro:update_public_key[custom.com] # From custom hostname
|
|
13
|
+
# rake react_on_rails_pro:verify_public_key # Verify current configuration
|
|
14
|
+
# rake react_on_rails_pro:public_key_help # Show help
|
|
15
|
+
|
|
16
|
+
namespace :react_on_rails_pro do # rubocop:disable Metrics/BlockLength
|
|
17
|
+
desc "Update the public key for React on Rails Pro license validation"
|
|
18
|
+
task :update_public_key, [:source] do |_task, args| # rubocop:disable Metrics/BlockLength
|
|
19
|
+
source = args[:source] || "production"
|
|
20
|
+
|
|
21
|
+
# Determine the API URL based on the source
|
|
22
|
+
api_url = case source
|
|
23
|
+
when "local", "localhost"
|
|
24
|
+
# Use the default local URL created by the Cloudflare Wrangler tool when the worker is run locally
|
|
25
|
+
"http://localhost:8788/api/public-key"
|
|
26
|
+
when "production", "prod"
|
|
27
|
+
"https://www.shakacode.com/api/public-key"
|
|
28
|
+
else
|
|
29
|
+
# Check if it's a custom URL or hostname
|
|
30
|
+
if source.start_with?("http://", "https://")
|
|
31
|
+
# Full URL provided
|
|
32
|
+
source.end_with?("/api/public-key") ? source : "#{source}/api/public-key"
|
|
33
|
+
else
|
|
34
|
+
# Just a hostname provided
|
|
35
|
+
"https://#{source}/api/public-key"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "Fetching public key from: #{api_url}"
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
uri = URI(api_url)
|
|
43
|
+
response = Net::HTTP.get_response(uri)
|
|
44
|
+
|
|
45
|
+
if response.code != "200"
|
|
46
|
+
puts "❌ Failed to fetch public key. HTTP Status: #{response.code}"
|
|
47
|
+
puts "Response: #{response.body}"
|
|
48
|
+
exit 1
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
data = JSON.parse(response.body)
|
|
52
|
+
public_key = data["publicKey"]
|
|
53
|
+
|
|
54
|
+
if public_key.nil? || public_key.empty?
|
|
55
|
+
puts "❌ No public key found in response"
|
|
56
|
+
exit 1
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# TODO: Add a prepublish check to ensure this key matches the latest public key from the API.
|
|
60
|
+
# This should be implemented after publishing the API endpoint on the ShakaCode website.
|
|
61
|
+
# Update Ruby public key file
|
|
62
|
+
ruby_file_path = File.join(File.dirname(__FILE__), "..", "lib", "react_on_rails_pro", "license_public_key.rb")
|
|
63
|
+
ruby_content = <<~RUBY.strip_heredoc
|
|
64
|
+
# frozen_string_literal: true
|
|
65
|
+
|
|
66
|
+
module ReactOnRailsPro
|
|
67
|
+
module LicensePublicKey
|
|
68
|
+
# ShakaCode's public key for React on Rails Pro license verification
|
|
69
|
+
# The private key corresponding to this public key is held by ShakaCode
|
|
70
|
+
# and is never committed to the repository
|
|
71
|
+
# Last updated: #{Time.now.utc.strftime('%Y-%m-%d %H:%M:%S UTC')}
|
|
72
|
+
# Source: #{api_url}
|
|
73
|
+
#
|
|
74
|
+
# You can update this public key by running the rake task:
|
|
75
|
+
# react_on_rails_pro:update_public_key
|
|
76
|
+
# This task fetches the latest key from the API endpoint:
|
|
77
|
+
# http://shakacode.com/api/public-key
|
|
78
|
+
KEY = OpenSSL::PKey::RSA.new(<<~PEM.strip.strip_heredoc)
|
|
79
|
+
#{public_key.strip}
|
|
80
|
+
PEM
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
RUBY
|
|
84
|
+
|
|
85
|
+
File.write(ruby_file_path, ruby_content)
|
|
86
|
+
puts "✅ Updated Ruby public key: #{ruby_file_path}"
|
|
87
|
+
|
|
88
|
+
# Update Node/TypeScript public key file
|
|
89
|
+
node_file_path = File.join(File.dirname(__FILE__), "..", "packages", "node-renderer", "src", "shared",
|
|
90
|
+
"licensePublicKey.ts")
|
|
91
|
+
node_content = <<~TYPESCRIPT
|
|
92
|
+
// ShakaCode's public key for React on Rails Pro license verification
|
|
93
|
+
// The private key corresponding to this public key is held by ShakaCode
|
|
94
|
+
// and is never committed to the repository
|
|
95
|
+
// Last updated: #{Time.now.utc.strftime('%Y-%m-%d %H:%M:%S UTC')}
|
|
96
|
+
// Source: #{api_url}
|
|
97
|
+
//
|
|
98
|
+
// You can update this public key by running the rake task:
|
|
99
|
+
// react_on_rails_pro:update_public_key
|
|
100
|
+
// This task fetches the latest key from the API endpoint:
|
|
101
|
+
// http://shakacode.com/api/public-key
|
|
102
|
+
export const PUBLIC_KEY = `#{public_key.strip}`;
|
|
103
|
+
TYPESCRIPT
|
|
104
|
+
|
|
105
|
+
File.write(node_file_path, node_content)
|
|
106
|
+
puts "✅ Updated Node public key: #{node_file_path}"
|
|
107
|
+
|
|
108
|
+
puts "\n✅ Successfully updated public keys from #{api_url}"
|
|
109
|
+
puts "\nPublic key info:"
|
|
110
|
+
puts " Algorithm: #{data['algorithm'] || 'RSA-2048'}"
|
|
111
|
+
puts " Format: #{data['format'] || 'PEM'}"
|
|
112
|
+
puts " Usage: #{data['usage'] || 'React on Rails Pro license verification'}"
|
|
113
|
+
rescue SocketError, Net::OpenTimeout, Net::ReadTimeout => e
|
|
114
|
+
puts "❌ Network error: #{e.message}"
|
|
115
|
+
puts "Please check your internet connection and the API URL."
|
|
116
|
+
exit 1
|
|
117
|
+
rescue JSON::ParserError => e
|
|
118
|
+
puts "❌ Failed to parse JSON response: #{e.message}"
|
|
119
|
+
exit 1
|
|
120
|
+
rescue StandardError => e
|
|
121
|
+
puts "❌ Error: #{e.message}"
|
|
122
|
+
puts e.backtrace.first(5)
|
|
123
|
+
exit 1
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
desc "Show usage examples for updating the public key"
|
|
128
|
+
task :public_key_help do
|
|
129
|
+
puts <<~HELP
|
|
130
|
+
React on Rails Pro - Public Key Management
|
|
131
|
+
==========================================
|
|
132
|
+
|
|
133
|
+
Update public key from different sources:
|
|
134
|
+
|
|
135
|
+
1. From production (ShakaCode's official server):
|
|
136
|
+
rake react_on_rails_pro:update_public_key
|
|
137
|
+
rake react_on_rails_pro:update_public_key[production]
|
|
138
|
+
|
|
139
|
+
2. From local development server:
|
|
140
|
+
rake react_on_rails_pro:update_public_key[local]
|
|
141
|
+
|
|
142
|
+
3. From a custom hostname:
|
|
143
|
+
rake react_on_rails_pro:update_public_key[staging.example.com]
|
|
144
|
+
|
|
145
|
+
4. From a custom full URL:
|
|
146
|
+
rake react_on_rails_pro:update_public_key[https://api.example.com/api/public-key]
|
|
147
|
+
|
|
148
|
+
Verify current public key:
|
|
149
|
+
rake react_on_rails_pro:verify_public_key
|
|
150
|
+
|
|
151
|
+
Note: The public key is used to verify JWT licenses for React on Rails Pro.
|
|
152
|
+
The corresponding private key is held securely by ShakaCode.
|
|
153
|
+
HELP
|
|
154
|
+
end
|
|
155
|
+
end
|
data/rakelib/rbs.rake
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
require "timeout"
|
|
5
|
+
|
|
6
|
+
# NOTE: Pro package does not include Steep tasks (:steep, :all) as it does not
|
|
7
|
+
# use Steep type checker. Only RBS validation is performed.
|
|
8
|
+
# rubocop:disable Metrics/BlockLength
|
|
9
|
+
namespace :rbs do
|
|
10
|
+
desc "Validate RBS type signatures"
|
|
11
|
+
task :validate do
|
|
12
|
+
require "rbs"
|
|
13
|
+
require "rbs/cli"
|
|
14
|
+
|
|
15
|
+
puts "Validating RBS type signatures..."
|
|
16
|
+
|
|
17
|
+
# Use Open3 for better error handling - captures stdout, stderr, and exit status separately
|
|
18
|
+
# This allows us to distinguish between actual validation errors and warnings
|
|
19
|
+
# Note: Must use bundle exec even though rake runs in bundle context because
|
|
20
|
+
# spawned shell commands via Open3.capture3() do NOT inherit bundle context
|
|
21
|
+
# Wrap in Timeout to prevent hung processes in CI environments (60 second timeout)
|
|
22
|
+
stdout, stderr, status = Timeout.timeout(60) do
|
|
23
|
+
Open3.capture3("bundle exec rbs -I sig validate")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if status.success?
|
|
27
|
+
puts "✓ RBS validation passed"
|
|
28
|
+
else
|
|
29
|
+
puts "✗ RBS validation failed"
|
|
30
|
+
puts stdout unless stdout.empty?
|
|
31
|
+
warn stderr unless stderr.empty?
|
|
32
|
+
exit 1
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
desc "Check RBS type signatures (alias for validate)"
|
|
37
|
+
task check: :validate
|
|
38
|
+
|
|
39
|
+
desc "List all RBS files"
|
|
40
|
+
task :list do
|
|
41
|
+
sig_files = Dir.glob("sig/**/*.rbs")
|
|
42
|
+
puts "RBS type signature files:"
|
|
43
|
+
sig_files.each { |f| puts " #{f}" }
|
|
44
|
+
puts "\nTotal: #{sig_files.count} files"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
# rubocop:enable Metrics/BlockLength
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# TODO: This file is not used for CI
|
|
4
|
+
require "coveralls/rake/task" if ENV["USE_COVERALLS"] == "TRUE"
|
|
5
|
+
|
|
6
|
+
require "pathname"
|
|
7
|
+
require "active_support/core_ext/string"
|
|
8
|
+
require_relative "task_helpers"
|
|
9
|
+
namespace :run_rspec do
|
|
10
|
+
include ReactOnRailsPro::TaskHelpers
|
|
11
|
+
|
|
12
|
+
spec_dummy_dir = File.join("spec", "dummy")
|
|
13
|
+
|
|
14
|
+
desc "Run RSpec for top level only"
|
|
15
|
+
task :gem do
|
|
16
|
+
run_tests_in("", rspec_args: File.join("spec", "react_on_rails_pro"))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
desc "Runs dummy rspec"
|
|
20
|
+
task dummy: ["dummy_app:dummy_app"] do
|
|
21
|
+
clean_gen_assets(spec_dummy_dir)
|
|
22
|
+
bundle_install_in(dummy_app_dir)
|
|
23
|
+
run_tests_in(spec_dummy_dir)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc "(HACK) Run RSpec on spec/empty_spec in order to have SimpleCov generate a coverage report from cache"
|
|
27
|
+
task :empty do
|
|
28
|
+
sh %(#{ENV['USE_COVERALLS'] ? 'COVERAGE=true' : ''} rspec spec/empty_spec.rb)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Coveralls::RakeTask.new if ENV["USE_COVERALLS"] == "TRUE"
|
|
32
|
+
|
|
33
|
+
desc "run all tests"
|
|
34
|
+
task run_rspec: %i[gem dummy empty js_tests] do
|
|
35
|
+
puts "Completed all RSpec tests"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
desc "js tests (same as 'yarn run test')"
|
|
40
|
+
task :js_tests do
|
|
41
|
+
sh "yarn run test"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
msg = <<-DESC.strip_heredoc
|
|
45
|
+
Runs all tests, run `rake -D run_rspec` to see all available test options.
|
|
46
|
+
DESC
|
|
47
|
+
desc msg
|
|
48
|
+
task run_rspec: ["run_rspec:run_rspec"]
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def calc_path(dir)
|
|
53
|
+
if dir.is_a?(String)
|
|
54
|
+
if dir.start_with?(File::SEPARATOR)
|
|
55
|
+
Pathname.new(dir)
|
|
56
|
+
else
|
|
57
|
+
Pathname.new(File.join(gem_root, dir))
|
|
58
|
+
end
|
|
59
|
+
else
|
|
60
|
+
dir
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Runs rspec in the given directory.
|
|
65
|
+
# If string is passed and it's not absolute, it's converted relative to root of the gem.
|
|
66
|
+
# TEST_ENV_COMMAND_NAME is used to make SimpleCov.command_name unique in order to
|
|
67
|
+
# prevent a name collision. Defaults to the given directory's name.
|
|
68
|
+
def run_tests_in(dir, options = {})
|
|
69
|
+
path = calc_path(dir)
|
|
70
|
+
|
|
71
|
+
command_name = options.fetch(:command_name, path.basename)
|
|
72
|
+
rspec_args = options.fetch(:rspec_args, "")
|
|
73
|
+
env_vars = +"#{options.fetch(:env_vars, '')} TEST_ENV_COMMAND_NAME=\"#{command_name}\""
|
|
74
|
+
env_vars << "COVERAGE=true" if ENV["USE_COVERALLS"]
|
|
75
|
+
sh_in_dir(path.realpath, "#{env_vars} bundle exec rspec #{rspec_args}")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def clean_gen_assets(dir)
|
|
79
|
+
path = calc_path(dir)
|
|
80
|
+
sh_in_dir(path.realpath, "yarn run build:clean")
|
|
81
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ReactOnRailsPro
|
|
4
|
+
module TaskHelpers
|
|
5
|
+
# Returns the root folder of the react_on_rails gem
|
|
6
|
+
def gem_root
|
|
7
|
+
File.expand_path("..", __dir__)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def dummy_app_dir
|
|
11
|
+
File.join(gem_root, "spec/dummy")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Executes a string or an array of strings in a shell in the given directory
|
|
15
|
+
def sh_in_dir(dir, *shell_commands)
|
|
16
|
+
Dir.chdir(dir) do
|
|
17
|
+
# Without `with_unbundled_env`, running bundle in the child directories won't correctly
|
|
18
|
+
# update the Gemfile.lock
|
|
19
|
+
Bundler.with_unbundled_env do
|
|
20
|
+
shell_commands.flatten.each do |shell_command|
|
|
21
|
+
sh(shell_command.strip)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def bundle_install_in(dir, frozen: true)
|
|
28
|
+
cmd = "#{frozen ? 'BUNDLE_FROZEN=true ' : ''}bundle install"
|
|
29
|
+
sh_in_dir(dir, cmd)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Runs bundle exec using that directory's Gemfile
|
|
33
|
+
def bundle_exec(dir: nil, args: nil, env_vars: "")
|
|
34
|
+
sh_in_dir(dir, "#{env_vars} #{args}")
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def symbolize_keys(hash)
|
|
38
|
+
hash.each_with_object({}) do |(key, value), new_hash|
|
|
39
|
+
new_key = key.is_a?(String) ? key.to_sym : key
|
|
40
|
+
new_value = value.is_a?(Hash) ? symbolize_keys(value) : value
|
|
41
|
+
new_hash[new_key] = new_value
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/rakelib/yard.rake
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "yard"
|
|
4
|
+
require "commonmarker"
|
|
5
|
+
|
|
6
|
+
class GithubMarkdown
|
|
7
|
+
attr_reader :to_html
|
|
8
|
+
|
|
9
|
+
def initialize(text)
|
|
10
|
+
@to_html = CommonMarker.render_html(text)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
YARD::Rake::YardocTask.new do |t|
|
|
15
|
+
helper = YARD::Templates::Helpers::MarkupHelper
|
|
16
|
+
helper.clear_markup_cache
|
|
17
|
+
helper::MARKUP_PROVIDERS[:markdown].unshift const: "GithubMarkdown"
|
|
18
|
+
t.files = %w[lib/react_on_rails_pro/utils.rb app/helpers/react_on_rails_pro_helper.rb]
|
|
19
|
+
t.options = ["-o", "gen-documentation", "-r", "readme-gen-docs.md"]
|
|
20
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require "react_on_rails_pro/version"
|
|
6
|
+
|
|
7
|
+
# Load the core react_on_rails version for dependency
|
|
8
|
+
# This is evaluated at build time, not on user machines
|
|
9
|
+
require_relative "../lib/react_on_rails/version"
|
|
10
|
+
|
|
11
|
+
Gem::Specification.new do |s|
|
|
12
|
+
s.name = "react_on_rails_pro"
|
|
13
|
+
s.version = ReactOnRailsPro::VERSION
|
|
14
|
+
s.authors = ["Justin Gordon"]
|
|
15
|
+
s.email = ["justin@shakacode.com"]
|
|
16
|
+
|
|
17
|
+
s.summary = "Rails with react server rendering with webpack. Performance helpers"
|
|
18
|
+
s.description = "See README.md"
|
|
19
|
+
s.homepage = "https://github.com/shakacode/react_on_rails_pro"
|
|
20
|
+
s.license = "UNLICENSED"
|
|
21
|
+
s.metadata["rubygems_mfa_required"] = "true"
|
|
22
|
+
|
|
23
|
+
s.files = `git ls-files -z`.split("\x0")
|
|
24
|
+
.reject { |f|
|
|
25
|
+
f.match(
|
|
26
|
+
%r{^(test|spec|features|tmp|node_modules|packages|coverage|Gemfile.lock|lib/tasks)/}
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
s.bindir = "exe"
|
|
30
|
+
s.executables = s.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
31
|
+
s.require_paths = ["lib"]
|
|
32
|
+
|
|
33
|
+
s.required_ruby_version = ">= 3.0"
|
|
34
|
+
|
|
35
|
+
s.add_runtime_dependency "addressable"
|
|
36
|
+
s.add_runtime_dependency "connection_pool"
|
|
37
|
+
s.add_runtime_dependency "execjs", "~> 2.9"
|
|
38
|
+
s.add_runtime_dependency "httpx", "~> 1.5"
|
|
39
|
+
s.add_runtime_dependency "jwt", "~> 2.7"
|
|
40
|
+
s.add_runtime_dependency "async", ">= 2.6"
|
|
41
|
+
s.add_runtime_dependency "rainbow"
|
|
42
|
+
s.add_runtime_dependency "react_on_rails", ReactOnRails::VERSION
|
|
43
|
+
s.add_development_dependency "bundler"
|
|
44
|
+
s.add_development_dependency "commonmarker"
|
|
45
|
+
s.add_development_dependency "gem-release"
|
|
46
|
+
s.add_development_dependency "yard"
|
|
47
|
+
end
|
data/readme-gen-docs.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[See documentation wiki](https://github.com/shakacode/react_on_rails/wiki)
|
data/script/bootstrap
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# script/bootstrap: Resolve all dependencies that the application requires to
|
|
4
|
+
# run.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
cd "$(dirname "$0")/.."
|
|
9
|
+
|
|
10
|
+
if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then
|
|
11
|
+
brew update
|
|
12
|
+
|
|
13
|
+
brew bundle check 2>&1 >/dev/null || {
|
|
14
|
+
echo "==> Installing Homebrew dependencies…"
|
|
15
|
+
brew bundle
|
|
16
|
+
}
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
if [ -f ".ruby-version" ] && [ -z "$(rbenv version-name 2>/dev/null)" ]; then
|
|
20
|
+
echo "==> Installing Ruby…"
|
|
21
|
+
rbenv install --skip-existing
|
|
22
|
+
which bundle 2>&1 >/dev/null || {
|
|
23
|
+
gem install bundler
|
|
24
|
+
rbenv rehash
|
|
25
|
+
}
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
if [ -f "Gemfile" ]; then
|
|
29
|
+
echo "==> Installing gem dependencies…"
|
|
30
|
+
bundle check --path vendor/gems 2>&1 >/dev/null || {
|
|
31
|
+
BUNDLE_FROZEN=true bundle install --path vendor/gems --quiet --without production
|
|
32
|
+
}
|
|
33
|
+
fi
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const cp = require('child_process');
|
|
5
|
+
|
|
6
|
+
const inNodeModules = __dirname.split(path.sep).includes('node_modules');
|
|
7
|
+
|
|
8
|
+
if (inNodeModules) {
|
|
9
|
+
console.log('preinstall: running inside node_modules — skipping link steps.');
|
|
10
|
+
process.exit(0);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function runCommand(cmd, args) {
|
|
14
|
+
const res = cp.spawnSync(cmd, args, { stdio: 'inherit' });
|
|
15
|
+
if (res.error) throw res.error;
|
|
16
|
+
if (res.status !== 0) throw new Error(`${cmd} ${args.join(' ')} exited with status ${res.status}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Run the original optional link steps sequentially in a cross-platform way.
|
|
21
|
+
// First run the package script `link-source` via yarn, which will run any shell ops inside the script
|
|
22
|
+
// (yarn itself will handle invoking a shell for the script body), then call yalc.
|
|
23
|
+
runCommand('yarn', ['run', 'link-source']);
|
|
24
|
+
runCommand('yalc', ['add', '--link', 'react-on-rails']);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
// Don't fail the overall install if these optional commands aren't available or fail,
|
|
27
|
+
// just log the error.
|
|
28
|
+
console.error('preinstall: optional link steps failed or are unavailable — continuing.', err);
|
|
29
|
+
// Keep the exit code 0 so the install doesn't fail.
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
data/script/setup
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# script/setup: Set up application for the first time after cloning, or set it
|
|
4
|
+
# back to the initial first unused state.
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
cd "$(dirname "$0")/.."
|
|
9
|
+
|
|
10
|
+
script/bootstrap
|
|
11
|
+
|
|
12
|
+
echo "===> Setting up DB..."
|
|
13
|
+
# reset database to a fresh state.
|
|
14
|
+
bin/rake db:create db:reset
|
|
15
|
+
|
|
16
|
+
if [ -z "$RAILS_ENV" ] && [ -z "$RACK_ENV" ]; then
|
|
17
|
+
# Only things for a development environment will run inside here
|
|
18
|
+
# Do things that need to be done to the application to set up for the first
|
|
19
|
+
# time. Or things needed to be run to to reset the application back to first
|
|
20
|
+
# use experience. These things are scoped to the application's domain.
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "==> App is now ready to go!"
|
data/script/test
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
|
|
3
|
+
# script/test: Run test suite for application. Optionally pass in a path to an
|
|
4
|
+
# individual test file to run a single test.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
cd "$(dirname "$0")/.."
|
|
10
|
+
|
|
11
|
+
[ -z "$DEBUG" ] || set -x
|
|
12
|
+
|
|
13
|
+
export RACK_ROOT=$(cd "$(dirname $0)"/.. && pwd)
|
|
14
|
+
|
|
15
|
+
if [ "$RAILS_ENV" = "test" ] || [ "$RACK_ENV" = "test" ]; then
|
|
16
|
+
# if executed and the environment is already set to `test`, then we want a
|
|
17
|
+
# clean from scratch application. This almost always means a ci environment,
|
|
18
|
+
# since we set the environment to `test` directly in `script/cibuild`.
|
|
19
|
+
script/setup
|
|
20
|
+
else
|
|
21
|
+
# if the environment isn't set to `test`, set it to `test` and update the
|
|
22
|
+
# application to ensure all dependencies are met as well as any other things
|
|
23
|
+
# that need to be up to date, like db migrations. The environement not having
|
|
24
|
+
# already been set to `test` almost always means this is being called on it's
|
|
25
|
+
# own from a `development` environment.
|
|
26
|
+
export RAILS_ENV="test" RACK_ENV="test"
|
|
27
|
+
|
|
28
|
+
script/update
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
echo "===> Running tests..."
|
|
32
|
+
|
|
33
|
+
if [ -n "$1" ]; then
|
|
34
|
+
# pass arguments to test call. This is useful for calling a single test.
|
|
35
|
+
bin/rake test "$1"
|
|
36
|
+
else
|
|
37
|
+
bin/rake test
|
|
38
|
+
fi
|
|
@@ -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
|