react_on_rails 13.2.0 → 13.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +5 -2
  3. data/.github/workflows/lint-js-and-ruby.yml +3 -3
  4. data/.github/workflows/main.yml +15 -13
  5. data/.github/workflows/package-js-tests.yml +2 -2
  6. data/.github/workflows/rspec-package-specs.yml +2 -2
  7. data/.rubocop.yml +4 -0
  8. data/CHANGELOG.md +19 -1
  9. data/Gemfile.development_dependencies +1 -1
  10. data/README.md +5 -5
  11. data/docs/getting-started.md +11 -5
  12. data/docs/guides/configuration.md +23 -18
  13. data/docs/guides/file-system-based-automated-bundle-generation.md +2 -0
  14. data/docs/guides/installation-into-an-existing-rails-app.md +18 -20
  15. data/docs/guides/tutorial.md +35 -31
  16. data/lib/generators/react_on_rails/base_generator.rb +15 -10
  17. data/lib/generators/react_on_rails/bin/dev +33 -0
  18. data/lib/generators/react_on_rails/bin/dev-static +33 -0
  19. data/lib/generators/react_on_rails/install_generator.rb +5 -0
  20. data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb +1 -1
  21. data/lib/react_on_rails/configuration.rb +40 -3
  22. data/lib/react_on_rails/helper.rb +21 -23
  23. data/lib/react_on_rails/packs_generator.rb +30 -101
  24. data/lib/react_on_rails/test_helper/ensure_assets_compiled.rb +1 -1
  25. data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +1 -20
  26. data/lib/react_on_rails/test_helper.rb +10 -1
  27. data/lib/react_on_rails/utils.rb +22 -0
  28. data/lib/react_on_rails/version.rb +1 -1
  29. data/lib/react_on_rails/webpacker_utils.rb +59 -3
  30. data/lib/tasks/generate_packs.rake +1 -1
  31. data/package.json +29 -28
  32. data/yarn.lock +2856 -3277
  33. metadata +4 -2
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ def installed?(process)
5
+ IO.popen "#{process} -v"
6
+ rescue Errno::ENOENT
7
+ false
8
+ end
9
+
10
+ def run(process)
11
+ args = [*ARGV]
12
+ args.shift
13
+ puts "Using #{process}"
14
+ exec "#{process} start -f Procfile.dev", args.join(" ")
15
+ rescue Errno::ENOENT
16
+ warn <<~MSG
17
+ ERROR:
18
+ Please ensure `Procfile.dev` exist in your project!
19
+ MSG
20
+ exit!
21
+ end
22
+
23
+ if installed? "overmind"
24
+ run "overmind"
25
+ elsif installed? "foreman"
26
+ run "foreman"
27
+ else
28
+ warn <<~MSG
29
+ NOTICE:
30
+ For this script to run, you need either 'overmind' or 'foreman' installed on your machine. Please try this script after installing one of them.
31
+ MSG
32
+ exit!
33
+ end
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ def installed?(process)
5
+ IO.popen "#{process} -v"
6
+ rescue Errno::ENOENT
7
+ false
8
+ end
9
+
10
+ def run(process)
11
+ args = [*ARGV]
12
+ args.shift
13
+ puts "Using #{process}"
14
+ exec "#{process} start -f Procfile.dev-static", args.join(" ")
15
+ rescue Errno::ENOENT
16
+ warn <<~MSG
17
+ ERROR:
18
+ Please ensure `Procfile.dev-static` exist in your project!
19
+ MSG
20
+ exit!
21
+ end
22
+
23
+ if installed? "overmind"
24
+ run "overmind"
25
+ elsif installed? "foreman"
26
+ run "foreman"
27
+ else
28
+ warn <<~MSG
29
+ NOTICE:
30
+ For this script to run, you need either 'overmind' or 'foreman' installed on your machine. Please try this script after installing one of them.
31
+ MSG
32
+ exit!
33
+ end
@@ -28,6 +28,7 @@ module ReactOnRails
28
28
  def run_generators
29
29
  if installation_prerequisites_met? || options.ignore_warnings?
30
30
  invoke_generators
31
+ add_bin_scripts
31
32
  else
32
33
  error = "react_on_rails generator prerequisites not met!"
