react-manifest-rails 0.2.29 → 0.2.31

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8688e621b55d1a5b9db497668b4942fc97c8f4aad5f7778c7a7fc4a412990d04
4
- data.tar.gz: c46872893e465f9684c68688a8f8ca02d361afd7bfa8421eb1b69b0180f8c3d9
3
+ metadata.gz: fc0a4a583ea6c0b488c1fc9e4c0af46dec90e4ecdd6b93cd7eae48267ffdbfaa
4
+ data.tar.gz: 1a00e3b56139db55d5c473e22bc35cd43e2fc1dcb3ee50700602344c09d0c4db
5
5
  SHA512:
6
- metadata.gz: 76a4b4aed865531470d641be4bb0d6608d30410d66463aad17e71b37a73acafe2fb4a825c5f3f89c0bc5e6a91d7016396699572d575950dca71a242378cbc6f3
7
- data.tar.gz: 2bbd77ad7db859306d6cfdb6a75a476bfca219b1e22cf0b3aa54bd12f3c42d8a441c35a1e07dbb4e5a0c3c198b968683a15f814fd64bf59a55a91b1ca3d2b9d1
6
+ metadata.gz: b6db17954b9a91e080c0074ce203d322af67ba58d887be9ae4a1ada51add9fe3d36f7fc256b1587c274c2315c9324caa7576421c19740a6aeab40fa85f3f5606
7
+ data.tar.gz: 49dc6ae440709098ace838c583f492a516fa5abd0b1b332525cd3803ed3787ed656cd23871b53ad8cb91908a4c0d62e0f9d96b8394180fe950da8ee405068d6c
data/CHANGELOG.md CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.31] - 2026-07-01
11
+
12
+ ### Fixed
13
+ - Controller manifests no longer pull in an unrelated bundle's files just because a component name collides (e.g. a generic `Show` component defined in two different `ux/app/*` dirs). A bundle now always satisfies a symbol from its own files first, instead of attributing it to whichever bundle happened to define that name first.
14
+ - `react_component` no longer silently stops auto-injecting a component's bundle for the rest of the request after `react_bundle_tag` has rendered once. Previously, calling `react_component` for a component in an unrelated bundle (not the current controller's own bundle, e.g. from a haml/erb view mixing controller-based and component-based rendering) would render with no script tag at all if `react_bundle_tag` had already run earlier in the same request.
15
+
16
+ ### Removed
17
+ - The gem version is no longer embedded in the `AUTO-GENERATED` manifest header. Previously every manifest's content digest changed on every gem upgrade, forcing a full regeneration of all `ux_*.js` files for no functional reason.
18
+
10
19
  ## [0.2.28] - 2026-05-11
11
20
 
12
21
  ### Fixed
@@ -30,7 +30,6 @@ module ReactManifest
30
30
 
31
31
  HEADER = <<~JS.freeze
32
32
  // AUTO-GENERATED — DO NOT EDIT
33
- // react-manifest-rails %<version>s
34
33
  // Run `rails react_manifest:generate` to regenerate.
35
34
  JS
36
35
 
@@ -130,6 +129,7 @@ module ReactManifest
130
129
  def build_controller_context(controller_dirs)
131
130
  bundle_files = {}
132
131
  symbol_to_bundle = {}
132
+ bundle_own_symbols = Hash.new { |h, k| h[k] = Set.new }
133
133
  external_symbol_to_require = {}
134
134
  dependencies = Hash.new { |h, k| h[k] = Set.new }
135
135
  external_requires = Hash.new { |h, k| h[k] = Set.new }
@@ -145,6 +145,7 @@ module ReactManifest
145
145
  next unless sym.match?(/\A[A-Z][A-Za-z0-9_]*\z/)
146
146
 
147
147
  symbol_to_bundle[sym] ||= bundle_name
148
+ bundle_own_symbols[bundle_name] << sym
148
149
  end
149
150
  end
150
151
  end
@@ -170,8 +171,16 @@ module ReactManifest
170
171
 
171
172
  # Compute per-bundle cross-app and external dependencies
172
173
  bundle_files.each do |bundle_name, files|
174
+ own_symbols = bundle_own_symbols[bundle_name]
175
+
173
176
  files.each do |file_path|
174
177
  extract_used_component_symbols(file_path).each do |sym|
