diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b462c4ba..a0bf61f84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,14 @@ Please follow the recommendations outlined at [keepachangelog.com](http://keepac Changes since last non-beta release. *Please add entries here for your pull requests that are not yet released.* -- Added `./bin/dev` and `./bin/dev-static` executables to ease and standardize running the dev server. [PR 1491](https://github.com/shakacode/react_on_rails/pull/1491) by [ahangarha](https://github.com/ahangarha) + +### [13.3.0] - 2022-01-28 +### Fixed - Fixed pack not found warning while using `react_component` and `react_component_hash` helpers, even when corresponding chunks are present. [PR 1511](https://github.com/shakacode/react_on_rails/pull/1511) by [pulkitkkr](https://github.com/pulkitkkr) +- Fixed FS-based packs generation functionality to trigger pack generation on the creation of a new react component inside `components_subdirectory`. [PR 1506](https://github.com/shakacode/react_on_rails/pull/1506) by [pulkitkkr](https://github.com/pulkitkkr) + +### Added +- Added `./bin/dev` and `./bin/dev-static` executables to ease and standardize running the dev server. [PR 1491](https://github.com/shakacode/react_on_rails/pull/1491) by [ahangarha](https://github.com/ahangarha) ### [13.2.0] - 2022-12-23 diff --git a/lib/react_on_rails/helper.rb b/lib/react_on_rails/helper.rb index d6e1ac76d..f3876445c 100644 --- a/lib/react_on_rails/helper.rb +++ b/lib/react_on_rails/helper.rb @@ -93,27 +93,6 @@ def react_component(component_name, options = {}) end end - def load_pack_for_component(component_name) - is_component_pack_present = File.exist?(generated_components_pack_path(component_name)) - is_development = ENV["RAILS_ENV"] == "development" - - if is_development && !is_component_pack_present - ReactOnRails::PacksGenerator.generate - raise_generated_missing_pack_warning(component_name) - end - - ReactOnRails::PacksGenerator.raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries? - - append_javascript_pack_tag "generated/#{component_name}" - append_stylesheet_pack_tag "generated/#{component_name}" - end - - def generated_components_pack_path(component_name) - extension = PacksGenerator::GENERATED_PACK_EXTENSION - - "#{ReactOnRails::WebpackerUtils.webpacker_source_entry_path}/generated/#{component_name}.#{extension}" - end - # react_component_hash is used to return multiple HTML strings for server rendering, such as for # adding meta-tags to a page. # It is exactly like react_component except for the following: @@ -340,6 +319,27 @@ def rails_context(server_side: true) private + def load_pack_for_component(component_name) + is_component_pack_present = File.exist?(generated_components_pack_path(component_name)) + is_development = ENV["RAILS_ENV"] == "development" + + if is_development && !is_component_pack_present + ReactOnRails::PacksGenerator.generate + raise_missing_pack_error(component_name) + end + + ReactOnRails::PacksGenerator.raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries? + + append_javascript_pack_tag "generated/#{component_name}" + append_stylesheet_pack_tag "generated/#{component_name}" + end + + def generated_components_pack_path(component_name) + extension = PacksGenerator::GENERATED_PACK_EXTENSION + + "#{ReactOnRails::WebpackerUtils.webpacker_source_entry_path}/generated/#{component_name}.#{extension}" + end + def build_react_component_result_for_server_rendered_string( server_rendered_html: required("server_rendered_html"), component_specification_tag: required("component_specification_tag"), @@ -555,10 +555,9 @@ def initialize_redux_stores result end - def raise_generated_missing_pack_warning(component_name) + def raise_missing_pack_error(component_name) msg = <<~MSG - **ERROR** ReactOnRails: Generated missing pack for Component: #{component_name}. Please refresh the webpage \ - once webpack has finished generating the bundles. If the problem persists + **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 1. Verify `components_subdirectory` is configured in `config/initializers/react_on_rails`. 2. Component: #{component_name} is placed inside the configured `components_subdirectory`. MSG diff --git a/lib/react_on_rails/packs_generator.rb b/lib/react_on_rails/packs_generator.rb index e5c4aba6f..a7592cfe9 100644 --- a/lib/react_on_rails/packs_generator.rb +++ b/lib/react_on_rails/packs_generator.rb @@ -24,13 +24,11 @@ def self.raise_nested_entries_disabled def verify_setup_and_generate_packs return unless components_subdirectory.present? - raise_webpacker_not_installed unless ReactOnRails::WebpackerUtils.using_webpacker? - raise_shakapacker_version_incompatible unless shackapacker_version_requirement_met? - raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries? + verify_configuration is_generated_directory_present = Dir.exist?(generated_packs_directory_path) - return if is_generated_directory_present && webpack_assets_status_checker.stale_generated_component_packs.empty? + return if is_generated_directory_present && !stale_or_missing_packs? clean_generated_packs_directory generate_packs @@ -297,6 +295,23 @@ def prepend_to_file_if_not_present(file, text_to_prepend) File.write(file, content_with_prepended_text) puts "Prepended\n#{text_to_prepend}to #{file}." end + + def stale_or_missing_packs? + component_files = common_component_to_path.values + client_component_to_path.values + most_recent_mtime = Utils.find_most_recent_mtime(component_files) + + component_files.each_with_object([]).any? do |file| + path = generated_pack_path(file) + + !File.exist?(path) || File.mtime(path) < most_recent_mtime + end + end + + def verify_configuration + raise_webpacker_not_installed unless ReactOnRails::WebpackerUtils.using_webpacker? + raise_shakapacker_version_incompatible unless shackapacker_version_requirement_met? + raise_nested_entries_disabled unless ReactOnRails::WebpackerUtils.nested_entries? + end end # rubocop:enable Metrics/ClassLength end diff --git a/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb b/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb index bd41f18cf..9fdd08b00 100644 --- a/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +++ b/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb @@ -29,17 +29,13 @@ def stale_generated_webpack_files stale_generated_files(client_files) end - def stale_generated_component_packs - stale_generated_files(component_pack_files) - end - def stale_generated_files(files) manifest_needed = ReactOnRails::WebpackerUtils.using_webpacker? && !ReactOnRails::WebpackerUtils.manifest_exists? return ["manifest.json"] if manifest_needed - most_recent_mtime = find_most_recent_mtime(files) + most_recent_mtime = Utils.find_most_recent_mtime(files) all_compiled_assets.each_with_object([]) do |webpack_generated_file, stale_gen_list| if !File.exist?(webpack_generated_file) || File.mtime(webpack_generated_file) < most_recent_mtime @@ -51,13 +47,6 @@ def stale_generated_files(files) private - def find_most_recent_mtime(files) - files.reduce(1.year.ago) do |newest_time, file| - mt = File.mtime(file) - mt > newest_time ? mt : newest_time - end - end - def all_compiled_assets @all_compiled_assets ||= begin webpack_generated_files = @webpack_generated_files.map do |bundle_name| @@ -89,14 +78,6 @@ def client_files @client_files ||= make_file_list(make_globs(source_path)).to_ary end - def component_pack_files - make_file_list(make_globs(components_search_path)).to_ary - end - - def components_search_path - "#{source_path}/**/#{ReactOnRails.configuration.components_subdirectory}" - end - def make_globs(dirs) Array(dirs).map { |dir| File.join(dir, "**", "*") } end diff --git a/lib/react_on_rails/utils.rb b/lib/react_on_rails/utils.rb index abb42a2e4..47efdc440 100644 --- a/lib/react_on_rails/utils.rb +++ b/lib/react_on_rails/utils.rb @@ -197,5 +197,12 @@ def self.smart_trim(str, max_length = 1000) rstrip = to_remove - lstrip str[0..(midpoint - lstrip - 1)] + TRUNCATION_FILLER + str[(midpoint + rstrip)..-1] end + + def self.find_most_recent_mtime(files) + files.reduce(1.year.ago) do |newest_time, file| + mt = File.mtime(file) + mt > newest_time ? mt : newest_time + end + end end end diff --git a/lib/react_on_rails/version.rb b/lib/react_on_rails/version.rb index 59a81d9f1..fe920a4ab 100644 --- a/lib/react_on_rails/version.rb +++ b/lib/react_on_rails/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module ReactOnRails - VERSION = "13.2.0" + VERSION = "13.3.0" end diff --git a/package.json b/package.json index 0568fc901..6ee3a82ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-on-rails", - "version": "13.2.0", + "version": "13.3.0", "description": "react-on-rails JavaScript for react_on_rails Ruby gem", "main": "node_package/lib/ReactOnRails.js", "directories": { diff --git a/spec/dummy/Gemfile.lock b/spec/dummy/Gemfile.lock index 745369f32..841c43774 100644 --- a/spec/dummy/Gemfile.lock +++ b/spec/dummy/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: ../.. specs: - react_on_rails (13.2.0) + react_on_rails (13.3.0) addressable connection_pool execjs (~> 2.5) diff --git a/spec/dummy/spec/packs_generator_spec.rb b/spec/dummy/spec/packs_generator_spec.rb index 2e3f21575..f345e6f9f 100644 --- a/spec/dummy/spec/packs_generator_spec.rb +++ b/spec/dummy/spec/packs_generator_spec.rb @@ -4,6 +4,8 @@ # rubocop:disable Metrics/ModuleLength module ReactOnRails + GENERATED_PACKS_CONSOLE_OUTPUT_TEXT = "Generated Packs:" + # rubocop:disable Metrics/BlockLength describe PacksGenerator do let(:webpacker_source_path) { File.expand_path("fixtures/automated_packs_generation", __dir__) } @@ -252,6 +254,45 @@ module ReactOnRails end end + context "when pack generator is called" do + let(:component_name) { "ComponentWithCommonOnly" } + let(:component_pack) { "#{generated_directory}/#{component_name}.js" } + + before do + stub_webpacker_source_path(component_name: component_name, + webpacker_source_path: webpacker_source_path) + end + + it "does not generate packs if there are no new components or stale files" do + expect { described_class.generate }.to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + + expect { described_class.generate }.not_to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + end + + it "generate packs if a new component is added" do + expect { described_class.generate }.to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + + create_new_component("NewComponent") + + expect { described_class.generate }.to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + end + + it "generate packs if an old component is updated" do + expect { described_class.generate }.to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + + create_new_component(component_name) + + expect { described_class.generate }.to output(GENERATED_PACKS_CONSOLE_OUTPUT_TEXT).to_stdout + end + + def create_new_component(name) + components_subdirectory = ReactOnRails.configuration.components_subdirectory + path = "#{webpacker_source_path}/components/#{component_name}/#{components_subdirectory}/#{name}.jsx" + + File.write(path, "// Empty Test Component\n") + end + end + def generated_server_bundle_file_path "#{webpacker_source_entry_path}/server-bundle-generated.js" end