react_on_rails 14.2.1 โ 16.1.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/AI_AGENT_INSTRUCTIONS.md +63 -0
- data/CHANGELOG.md +564 -85
- data/CLAUDE.md +135 -0
- data/CODING_AGENTS.md +313 -0
- data/CONTRIBUTING.md +448 -37
- data/Gemfile.development_dependencies +6 -1
- data/Gemfile.lock +13 -4
- data/KUDOS.md +22 -1
- data/LICENSE.md +30 -4
- data/LICENSES/README.md +14 -0
- data/NEWS.md +48 -48
- data/PROJECTS.md +45 -40
- data/REACT-ON-RAILS-PRO-LICENSE.md +129 -0
- data/README.md +113 -42
- data/SUMMARY.md +62 -52
- data/TODO.md +135 -0
- data/bin/lefthook/check-trailing-newlines +38 -0
- data/bin/lefthook/get-changed-files +26 -0
- data/bin/lefthook/prettier-format +26 -0
- data/bin/lefthook/ruby-autofix +26 -0
- data/bin/lefthook/ruby-lint +27 -0
- data/eslint.config.ts +232 -0
- data/knip.ts +40 -6
- data/lib/generators/USAGE +4 -5
- data/lib/generators/react_on_rails/USAGE +65 -0
- data/lib/generators/react_on_rails/base_generator.rb +276 -62
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -0
- data/lib/generators/react_on_rails/generator_helper.rb +35 -1
- data/lib/generators/react_on_rails/generator_messages.rb +138 -17
- data/lib/generators/react_on_rails/install_generator.rb +474 -26
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +19 -6
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +110 -18
- data/lib/generators/react_on_rails/templates/.eslintrc +1 -1
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +5 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-prod-assets +8 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static-assets +2 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +2 -2
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorldServer.js +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js +1 -8
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx +21 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.tsx +25 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.server.jsx +5 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.server.tsx +5 -0
- data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/views/layouts/hello_world.html.erb +4 -2
- data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +5 -2
- data/lib/generators/react_on_rails/templates/base/base/bin/dev +34 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +14 -5
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +76 -7
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +6 -10
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +3 -2
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb +0 -2
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/actions/helloWorldActionCreators.ts +18 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -6
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.tsx +24 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/constants/helloWorldConstants.ts +6 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/containers/HelloWorldContainer.ts +20 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/reducers/helloWorldReducer.js +1 -1
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/reducers/helloWorldReducer.ts +22 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.client.tsx +23 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.jsx +5 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.tsx +5 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/store/helloWorldStore.ts +18 -0
- data/lib/react_on_rails/configuration.rb +141 -57
- data/lib/react_on_rails/controller.rb +6 -2
- data/lib/react_on_rails/dev/file_manager.rb +78 -0
- data/lib/react_on_rails/dev/pack_generator.rb +27 -0
- data/lib/react_on_rails/dev/process_manager.rb +61 -0
- data/lib/react_on_rails/dev/server_manager.rb +487 -0
- data/lib/react_on_rails/dev.rb +20 -0
- data/lib/react_on_rails/doctor.rb +1149 -0
- data/lib/react_on_rails/engine.rb +6 -0
- data/lib/react_on_rails/git_utils.rb +12 -2
- data/lib/react_on_rails/helper.rb +176 -74
- data/lib/react_on_rails/json_parse_error.rb +6 -1
- data/lib/react_on_rails/packer_utils.rb +61 -71
- data/lib/react_on_rails/packs_generator.rb +221 -19
- data/lib/react_on_rails/prerender_error.rb +4 -0
- data/lib/react_on_rails/pro/NOTICE +21 -0
- data/lib/react_on_rails/pro/helper.rb +122 -0
- data/lib/react_on_rails/pro/utils.rb +53 -0
- data/lib/react_on_rails/react_component/render_options.rb +38 -6
- data/lib/react_on_rails/server_rendering_js_code.rb +0 -1
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +12 -5
- data/lib/react_on_rails/system_checker.rb +659 -0
- data/lib/react_on_rails/test_helper/webpack_assets_compiler.rb +1 -1
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +6 -4
- data/lib/react_on_rails/test_helper.rb +2 -3
- data/lib/react_on_rails/utils.rb +139 -43
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +14 -20
- data/lib/react_on_rails/version_syntax_converter.rb +1 -1
- data/lib/react_on_rails.rb +1 -0
- data/lib/tasks/assets.rake +1 -1
- data/lib/tasks/doctor.rake +48 -0
- data/lib/tasks/generate_packs.rake +158 -1
- data/react_on_rails.gemspec +1 -0
- data/tsconfig.eslint.json +6 -0
- data/tsconfig.json +5 -3
- metadata +63 -14
- data/REACT-ON-RAILS-PRO-LICENSE +0 -95
- data/lib/generators/react_on_rails/adapt_for_older_shakapacker_generator.rb +0 -41
- data/lib/generators/react_on_rails/bin/dev +0 -30
- data/lib/generators/react_on_rails/bin/dev-static +0 -30
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static.tt +0 -9
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt +0 -8
- /data/lib/generators/react_on_rails/templates/base/base/config/webpack/{webpackConfig.js.tt โ generateWebpackConfigs.js.tt} +0 -0
- /data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/{HelloWorldApp.jsx โ HelloWorldApp.client.jsx} +0 -0
@@ -1,127 +1,121 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "shakapacker"
|
4
|
+
|
3
5
|
module ReactOnRails
|
4
6
|
module PackerUtils
|
5
|
-
def self.
|
6
|
-
|
7
|
+
def self.dev_server_running?
|
8
|
+
Shakapacker.dev_server.running?
|
7
9
|
end
|
8
10
|
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
12
|
-
@using_shakapacker_const = ReactOnRails::Utils.gem_available?("shakapacker") &&
|
13
|
-
shakapacker_version_requirement_met?([7, 0, 0])
|
11
|
+
def self.dev_server_url
|
12
|
+
"#{Shakapacker.dev_server.protocol}://#{Shakapacker.dev_server.host_with_port}"
|
14
13
|
end
|
15
14
|
|
16
|
-
def self.
|
17
|
-
return @
|
15
|
+
def self.shakapacker_version
|
16
|
+
return @shakapacker_version if defined?(@shakapacker_version)
|
18
17
|
|
19
|
-
@
|
20
|
-
shakapacker_version_as_array[0] <= 6) ||
|
21
|
-
ReactOnRails::Utils.gem_available?("webpacker")
|
18
|
+
@shakapacker_version = Gem.loaded_specs["shakapacker"].version.to_s
|
22
19
|
end
|
23
20
|
|
24
|
-
def self.
|
25
|
-
return
|
26
|
-
return "webpacker" if using_webpacker_const?
|
27
|
-
|
28
|
-
nil
|
29
|
-
end
|
21
|
+
def self.shakapacker_version_as_array
|
22
|
+
return @shakapacker_version_as_array if defined?(@shakapacker_version_as_array)
|
30
23
|
|
31
|
-
|
32
|
-
return nil unless using_packer?
|
24
|
+
match = shakapacker_version.match(ReactOnRails::VersionChecker::VERSION_PARTS_REGEX)
|
33
25
|
|
34
|
-
|
35
|
-
|
36
|
-
return ::Shakapacker
|
37
|
-
end
|
38
|
-
require "webpacker"
|
39
|
-
::Webpacker
|
26
|
+
# match[4] is the pre-release version, not normally a number but something like "beta.1" or `nil`
|
27
|
+
@shakapacker_version_as_array = [match[1].to_i, match[2].to_i, match[3].to_i, match[4]].compact
|
40
28
|
end
|
41
29
|
|
42
|
-
def self.
|
43
|
-
|
44
|
-
|
45
|
-
packer.dev_server.running?
|
30
|
+
def self.shakapacker_version_requirement_met?(required_version)
|
31
|
+
@version_checks ||= {}
|
32
|
+
@version_checks[required_version] ||= Gem::Version.new(shakapacker_version) >= Gem::Version.new(required_version)
|
46
33
|
end
|
47
34
|
|
48
|
-
def self.
|
49
|
-
|
50
|
-
return nil unless ReactOnRails::Utils.gem_available?("shakapacker")
|
51
|
-
|
52
|
-
@shakapacker_version = Gem.loaded_specs["shakapacker"].version.to_s
|
35
|
+
def self.supports_async_loading?
|
36
|
+
shakapacker_version_requirement_met?("8.2.0")
|
53
37
|
end
|
54
38
|
|
55
|
-
def self.
|
56
|
-
|
57
|
-
|
58
|
-
@shakapacker_version_as_array = [match[1].to_i, match[2].to_i, match[3].to_i]
|
39
|
+
def self.supports_basic_pack_generation?
|
40
|
+
shakapacker_version_requirement_met?(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION)
|
59
41
|
end
|
60
42
|
|
61
|
-
def self.
|
62
|
-
|
63
|
-
|
64
|
-
Gem::Version.new(shakapacker_version) >= Gem::Version.new(req_ver)
|
43
|
+
def self.supports_autobundling?
|
44
|
+
min_version = ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_BUNDLING
|
45
|
+
::Shakapacker.config.respond_to?(:nested_entries?) && shakapacker_version_requirement_met?(min_version)
|
65
46
|
end
|
66
47
|
|
67
48
|
# This returns either a URL for the webpack-dev-server, non-server bundle or
|
68
49
|
# the hashed server bundle if using the same bundle for the client.
|
69
50
|
# Otherwise returns a file path.
|
70
51
|
def self.bundle_js_uri_from_packer(bundle_name)
|
71
|
-
hashed_bundle_name =
|
52
|
+
hashed_bundle_name = ::Shakapacker.manifest.lookup!(bundle_name)
|
72
53
|
|
73
54
|
# Support for hashing the server-bundle and having that built
|
74
55
|
# the webpack-dev-server is provided by the config value
|
75
56
|
# "same_bundle_for_client_and_server" where a value of true
|
76
57
|
# would mean that the bundle is created by the webpack-dev-server
|
77
|
-
|
58
|
+
is_bundle_running_on_server = (bundle_name == ReactOnRails.configuration.server_bundle_js_file) ||
|
59
|
+
(bundle_name == ReactOnRails.configuration.rsc_bundle_js_file)
|
78
60
|
|
79
|
-
if
|
61
|
+
if ::Shakapacker.dev_server.running? && (!is_bundle_running_on_server ||
|
80
62
|
ReactOnRails.configuration.same_bundle_for_client_and_server)
|
81
|
-
"#{
|
63
|
+
"#{dev_server_url}#{hashed_bundle_name}"
|
82
64
|
else
|
83
65
|
File.expand_path(File.join("public", hashed_bundle_name)).to_s
|
84
66
|
end
|
85
67
|
end
|
86
68
|
|
87
|
-
def self.
|
88
|
-
|
89
|
-
|
69
|
+
def self.public_output_uri_path
|
70
|
+
"#{::Shakapacker.config.public_output_path.relative_path_from(::Shakapacker.config.public_path)}/"
|
71
|
+
end
|
90
72
|
|
91
|
-
|
73
|
+
# The function doesn't ensure that the asset exists.
|
74
|
+
# - It just returns url to the asset if dev server is running
|
75
|
+
# - Otherwise it returns file path to the asset
|
76
|
+
def self.asset_uri_from_packer(asset_name)
|
77
|
+
if dev_server_running?
|
78
|
+
"#{dev_server_url}/#{public_output_uri_path}#{asset_name}"
|
79
|
+
else
|
80
|
+
File.join(packer_public_output_path, asset_name).to_s
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.precompile?
|
85
|
+
::Shakapacker.config.shakapacker_precompile?
|
92
86
|
end
|
93
87
|
|
94
88
|
def self.packer_source_path
|
95
|
-
|
89
|
+
::Shakapacker.config.source_path
|
96
90
|
end
|
97
91
|
|
98
92
|
def self.packer_source_entry_path
|
99
|
-
|
93
|
+
::Shakapacker.config.source_entry_path
|
100
94
|
end
|
101
95
|
|
102
96
|
def self.nested_entries?
|
103
|
-
|
97
|
+
::Shakapacker.config.nested_entries?
|
104
98
|
end
|
105
99
|
|
106
100
|
def self.packer_public_output_path
|
107
|
-
|
101
|
+
::Shakapacker.config.public_output_path.to_s
|
108
102
|
end
|
109
103
|
|
110
104
|
def self.manifest_exists?
|
111
|
-
|
105
|
+
::Shakapacker.config.public_manifest_path.exist?
|
112
106
|
end
|
113
107
|
|
114
108
|
def self.packer_source_path_explicit?
|
115
|
-
|
109
|
+
::Shakapacker.config.send(:data)[:source_path].present?
|
116
110
|
end
|
117
111
|
|
118
112
|
def self.check_manifest_not_cached
|
119
|
-
return unless
|
113
|
+
return unless ::Shakapacker.config.cache_manifest?
|
120
114
|
|
121
115
|
msg = <<-MSG.strip_heredoc
|
122
116
|
ERROR: you have enabled cache_manifest in the #{Rails.env} env when using the
|
123
117
|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets helper
|
124
|
-
To fix this: edit your config
|
118
|
+
To fix this: edit your config/shakapacker.yml file and set cache_manifest to false for test.
|
125
119
|
MSG
|
126
120
|
puts wrap_message(msg)
|
127
121
|
exit!
|
@@ -142,7 +136,7 @@ module ReactOnRails
|
|
142
136
|
def self.raise_nested_entries_disabled
|
143
137
|
msg = <<~MSG
|
144
138
|
**ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shakapacker. Please update \
|
145
|
-
config
|
139
|
+
config/shakapacker.yml to enable nested entries. for more information read
|
146
140
|
https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md#enable-nested_entries-for-shakapacker
|
147
141
|
MSG
|
148
142
|
|
@@ -151,26 +145,22 @@ module ReactOnRails
|
|
151
145
|
|
152
146
|
def self.raise_shakapacker_version_incompatible_for_autobundling
|
153
147
|
msg = <<~MSG
|
154
|
-
**ERROR** ReactOnRails: Please upgrade Shakapacker to version #{
|
155
|
-
above to use the automated bundle generation feature
|
156
|
-
#{
|
148
|
+
**ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_BUNDLING} or \
|
149
|
+
above to use the automated bundle generation feature (which requires nested_entries support). \
|
150
|
+
The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}. \
|
151
|
+
Basic pack generation requires ::Shakapacker #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or above.
|
157
152
|
MSG
|
158
153
|
|
159
154
|
raise ReactOnRails::Error, msg
|
160
155
|
end
|
161
156
|
|
162
|
-
def self.
|
157
|
+
def self.raise_shakapacker_version_incompatible_for_basic_pack_generation
|
163
158
|
msg = <<~MSG
|
164
|
-
**ERROR** ReactOnRails:
|
165
|
-
|
166
|
-
automated bundle generation feature.
|
159
|
+
**ERROR** ReactOnRails: Please upgrade ::Shakapacker to version #{ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION} or \
|
160
|
+
above to use basic pack generation features. The currently installed version is #{ReactOnRails::PackerUtils.shakapacker_version}.
|
167
161
|
MSG
|
168
162
|
|
169
163
|
raise ReactOnRails::Error, msg
|
170
164
|
end
|
171
|
-
|
172
|
-
def self.semver_to_string(ary)
|
173
|
-
"#{ary[0]}.#{ary[1]}.#{ary[2]}"
|
174
|
-
end
|
175
165
|
end
|
176
166
|
end
|
@@ -1,12 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "fileutils"
|
4
|
+
require "set"
|
4
5
|
|
5
6
|
module ReactOnRails
|
6
7
|
# rubocop:disable Metrics/ClassLength
|
7
8
|
class PacksGenerator
|
8
9
|
CONTAINS_CLIENT_OR_SERVER_REGEX = /\.(server|client)($|\.)/
|
9
|
-
|
10
|
+
COMPONENT_EXTENSIONS = /\.(jsx?|tsx?)$/
|
11
|
+
MINIMUM_SHAKAPACKER_VERSION = "6.5.1"
|
12
|
+
# Auto-registration requires nested_entries support which was added in 7.0.0
|
13
|
+
MINIMUM_SHAKAPACKER_VERSION_FOR_AUTO_BUNDLING = "7.0.0"
|
10
14
|
|
11
15
|
def self.instance
|
12
16
|
@instance ||= PacksGenerator.new
|
@@ -16,13 +20,20 @@ module ReactOnRails
|
|
16
20
|
return unless ReactOnRails.configuration.auto_load_bundle
|
17
21
|
|
18
22
|
add_generated_pack_to_server_bundle
|
23
|
+
|
24
|
+
# Clean any non-generated files from directories
|
25
|
+
clean_non_generated_files_with_feedback
|
26
|
+
|
19
27
|
are_generated_files_present_and_up_to_date = Dir.exist?(generated_packs_directory_path) &&
|
20
28
|
File.exist?(generated_server_bundle_file_path) &&
|
21
29
|
!stale_or_missing_packs?
|
22
30
|
|
23
|
-
|
31
|
+
if are_generated_files_present_and_up_to_date
|
32
|
+
puts Rainbow("โ
Generated packs are up to date, no regeneration needed").green
|
33
|
+
return
|
34
|
+
end
|
24
35
|
|
25
|
-
|
36
|
+
clean_generated_directories_with_feedback
|
26
37
|
generate_packs
|
27
38
|
end
|
28
39
|
|
@@ -44,11 +55,66 @@ module ReactOnRails
|
|
44
55
|
puts(Rainbow("Generated Packs: #{output_path}").yellow)
|
45
56
|
end
|
46
57
|
|
58
|
+
def first_js_statement_in_code(content) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
59
|
+
return "" if content.nil? || content.empty?
|
60
|
+
|
61
|
+
start_index = 0
|
62
|
+
content_length = content.length
|
63
|
+
|
64
|
+
while start_index < content_length
|
65
|
+
# Skip whitespace
|
66
|
+
start_index += 1 while start_index < content_length && content[start_index].match?(/\s/)
|
67
|
+
|
68
|
+
break if start_index >= content_length
|
69
|
+
|
70
|
+
current_chars = content[start_index, 2]
|
71
|
+
|
72
|
+
case current_chars
|
73
|
+
when "//"
|
74
|
+
# Single-line comment
|
75
|
+
newline_index = content.index("\n", start_index)
|
76
|
+
return "" if newline_index.nil?
|
77
|
+
|
78
|
+
start_index = newline_index + 1
|
79
|
+
when "/*"
|
80
|
+
# Multi-line comment
|
81
|
+
comment_end = content.index("*/", start_index)
|
82
|
+
return "" if comment_end.nil?
|
83
|
+
|
84
|
+
start_index = comment_end + 2
|
85
|
+
else
|
86
|
+
# Found actual content
|
87
|
+
next_line_index = content.index("\n", start_index)
|
88
|
+
return next_line_index ? content[start_index...next_line_index].strip : content[start_index..].strip
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
""
|
93
|
+
end
|
94
|
+
|
95
|
+
def client_entrypoint?(file_path)
|
96
|
+
content = File.read(file_path)
|
97
|
+
# has "use client" directive. It can be "use client" or 'use client'
|
98
|
+
first_js_statement_in_code(content).match?(/^["']use client["'](?:;|\s|$)/)
|
99
|
+
end
|
100
|
+
|
47
101
|
def pack_file_contents(file_path)
|
48
102
|
registered_component_name = component_name(file_path)
|
49
|
-
|
103
|
+
load_server_components = ReactOnRails::Utils.rsc_support_enabled?
|
104
|
+
|
105
|
+
if load_server_components && !client_entrypoint?(file_path)
|
106
|
+
return <<~FILE_CONTENT.strip
|
107
|
+
import registerServerComponent from 'react-on-rails/registerServerComponent/client';
|
108
|
+
|
109
|
+
registerServerComponent("#{registered_component_name}");
|
110
|
+
FILE_CONTENT
|
111
|
+
end
|
112
|
+
|
113
|
+
relative_component_path = relative_component_path_from_generated_pack(file_path)
|
114
|
+
|
115
|
+
<<~FILE_CONTENT.strip
|
50
116
|
import ReactOnRails from 'react-on-rails/client';
|
51
|
-
import #{registered_component_name} from '#{
|
117
|
+
import #{registered_component_name} from '#{relative_component_path}';
|
52
118
|
|
53
119
|
ReactOnRails.register({#{registered_component_name}});
|
54
120
|
FILE_CONTENT
|
@@ -61,27 +127,46 @@ module ReactOnRails
|
|
61
127
|
puts(Rainbow("Generated Server Bundle: #{generated_server_bundle_file_path}").orange)
|
62
128
|
end
|
63
129
|
|
130
|
+
def build_server_pack_content(component_on_server_imports, server_components, client_components)
|
131
|
+
content = <<~FILE_CONTENT
|
132
|
+
import ReactOnRails from 'react-on-rails';
|
133
|
+
|
134
|
+
#{component_on_server_imports.join("\n")}\n
|
135
|
+
FILE_CONTENT
|
136
|
+
|
137
|
+
if server_components.any?
|
138
|
+
content += <<~FILE_CONTENT
|
139
|
+
import registerServerComponent from 'react-on-rails/registerServerComponent/server';
|
140
|
+
registerServerComponent({#{server_components.join(",\n")}});\n
|
141
|
+
FILE_CONTENT
|
142
|
+
end
|
143
|
+
|
144
|
+
content + "ReactOnRails.register({#{client_components.join(",\n")}});"
|
145
|
+
end
|
146
|
+
|
64
147
|
def generated_server_pack_file_content
|
65
148
|
common_components_for_server_bundle = common_component_to_path.delete_if { |k| server_component_to_path.key?(k) }
|
66
149
|
component_for_server_registration_to_path = common_components_for_server_bundle.merge(server_component_to_path)
|
67
150
|
|
68
|
-
|
151
|
+
component_on_server_imports = component_for_server_registration_to_path.map do |name, component_path|
|
69
152
|
"import #{name} from '#{relative_path(generated_server_bundle_file_path, component_path)}';"
|
70
153
|
end
|
71
154
|
|
72
|
-
|
155
|
+
load_server_components = ReactOnRails::Utils.rsc_support_enabled?
|
156
|
+
server_components = component_for_server_registration_to_path.keys.delete_if do |name|
|
157
|
+
next true unless load_server_components
|
73
158
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
159
|
+
component_path = component_for_server_registration_to_path[name]
|
160
|
+
client_entrypoint?(component_path)
|
161
|
+
end
|
162
|
+
client_components = component_for_server_registration_to_path.keys - server_components
|
78
163
|
|
79
|
-
|
80
|
-
FILE_CONTENT
|
164
|
+
build_server_pack_content(component_on_server_imports, server_components, client_components)
|
81
165
|
end
|
82
166
|
|
83
167
|
def add_generated_pack_to_server_bundle
|
84
168
|
return if ReactOnRails.configuration.make_generated_server_bundle_the_entrypoint
|
169
|
+
return if ReactOnRails.configuration.server_bundle_js_file.blank?
|
85
170
|
|
86
171
|
relative_path_to_generated_server_bundle = relative_path(server_bundle_entrypoint,
|
87
172
|
generated_server_bundle_file_path)
|
@@ -109,9 +194,112 @@ module ReactOnRails
|
|
109
194
|
"#{generated_nonentrypoints_path}/#{generated_server_bundle_file_name}.js"
|
110
195
|
end
|
111
196
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
197
|
+
def clean_non_generated_files_with_feedback
|
198
|
+
directories_to_clean = [generated_packs_directory_path, generated_server_bundle_directory_path].compact.uniq
|
199
|
+
expected_files = build_expected_files_set
|
200
|
+
|
201
|
+
puts Rainbow("๐งน Cleaning non-generated files...").yellow
|
202
|
+
|
203
|
+
total_deleted = directories_to_clean.sum do |dir_path|
|
204
|
+
clean_unexpected_files_from_directory(dir_path, expected_files)
|
205
|
+
end
|
206
|
+
|
207
|
+
display_cleanup_summary(total_deleted)
|
208
|
+
end
|
209
|
+
|
210
|
+
def build_expected_files_set
|
211
|
+
expected_pack_files = Set.new
|
212
|
+
common_component_to_path.each_value { |path| expected_pack_files << generated_pack_path(path) }
|
213
|
+
client_component_to_path.each_value { |path| expected_pack_files << generated_pack_path(path) }
|
214
|
+
|
215
|
+
if ReactOnRails.configuration.server_bundle_js_file.present?
|
216
|
+
expected_server_bundle = generated_server_bundle_file_path
|
217
|
+
end
|
218
|
+
|
219
|
+
{ pack_files: expected_pack_files, server_bundle: expected_server_bundle }
|
220
|
+
end
|
221
|
+
|
222
|
+
def clean_unexpected_files_from_directory(dir_path, expected_files)
|
223
|
+
return 0 unless Dir.exist?(dir_path)
|
224
|
+
|
225
|
+
existing_files = Dir.glob("#{dir_path}/**/*").select { |f| File.file?(f) }
|
226
|
+
unexpected_files = find_unexpected_files(existing_files, dir_path, expected_files)
|
227
|
+
|
228
|
+
if unexpected_files.any?
|
229
|
+
delete_unexpected_files(unexpected_files, dir_path)
|
230
|
+
unexpected_files.length
|
231
|
+
else
|
232
|
+
puts Rainbow(" No unexpected files found in #{dir_path}").cyan
|
233
|
+
0
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def find_unexpected_files(existing_files, dir_path, expected_files)
|
238
|
+
existing_files.reject do |file|
|
239
|
+
if dir_path == generated_server_bundle_directory_path
|
240
|
+
file == expected_files[:server_bundle]
|
241
|
+
else
|
242
|
+
expected_files[:pack_files].include?(file)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def delete_unexpected_files(unexpected_files, dir_path)
|
248
|
+
puts Rainbow(" Deleting #{unexpected_files.length} unexpected files from #{dir_path}:").cyan
|
249
|
+
unexpected_files.each do |file|
|
250
|
+
puts Rainbow(" - #{File.basename(file)}").blue
|
251
|
+
File.delete(file)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def display_cleanup_summary(total_deleted)
|
256
|
+
if total_deleted.positive?
|
257
|
+
puts Rainbow("๐๏ธ Deleted #{total_deleted} unexpected files total").red
|
258
|
+
else
|
259
|
+
puts Rainbow("โจ No unexpected files to delete").green
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def clean_generated_directories_with_feedback
|
264
|
+
directories_to_clean = [
|
265
|
+
generated_packs_directory_path,
|
266
|
+
generated_server_bundle_directory_path
|
267
|
+
].compact.uniq
|
268
|
+
|
269
|
+
puts Rainbow("๐งน Cleaning generated directories...").yellow
|
270
|
+
|
271
|
+
total_deleted = directories_to_clean.sum { |dir_path| clean_directory_with_feedback(dir_path) }
|
272
|
+
|
273
|
+
if total_deleted.positive?
|
274
|
+
puts Rainbow("๐๏ธ Deleted #{total_deleted} generated files total").red
|
275
|
+
else
|
276
|
+
puts Rainbow("โจ No files to delete, directories are clean").green
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def clean_directory_with_feedback(dir_path)
|
281
|
+
return create_directory_with_feedback(dir_path) unless Dir.exist?(dir_path)
|
282
|
+
|
283
|
+
files = Dir.glob("#{dir_path}/**/*").select { |f| File.file?(f) }
|
284
|
+
|
285
|
+
if files.any?
|
286
|
+
puts Rainbow(" Deleting #{files.length} files from #{dir_path}:").cyan
|
287
|
+
files.each { |file| puts Rainbow(" - #{File.basename(file)}").blue }
|
288
|
+
FileUtils.rm_rf(dir_path)
|
289
|
+
FileUtils.mkdir_p(dir_path)
|
290
|
+
files.length
|
291
|
+
else
|
292
|
+
puts Rainbow(" Directory #{dir_path} is already empty").cyan
|
293
|
+
FileUtils.rm_rf(dir_path)
|
294
|
+
FileUtils.mkdir_p(dir_path)
|
295
|
+
0
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def create_directory_with_feedback(dir_path)
|
300
|
+
puts Rainbow(" Directory #{dir_path} does not exist, creating...").cyan
|
301
|
+
FileUtils.mkdir_p(dir_path)
|
302
|
+
0
|
115
303
|
end
|
116
304
|
|
117
305
|
def server_bundle_entrypoint
|
@@ -125,6 +313,13 @@ module ReactOnRails
|
|
125
313
|
"#{source_entry_path}/generated"
|
126
314
|
end
|
127
315
|
|
316
|
+
def generated_server_bundle_directory_path
|
317
|
+
return nil if ReactOnRails.configuration.make_generated_server_bundle_the_entrypoint
|
318
|
+
|
319
|
+
source_entrypoint_parent = Pathname(ReactOnRails::PackerUtils.packer_source_entry_path).parent
|
320
|
+
"#{source_entrypoint_parent}/generated"
|
321
|
+
end
|
322
|
+
|
128
323
|
def relative_component_path_from_generated_pack(ror_component_path)
|
129
324
|
component_file_pathname = Pathname.new(ror_component_path)
|
130
325
|
component_generated_pack_path = generated_pack_path(ror_component_path)
|
@@ -155,14 +350,20 @@ module ReactOnRails
|
|
155
350
|
paths.to_h { |path| [component_name(path), path] }
|
156
351
|
end
|
157
352
|
|
353
|
+
def filter_component_files(paths)
|
354
|
+
paths.grep(COMPONENT_EXTENSIONS)
|
355
|
+
end
|
356
|
+
|
158
357
|
def common_component_to_path
|
159
358
|
common_components_paths = Dir.glob("#{components_search_path}/*").grep_v(CONTAINS_CLIENT_OR_SERVER_REGEX)
|
160
|
-
|
359
|
+
filtered_paths = filter_component_files(common_components_paths)
|
360
|
+
component_name_to_path(filtered_paths)
|
161
361
|
end
|
162
362
|
|
163
363
|
def client_component_to_path
|
164
364
|
client_render_components_paths = Dir.glob("#{components_search_path}/*.client.*")
|
165
|
-
|
365
|
+
filtered_client_paths = filter_component_files(client_render_components_paths)
|
366
|
+
client_specific_components = component_name_to_path(filtered_client_paths)
|
166
367
|
|
167
368
|
duplicate_components = common_component_to_path.slice(*client_specific_components.keys)
|
168
369
|
duplicate_components.each_key { |component| raise_client_component_overrides_common(component) }
|
@@ -172,7 +373,8 @@ module ReactOnRails
|
|
172
373
|
|
173
374
|
def server_component_to_path
|
174
375
|
server_render_components_paths = Dir.glob("#{components_search_path}/*.server.*")
|
175
|
-
|
376
|
+
filtered_server_paths = filter_component_files(server_render_components_paths)
|
377
|
+
server_specific_components = component_name_to_path(filtered_server_paths)
|
176
378
|
|
177
379
|
duplicate_components = common_component_to_path.slice(*server_specific_components.keys)
|
178
380
|
duplicate_components.each_key { |component| raise_server_component_overrides_common(component) }
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# React on Rails Pro License
|
2
|
+
|
3
|
+
The files in this directory and its subdirectories are licensed under the **React on Rails Pro** license, which is separate from the MIT license that covers the core React on Rails functionality.
|
4
|
+
|
5
|
+
## License Terms
|
6
|
+
|
7
|
+
These files are proprietary software and are **NOT** covered by the MIT license found in the root LICENSE.md file. Usage requires a valid React on Rails Pro license.
|
8
|
+
|
9
|
+
## Distribution
|
10
|
+
|
11
|
+
Files in this directory will be **omitted** from future distributions of the open source React on Rails Ruby gem. They are exclusively available to React on Rails Pro licensees.
|
12
|
+
|
13
|
+
## License Reference
|
14
|
+
|
15
|
+
For the complete React on Rails Pro license terms, see: `REACT-ON-RAILS-PRO-LICENSE.md` in the root directory of this repository.
|
16
|
+
|
17
|
+
## More Information
|
18
|
+
|
19
|
+
For React on Rails Pro licensing information and to obtain a license, please visit:
|
20
|
+
- [React on Rails Pro](https://www.shakacode.com/react-on-rails-pro/)
|
21
|
+
- Contact: [react_on_rails@shakacode.com](mailto:react_on_rails@shakacode.com)
|