178
+ # A symbol the bundle defines itself (in any of its own files) is
179
+ # always satisfied locally — never attribute it to another bundle
180
+ # or an external provider just because that symbol name happens
181
+ # to collide with something defined elsewhere.
182
+ next if own_symbols.include?(sym)
183
+
175
184
  dep_bundle = symbol_to_bundle[sym]
176
185
  dependencies[bundle_name] << dep_bundle if dep_bundle && dep_bundle != bundle_name
177
186
 
@@ -316,10 +325,7 @@ module ReactManifest
316
325
  # ----------------------------------------------------------- helpers
317
326
 
318
327
  def header_lines
319
- [
320
- format(HEADER, version: ReactManifest::VERSION),
321
- ""
322
- ].flatten
328
+ [HEADER, ""]
323
329
  end
324
330
 
325
331
  def js_files_in(dir)
@@ -8,7 +8,7 @@ module ReactManifest
8
8
 
9
9
  def log_info(message)
10
10
  full = "[ReactManifest] #{message}"
11
- Rails.logger.info(full)
11
+ Rails.logger.debug(full)
12
12
  $stdout.puts(full) if stdout_logging_needed?
13
13
  end
14
14
 
@@ -9,6 +9,7 @@ module ReactManifest
9
9
  # ----------------------------------------------------------------
10
10
  initializer "react_manifest.ensure_manifests", after: :load_config_initializers do
11
11
  next unless Rails.env.development?
12
+ next if defined?(Rails::Console)
12
13
 
13
14
  config = ReactManifest.configuration
14
15
 
@@ -60,6 +61,8 @@ module ReactManifest
60
61
  # Start the file watcher in development
61
62
  # ----------------------------------------------------------------
62
63
  initializer "react_manifest.start_watcher" do
64
+ next if defined?(Rails::Console)
65
+
63
66
  if Rails.env.development? && !ReactManifest::Watcher.running?
64
67
  begin
65
68
  ReactManifest::Watcher.start(ReactManifest.configuration)
@@ -1,3 +1,3 @@
1
1
  module ReactManifest
2
- VERSION = "0.2.29".freeze
2
+ VERSION = "0.2.31".freeze
3
3
  end
@@ -26,7 +26,6 @@ module ReactManifest
26
26
  return "".html_safe if fresh_bundles.empty?
27
27
 
28
28
  fresh_bundles.each { |b| emitted << b }
29
- mark_bundle_tag_rendered
30
29
 
31
30
  asset_names = fresh_bundles.map { |bundle| "#{bundle}.js" }
32
31
  javascript_include_tag(*asset_names, extname: false, **html_options)
@@ -38,7 +37,6 @@ module ReactManifest
38
37
  # This avoids strict dependence on controller_path -> bundle naming alignment.
39
38
  def react_component(*args, **kwargs, &block)
40
39
  html = super
41
- return html if bundle_tag_rendered?
42
40
 
43
41
  component_name = args.first
44
42
  bundles = ReactManifest.resolve_bundles_for_component_direct(component_name)
@@ -78,17 +76,5 @@ module ReactManifest
78
76
  @emitted_bundles ||= []
79
77
  end
80
78
  end
81
-
82
- def mark_bundle_tag_rendered
83
- return unless respond_to?(:request, true) && request
84
-
85
- request.env["react_manifest.bundle_tag_rendered"] = true
86
- end
87
-
88
- def bundle_tag_rendered?
89
- return false unless respond_to?(:request, true) && request
90
-
91
- request.env["react_manifest.bundle_tag_rendered"] == true
92
- end
93
79
  end
94
80
  end
@@ -14,6 +14,7 @@ module ReactManifest
14
14
  # additional regeneration is queued (not one per file event).
15
15
  module Watcher
16
16
  DEBOUNCE_SECONDS = 0.3
17
+ BRANCH_SWITCH_COOLDOWN = 3
17
18
 
18
19
  class << self
19
20
  include ReactManifest::Logging
@@ -35,6 +36,9 @@ module ReactManifest
35
36
  end
36
37
 
37
38
  @regen_mutex = Mutex.new
39
+ @git_dir = detect_git_dir
40
+ @last_git_head = read_git_head
41
+ @branch_switch_until = nil
38
42
 
39
43
  log_info "Watching #{root.sub("#{Rails.root}/", '')} for changes..."
40
44
 