33
34
  GeneratorMessages.add_error(error)
@@ -75,6 +76,10 @@ module ReactOnRails
75
76
  GeneratorMessages.add_error(error)
76
77
  true
77
78
  end
79
+
80
+ def add_bin_scripts
81
+ directory "#{__dir__}/bin", "bin"
82
+ end
78
83
  end
79
84
  end
80
85
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # See https://github.com/shakacode/react_on_rails/blob/master/docs/basics/configuration.md
3
+ # See https://github.com/shakacode/react_on_rails/blob/master/docs/guides/configuration.md
4
4
  # for many more options.
5
5
 
6
6
  ReactOnRails.configure do |config|
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rubocop:disable Metrics/ClassLength
4
+
3
5
  module ReactOnRails
4
6
  def self.configure
5
7
  yield(configuration)
@@ -109,6 +111,7 @@ module ReactOnRails
109
111
 
110
112
  # on ReactOnRails
111
113
  def setup_config_values
114
+ check_autobundling_requirements_if_configured
112
115
  ensure_webpack_generated_files_exists
113
116
  configure_generated_assets_dirs_deprecation
114
117
  configure_skip_display_none_deprecation
@@ -121,14 +124,37 @@ module ReactOnRails
121
124
 
122
125
  private
123
126
 
127
+ def check_autobundling_requirements_if_configured
128
+ raise_missing_components_subdirectory if auto_load_bundle && !components_subdirectory.present?
129
+ return unless components_subdirectory.present?
130
+
131
+ ReactOnRails::WebpackerUtils.raise_shakapacker_not_installed unless ReactOnRails::WebpackerUtils.using_webpacker?
132
+ ReactOnRails::WebpackerUtils.raise_shakapacker_version_incompatible_for_autobundling unless
133
+ ReactOnRails::WebpackerUtils.shackapacker_version_requirement_met?(
134
+ ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION
135
+ )
136
+ ReactOnRails::WebpackerUtils.raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries?
137
+ end
138
+
124
139
  def adjust_precompile_task
125
140
  skip_react_on_rails_precompile = %w[no false n f].include?(ENV["REACT_ON_RAILS_PRECOMPILE"])
126
141
 
127
142
  return if skip_react_on_rails_precompile || build_production_command.blank?
128
143
 
129
- # Ensure that shakacode/shakapacker does not call bin/webpacker if we're providing
130
- # the build command.
131
- ENV["WEBPACKER_PRECOMPILE"] = "false"
144
+ if Webpacker.config.webpacker_precompile?
145
+ msg = <<~MSG
146
+
147
+ React on Rails and Shakapacker error in configuration!
148
+ In order to use config/react_on_rails.rb config.build_production_command,
149
+ you must edit config/webpacker.yml to include this value in the default configuration:
150
+ 'webpacker_precompile: false'
151
+
152
+ Alternatively, remove the config/react_on_rails.rb config.build_production_command and the
153
+ default bin/webpacker script will be used for assets:precompile.
154
+
155
+ MSG
156
+ raise ReactOnRails::Error, msg
157
+ end
132
158
 