@@ -73,15 +77,61 @@ module ReactManifest
73
77
  @regen_thread = nil
74
78
  @regen_pending = false
75
79
  @regen_mutex = nil
80
+ @git_dir = nil
81
+ @last_git_head = nil
82
+ @branch_switch_until = nil
76
83
  end
77
84
 
78
85
  private
79
86
 
80
87
  def handle_file_changes(modified, added, removed, config)
88
+ if branch_switch_detected?
89
+ log_info "Branch change detected — skipping regeneration"
90
+ return
91
+ end
92
+
81
93
  (modified + added + removed).each { |f| Scanner.invalidate(f) }
82
94
  schedule_regeneration(config)
83
95
  end
84
96
 
97
+ def branch_switch_detected?
98
+ return false unless @git_dir
99
+
100
+ return true if @branch_switch_until && Time.now < @branch_switch_until
101
+
102
+ current_head = read_git_head
103
+ return false unless current_head && @last_git_head
104
+
105
+ if current_head != @last_git_head
106
+ @last_git_head = current_head
107
+ @branch_switch_until = Time.now + BRANCH_SWITCH_COOLDOWN
108
+ return true
109
+ end
110
+
111
+ false
112
+ end
113
+
114
+ def detect_git_dir
115
+ git_path = File.join(Rails.root.to_s, ".git")
116
+ if File.file?(git_path)
117
+ content = File.read(git_path).strip
118
+ return content.sub("gitdir: ", "").strip if content.start_with?("gitdir: ")
119
+ elsif File.directory?(git_path)
120
+ return git_path
121
+ end
122
+ nil
123
+ rescue StandardError
124
+ nil
125
+ end
126
+
127
+ def read_git_head
128
+ return nil unless @git_dir
129
+
130
+ File.read(File.join(@git_dir, "HEAD")).strip
131
+ rescue StandardError
132
+ nil
133
+ end
134
+
85
135
  # Schedule a regeneration on the background thread. Coalesces rapid
86
136
  # back-to-back file events: if the regen thread is already running,
87
137
  # we just set @regen_pending and return immediately so the listen
@@ -146,6 +146,7 @@ module ReactManifest
146
146
 
147
147
  controller_dirs = TreeClassifier.new(config).classify.controller_dirs
148
148
  symbol_to_bundle = {}
149
+ bundle_own_symbols = Hash.new { |h, k| h[k] = Set.new }
149
150
  bundle_files = Hash.new { |h, k| h[k] = [] }
150
151
  bundle_dependencies = Hash.new { |h, k| h[k] = Set.new }
151
152
 
@@ -160,13 +161,21 @@ module ReactManifest
160
161
 
161
162
  # Keep first writer to ensure deterministic behavior if a symbol is duplicated.
162
163
  symbol_to_bundle[symbol] ||= bundle_name
164
+ bundle_own_symbols[bundle_name] << symbol
163
165
  end
164
166
  end
165
167
  end
166
168
 
167
169
  bundle_files.each do |bundle_name, files|
170
+ own_symbols = bundle_own_symbols[bundle_name]
171
+
168
172
  files.each do |file_path|
169
173
  extract_used_component_symbols(file_path).each do |symbol|
174
+ # A symbol the bundle defines itself is always satisfied locally —
175
+ # never attribute it to another bundle just because that symbol
176
+ # name happens to collide with something defined elsewhere.
177
+ next if own_symbols.include?(symbol)
178
+
170
179
  dep_bundle = symbol_to_bundle[symbol]
171
180
  next unless dep_bundle && dep_bundle != bundle_name
172
181
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react-manifest-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.29
4
+ version: 0.2.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oliver Noonan
@@ -160,7 +160,7 @@ licenses:
160
160
  metadata:
161
161
  homepage_uri: https://github.com/olivernoonan/react-manifest-rails
162
162
  source_code_uri: https://github.com/olivernoonan/react-manifest-rails
163
- changelog_uri: https://github.com/olivernoonan/react-manifest-rails/blob/main/CHANGELOG.md
163
+ changelog_uri: https://github.com/olivernoonan/react-manifest-rails/blob/master/CHANGELOG.md
164
164
  bug_tracker_uri: https://github.com/olivernoonan/react-manifest-rails/issues
165
165
  rubygems_mfa_required: 'true'
166
166
  rdoc_options: []