133
159
  precompile_tasks = lambda {
134
160
  Rake::Task["react_on_rails:generate_packs"].invoke
@@ -230,5 +256,16 @@ module ReactOnRails
230
256
 
231
257
  Rails.logger.warn "[DEPRECATION] ReactOnRails: remove skip_display_none from configuration."
232
258
  end
259
+
260
+ def raise_missing_components_subdirectory
261
+ msg = <<~MSG
262
+ **ERROR** ReactOnRails: auto_load_bundle is set to true, yet components_subdirectory is unconfigured.\
263
+ Please set components_subdirectory to the desired directory. For more information, please see \
264
+ https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md
265
+ MSG
266
+
267
+ raise ReactOnRails::Error, msg
268
+ end
233
269
  end
234
270
  end
271
+ # rubocop:enable Metrics/ClassLength
@@ -91,26 +91,6 @@ module ReactOnRails
91
91
  end
92
92
  end
93
93
 
94
- def load_pack_for_component(component_name)
95
- component_pack_file = generated_components_pack(component_name)
96
- is_component_pack_present = File.exist?("#{component_pack_file}.jsx")
97
- is_development = ENV["RAILS_ENV"] == "development"
98
-
99
- if is_development && !is_component_pack_present
100
- ReactOnRails::PacksGenerator.generate
101
- raise_generated_missing_pack_warning(component_name)
102
- end
103
-
104
- ReactOnRails::PacksGenerator.raise_nested_enteries_disabled unless ReactOnRails::WebpackerUtils.nested_entries?
105
-
106
- append_javascript_pack_tag "generated/#{component_name}"
107
- append_stylesheet_pack_tag "generated/#{component_name}"
108
- end
109
-
110
- def generated_components_pack(component_name)
111
- "#{ReactOnRails::WebpackerUtils.webpacker_source_entry_path}/generated/#{component_name}"
112
- end
113
-
114
94
  # react_component_hash is used to return multiple HTML strings for server rendering, such as for
115
95
  # adding meta-tags to a page.
116
96
  # It is exactly like react_component except for the following:
@@ -337,6 +317,25 @@ module ReactOnRails
337
317
 
338
318
  private
339
319
 
320
+ def load_pack_for_component(component_name)
321
+ is_component_pack_present = File.exist?(generated_components_pack_path(component_name))
322
+ is_development = ENV["RAILS_ENV"] == "development"
323
+
324
+ if is_development && !is_component_pack_present
325
+ ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
326
+ raise_missing_pack_error(component_name)
327
+ end
328
+
329
+ ReactOnRails::WebpackerUtils.raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries?
330
+
331
+ append_javascript_pack_tag "generated/#{component_name}"
332
+ append_stylesheet_pack_tag "generated/#{component_name}"
333
+ end
334
+
335
+ def generated_components_pack_path(component_name)
336
+ "#{ReactOnRails::WebpackerUtils.webpacker_source_entry_path}/generated/#{component_name}.js"
337
+ end
338
+
340
339
  def build_react_component_result_for_server_rendered_string(
341
340
  server_rendered_html: required("server_rendered_html"),
342
341
  component_specification_tag: required("component_specification_tag"),
@@ -552,10 +551,9 @@ module ReactOnRails
552
551
  result
553
552
  end
554
553
 
555
- def raise_generated_missing_pack_warning(component_name)
554
+ def raise_missing_pack_error(component_name)
556
555
  msg = <<~MSG
557
- **ERROR** ReactOnRails: Generated missing pack for Component: #{component_name}. Please refresh the webpage \
558
- once webpack has finished generating the bundles. If the problem persists
556
+ **ERROR** ReactOnRails: Generated missing pack for Component: #{component_name}. Please restart the webpack dev server or webpack in watch mode, to ensure webpack generates the chunks corresponding to #{component_name} component. If the problem persists
559
557
  1. Verify `components_subdirectory` is configured in `config/initializers/react_on_rails`.
560
558
  2. Component: #{component_name} is placed inside the configured `components_subdirectory`.
561
559
  MSG
@@ -6,45 +6,23 @@ module ReactOnRails
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class PacksGenerator
8
8
  CONTAINS_CLIENT_OR_SERVER_REGEX = /\.(server|client)($|\.)/.freeze
9
- MINIMUM_SHAKAPACKER_MAJOR_VERSION = 6
10
- MINIMUM_SHAKAPACKER_MINOR_VERSION = 5
11
- MINIMUM_SHAKAPACKER_PATCH_VERSION = 1
9
+ MINIMUM_SHAKAPACKER_VERSION = [6, 5, 1].freeze
12
10
 
13
- def self.generate
14
- packs_generator = PacksGenerator.new
15
- packs_generator.verify_setup_and_generate_packs
11
+ def self.instance
12
+ @instance ||= PacksGenerator.new
16
13
  end
17
14
 
18
- def self.raise_nested_enteries_disabled
19
- packs_generator = PacksGenerator.new
20
- packs_generator.raise_nested_enteries_disabled
21
- end
22
-
23
- def verify_setup_and_generate_packs
24
- return unless components_subdirectory.present?
25
-
26
- raise_webpacker_not_installed unless ReactOnRails::WebpackerUtils.using_webpacker?
27
- raise_shakapacker_version_incompatible unless shackapacker_version_requirement_met?
28
- raise_nested_enteries_disabled unless ReactOnRails::WebpackerUtils.nested_entries?
15
+ def generate_packs_if_stale
16
+ are_generated_files_present_and_up_to_date = Dir.exist?(generated_packs_directory_path) &&
17
+ File.exist?(generated_server_bundle_file_path) &&
18
+ !stale_or_missing_packs?
29
19
 
30
- is_generated_directory_present = Dir.exist?(generated_packs_directory_path)
31
-
32
- return if is_generated_directory_present && webpack_assets_status_checker.stale_generated_component_packs.empty?
20
+ return if are_generated_files_present_and_up_to_date
33
21
 
34
22
  clean_generated_packs_directory
35
23
  generate_packs
36
24
  end
37
25
 
38
- def raise_nested_enteries_disabled
39
- msg = <<~MSG
40
- **ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shakapacker. Please update \
41
- webpacker.yml to enable nested enteries. for more information read
42
- https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md#enable-nested_entries-for-shakapacker
43
- MSG
44
-
45
- raise ReactOnRails::Error, msg
46
- end
47
-
48
26
  private
49
27
 
50
28
  def generate_packs
@@ -100,22 +78,26 @@ module ReactOnRails
100
78
  end
101
79
 
102
80
  def add_generated_pack_to_server_bundle
103
- relative_path_to_generated_server_bundle = relative_path(defined_server_bundle_file_path,
81
+ relative_path_to_generated_server_bundle = relative_path(server_bundle_entrypoint,
104
82
  generated_server_bundle_file_path)
105
83
  content = <<~FILE_CONTENT
106
- import "./#{relative_path_to_generated_server_bundle}"\n
84
+ // import statement added by react_on_rails:generate_packs rake task
85
+ import "./#{relative_path_to_generated_server_bundle}"
107
86
  FILE_CONTENT
108
87
 
109
- prepend_to_file_if_not_present(defined_server_bundle_file_path, content)
88
+ ReactOnRails::Utils.prepend_to_file_if_text_not_present(
89
+ file: server_bundle_entrypoint,
90
+ text_to_prepend: content,
91
+ regex: %r{import ['"]\./#{relative_path_to_generated_server_bundle}['"]}
92
+ )
110
93
  end
111
94
 
112
95
  def generated_server_bundle_file_path
113
- file_ext = File.extname(defined_server_bundle_file_path)
114
- generated_server_bundle_file_path = defined_server_bundle_file_path.sub(file_ext, "-generated#{file_ext}")
96
+ generated_server_bundle_file_path = server_bundle_entrypoint.sub(".js", "-generated.js")
115
97
  generated_server_bundle_file_name = component_name(generated_server_bundle_file_path)
116
98
  source_entry_path = ReactOnRails::WebpackerUtils.webpacker_source_entry_path
117
99
 
118
- "#{source_entry_path}/#{generated_server_bundle_file_name}#{file_ext}"
100
+ "#{source_entry_path}/#{generated_server_bundle_file_name}.js"
119
101
  end
120
102
 
121
103
  def clean_generated_packs_directory
@@ -123,8 +105,9 @@ module ReactOnRails
123
105
  FileUtils.mkdir_p(generated_packs_directory_path)
124
106
  end
125
107
 
126
- def defined_server_bundle_file_path
127
- ReactOnRails::Utils.server_bundle_js_file_path
108
+ def server_bundle_entrypoint
109
+ Rails.root.join(ReactOnRails::WebpackerUtils.webpacker_source_entry_path,
110
+ ReactOnRails.configuration.server_bundle_js_file)
128
111
  end
129
112
 
130
113
  def generated_packs_directory_path
@@ -150,7 +133,7 @@ module ReactOnRails
150
133
  end
151
134
 
152
135
  def generated_pack_path(file_path)
153
- "#{generated_packs_directory_path}/#{component_name(file_path)}.jsx"
136
+ "#{generated_packs_directory_path}/#{component_name(file_path)}.js"
154
137
  end
155
138
 
156
139
  def component_name(file_path)
@@ -197,23 +180,7 @@ module ReactOnRails
197
180
  def components_search_path
198
181
  source_path = ReactOnRails::WebpackerUtils.webpacker_source_path
199
182
 
200
- "#{source_path}/**/#{components_subdirectory}"
201
- end
202
-
203
- def components_subdirectory
204
- ReactOnRails.configuration.components_subdirectory
205
- end
206
-
207
- def webpack_assets_status_checker
208
- source_path = ReactOnRails::Utils.source_path
209
- generated_assets_full_path = ReactOnRails::Utils.generated_assets_full_path
210
- webpack_generated_files = ReactOnRails.configuration.webpack_generated_files
211
-
212
- @webpack_assets_status_checker ||= ReactOnRails::TestHelper::WebpackAssetsStatusChecker.new(
213
- source_path: source_path,
214
- generated_assets_full_path: generated_assets_full_path,
215
- webpack_generated_files: webpack_generated_files
216
- )
183
+ "#{source_path}/**/#{ReactOnRails.configuration.components_subdirectory}"
217
184
  end
218
185
 
219
186
  def raise_client_component_overrides_common(component_name)
@@ -245,53 +212,15 @@ module ReactOnRails
245
212
  raise ReactOnRails::Error, msg
246
213
  end
247
214
 
248
- def raise_shakapacker_version_incompatible
249
- msg = <<~MSG
250
- **ERROR** ReactOnRails: Please upgrade Shakapacker to version #{minimum_required_shakapacker_version} or \
251
- above to use the automated bundle generation feature. The currently installed version is \
252
- #{ReactOnRails::WebpackerUtils.shakapacker_version}.
253
- MSG
254
-
255
- raise ReactOnRails::Error, msg
256
- end
257
-
258
- def raise_webpacker_not_installed
259
- msg = <<~MSG
260
- **ERROR** ReactOnRails: Missing Shakapacker gem. Please upgrade to use Shakapacker \
261
- #{minimum_required_shakapacker_version} or above to use the \
262
- automated bundle generation feature.
263
- MSG
264
-
265
- raise ReactOnRails::Error, msg
266
- end
215
+ def stale_or_missing_packs?
216
+ component_files = common_component_to_path.values + client_component_to_path.values
217
+ most_recent_mtime = Utils.find_most_recent_mtime(component_files)
267
218
 
268
- def shakapacker_major_minor_version
269
- shakapacker_version = ReactOnRails::WebpackerUtils.shakapacker_version
270
- match = shakapacker_version.match(ReactOnRails::VersionChecker::MAJOR_MINOR_PATCH_VERSION_REGEX)
219
+ component_files.each_with_object([]).any? do |file|
220
+ path = generated_pack_path(file)
271
221
 
272
- [match[1].to_i, match[2].to_i, match[3].to_i]
273
- end
274
-
275
- def shackapacker_version_requirement_met?
276
- major = shakapacker_major_minor_version[0]
277
- minor = shakapacker_major_minor_version[1]
278
- patch = shakapacker_major_minor_version[2]
279
-
280
- major >= MINIMUM_SHAKAPACKER_MAJOR_VERSION && minor >= MINIMUM_SHAKAPACKER_MINOR_VERSION &&
281
- patch >= MINIMUM_SHAKAPACKER_PATCH_VERSION
282
- end
283
-
284
- def minimum_required_shakapacker_version
285
- "#{MINIMUM_SHAKAPACKER_MAJOR_VERSION}.#{MINIMUM_SHAKAPACKER_MINOR_VERSION}.#{MINIMUM_SHAKAPACKER_PATCH_VERSION}"
286
- end
287
-
288
- def prepend_to_file_if_not_present(file, text_to_prepend)
289
- file_content = File.read(file)
290
-
291
- return if file_content.include?(text_to_prepend)
292
-
293
- content_with_prepended_text = text_to_prepend + file_content
294
- File.write(file, content_with_prepended_text)
222
+ !File.exist?(path) || File.mtime(path) < most_recent_mtime
223
+ end
295
224
  end
296
225
  end
297
226
  # rubocop:enable Metrics/ClassLength
@@ -37,7 +37,7 @@ module ReactOnRails
37
37
  # All done if no stale files!
38
38
  return if stale_gen_files.empty?
39
39
 
40
- ReactOnRails::PacksGenerator.generate
40
+ ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
41
41
 
42
42
  # Inform the developer that we're ensuring gen assets are ready.
43
43
  puts_start_compile_check_message(stale_gen_files)
@@ -29,17 +29,13 @@ module ReactOnRails
29
29
  stale_generated_files(client_files)
30
30
  end
31
31
 
32
- def stale_generated_component_packs
33
- stale_generated_files(component_pack_files)
34
- end
35
-
36
32
  def stale_generated_files(files)
37
33
  manifest_needed = ReactOnRails::WebpackerUtils.using_webpacker? &&
38
34
  !ReactOnRails::WebpackerUtils.manifest_exists?
39
35
 
40
36
  return ["manifest.json"] if manifest_needed
41
37
 
42
- most_recent_mtime = find_most_recent_mtime(files)
38
+ most_recent_mtime = Utils.find_most_recent_mtime(files)
43
39
  all_compiled_assets.each_with_object([]) do |webpack_generated_file, stale_gen_list|
44
40
  if !File.exist?(webpack_generated_file) ||
45
41
  File.mtime(webpack_generated_file) < most_recent_mtime
@@ -51,13 +47,6 @@ module ReactOnRails
51
47
 
52
48
  private
53
49
 
54
- def find_most_recent_mtime(files)
55
- files.reduce(1.year.ago) do |newest_time, file|
56
- mt = File.mtime(file)
57
- mt > newest_time ? mt : newest_time
58
- end
59
- end
60
-
61
50
  def all_compiled_assets
62
51
  @all_compiled_assets ||= begin
63
52
  webpack_generated_files = @webpack_generated_files.map do |bundle_name|
@@ -89,14 +78,6 @@ module ReactOnRails
89
78
  @client_files ||= make_file_list(make_globs(source_path)).to_ary
90
79
  end
91
80
 
92
- def component_pack_files
93
- make_file_list(make_globs(components_search_path)).to_ary
94
- end
95
-
96
- def components_search_path
97
- "#{source_path}/**/#{ReactOnRails.configuration.components_subdirectory}"
98
- end
99
-
100
81
  def make_globs(dirs)
101
82
  Array(dirs).map { |dir| File.join(dir, "**", "*") }
102
83
  end
@@ -35,8 +35,17 @@ module ReactOnRails
35
35
  def self.configure_rspec_to_compile_assets(config, *metatags)
36
36
  metatags = %i[js server_rendering controller] if metatags.empty?
37
37
 
38
+ # Supported since RSpec 3.5.0
39
+ supports_first_matching_example = config.respond_to?(:when_first_matching_example_defined)
40
+
38
41
  metatags.each do |metatag|
39
- config.before(:example, metatag) { ReactOnRails::TestHelper.ensure_assets_compiled }
42
+ if supports_first_matching_example
43
+ config.when_first_matching_example_defined(metatag) do
44
+ ReactOnRails::TestHelper.ensure_assets_compiled
45
+ end
46
+ else
47
+ config.before(:example, metatag) { ReactOnRails::TestHelper.ensure_assets_compiled }
48
+ end
40
49
  end
41
50
  end
42
51
 
@@ -197,5 +197,27 @@ module ReactOnRails
197
197
  rstrip = to_remove - lstrip
198
198
  str[0..(midpoint - lstrip - 1)] + TRUNCATION_FILLER + str[(midpoint + rstrip)..-1]
199
199
  end
200
+
201
+ def self.find_most_recent_mtime(files)
202
+ files.reduce(1.year.ago) do |newest_time, file|
203
+ mt = File.mtime(file)
204
+ mt > newest_time ? mt : newest_time
205
+ end
206
+ end
207
+
208
+ def self.prepend_to_file_if_text_not_present(file:, text_to_prepend:, regex:)
209
+ if File.exist?(file)
210
+ file_content = File.read(file)
211
+
212
+ return if file_content.match(regex)
213
+
214
+ content_with_prepended_text = text_to_prepend + file_content
215
+ File.write(file, content_with_prepended_text, mode: "w")
216
+ else
217
+ File.write(file, text_to_prepend, mode: "w+")
218
+ end
219
+
220
+ puts "Prepended\n#{text_to_prepend}to #{file}."
221
+ end
200
222
  end
201
223
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "13.2.0"
4
+ VERSION = "13.3.1"
5
5
  end
@@ -2,8 +2,6 @@
2
2
 
3
3
  module ReactOnRails
4
4
  module WebpackerUtils
5
- # TODO: V13 code should be cleaned up so that the webpacker gem is required.
6
- # This check should only be done at startup.
7
5
  def self.using_webpacker?
8
6
  return @using_webpacker if defined?(@using_webpacker)
9
7
 
@@ -20,7 +18,19 @@ module ReactOnRails
20
18
  def self.shakapacker_version
21
19
  return nil unless ReactOnRails::Utils.gem_available?("shakapacker")
22
20
 
23
- Gem.loaded_specs["shakapacker"].version.to_s
21
+ @shakapacker_version ||= Gem.loaded_specs["shakapacker"].version.to_s
22
+ end
23
+
24
+ def self.shakapacker_version_as_array
25
+ match = shakapacker_version.match(ReactOnRails::VersionChecker::MAJOR_MINOR_PATCH_VERSION_REGEX)
26
+
27
+ @shakapacker_version_as_array = [match[1].to_i, match[2].to_i, match[3].to_i]
28
+ end
29
+
30
+ def self.shackapacker_version_requirement_met?(required_version)
31
+ req_ver = semver_to_string(required_version)
32
+
33
+ Gem::Version.new(shakapacker_version) >= Gem::Version.new(req_ver)
24
34
  end
25
35
 
26
36
  # This returns either a URL for the webpack-dev-server, non-server bundle or
@@ -85,5 +95,51 @@ module ReactOnRails
85
95
  puts wrap_message(msg)
86
96
  exit!
87
97
  end
98
+
99
+ def self.webpack_assets_status_checker
100
+ source_path = ReactOnRails::Utils.source_path
101
+ generated_assets_full_path = ReactOnRails::Utils.generated_assets_full_path
102
+ webpack_generated_files = ReactOnRails.configuration.webpack_generated_files
103
+
104
+ @webpack_assets_status_checker ||= ReactOnRails::TestHelper::WebpackAssetsStatusChecker.new(
105
+ source_path: source_path,
106
+ generated_assets_full_path: generated_assets_full_path,
107
+ webpack_generated_files: webpack_generated_files
108
+ )
109
+ end
110
+
111
+ def self.raise_nested_entries_disabled
112
+ msg = <<~MSG
113
+ **ERROR** ReactOnRails: `nested_entries` is configured to be disabled in shakapacker. Please update \
114
+ webpacker.yml to enable nested entries. for more information read
115
+ https://www.shakacode.com/react-on-rails/docs/guides/file-system-based-automated-bundle-generation.md#enable-nested_entries-for-shakapacker
116
+ MSG
117
+
118
+ raise ReactOnRails::Error, msg
119
+ end
120
+
121
+ def self.raise_shakapacker_version_incompatible_for_autobundling
122
+ msg = <<~MSG
123
+ **ERROR** ReactOnRails: Please upgrade Shakapacker to version #{ReactOnRails::WebpackerUtils.semver_to_string(ReactOnRails::PacksGenerator::MINIMUM_SHAKAPACKER_VERSION)} or \
124
+ above to use the automated bundle generation feature. The currently installed version is \
125
+ #{ReactOnRails::WebpackerUtils.semver_to_string(ReactOnRails::WebpackerUtils.shakapacker_version_as_array)}.
126
+ MSG
127
+
128
+ raise ReactOnRails::Error, msg
129
+ end
130
+
131
+ def self.raise_shakapacker_not_installed
132
+ msg = <<~MSG
133
+ **ERROR** ReactOnRails: Missing Shakapacker gem. Please upgrade to use Shakapacker \
134
+ #{ReactOnRails::WebpackerUtils.semver_to_string(minimum_required_shakapacker_version)} or above to use the \
135
+ automated bundle generation feature.
136
+ MSG
137
+
138
+ raise ReactOnRails::Error, msg
139
+ end
140
+
141
+ def self.semver_to_string(ary)
142
+ "#{ary[0]}.#{ary[1]}.#{ary[2]}"
143
+ end
88
144
  end
89
145
  end
@@ -6,6 +6,6 @@ namespace :react_on_rails do
6
6
  DESC
7
7
 
8
8
  task generate_packs: :environment do
9
- ReactOnRails::PacksGenerator.generate
9
+ ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
10
10
  end
11
11
  end