react_on_rails 16.7.0.rc.1 → 16.7.0.rc.3

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: 6c1fa8759e37cddc05c49a9824d2914bd87a2cdbb12d174d48503604b30a6c58
4
- data.tar.gz: a61dd03cdd48c4d61f9a4df42ef329b44a80484e9078187e3f98765465d5ae87
3
+ metadata.gz: a330ac2b76a6a565ea1f64291f54d2ff5a90b39e33bb7c1929f3caa11ed8358e
4
+ data.tar.gz: 4d06374dfcb3c2004138c3386ed326634b03c91a27e96c4d442b0bcd5a9c39c9
5
5
  SHA512:
6
- metadata.gz: f482e32ce3d43fd9814535245f094c6652d1ca40e15449cb0acbba1ae0a551e52a3aab07846a95fce9316c4067e0c519114736995145baaf3dc99838eef39261
7
- data.tar.gz: 12e1670e1b1671ca36f3f4ffb426cdfb1a4a56b6a888da7d3100e6f327412a74a0714ea6a4f51e44c623c3e9941f70c742689dc47cdbd49fcf85f3d3f44ff49c
6
+ metadata.gz: 55392f01cd6ccad3792eac088c3f59d354131e159d22bc15dc086b17abc75ca248da294269d3e73ee25cea846af246e0d59ab2b93558ab0cf9bd9558e3ef52bf
7
+ data.tar.gz: c8fed4f8f74704860bff9a4784906ebcf5bab48cf7a50d9e7240a750d71c4d87dd228c55b3f0bad80edcc0c06565a20f606f8a2f1938ab8b3fa0108c52241bbf
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.7.0.rc.1)
4
+ react_on_rails (16.7.0.rc.3)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -201,6 +201,10 @@ GEM
201
201
  nokogiri (1.19.2)
202
202
  mini_portile2 (~> 2.8.2)
203
203
  racc (~> 1.4)
204
+ nokogiri (1.19.2-arm64-darwin)
205
+ racc (~> 1.4)
206
+ nokogiri (1.19.2-x86_64-linux-gnu)
207
+ racc (~> 1.4)
204
208
  ostruct (0.6.1)
205
209
  package_json (0.2.0)
206
210
  parallel (1.24.0)
@@ -377,6 +381,8 @@ GEM
377
381
  sprockets (>= 3.0.0)
378
382
  sqlite3 (1.7.3)
379
383
  mini_portile2 (~> 2.8.0)
384
+ sqlite3 (1.7.3-arm64-darwin)
385
+ sqlite3 (1.7.3-x86_64-linux)
380
386
  steep (1.9.4)
381
387
  activesupport (>= 5.1)
382
388
  concurrent-ruby (>= 1.1.10)
@@ -428,7 +434,9 @@ GEM
428
434
  zeitwerk (2.7.5)
429
435
 
430
436
  PLATFORMS
437
+ arm64-darwin
431
438
  ruby
439
+ x86_64-linux
432
440
 
433
441
  DEPENDENCIES
434
442
  amazing_print
@@ -84,12 +84,16 @@ module GeneratorHelper
84
84
  false
85
85
  end
86
86
 
87
- # Check if React on Rails Pro gem is installed
87
+ # Check if React on Rails Pro gem is installed (real state — never "scheduled to be installed").
88
88
  #
89
89
  # Detection priority:
90
90
  # 1. Gem.loaded_specs - gem is loaded in current Ruby process (most reliable)
91
91
  # 2. Gemfile.lock - gem is resolved and installed
92
92
  #
93
+ # Use {#pro_gem_install_deferred?} for the broader "present, or will be installed by this
94
+ # generator run" meaning. Use {#invalidate_pro_gem_installed_cache!} after an operation
95
+ # that changes real state (e.g., bundle add) so the next call re-reads the lockfile.
96
+ #
93
97
  # @return [Boolean] true if react_on_rails_pro gem is installed
94
98
  def pro_gem_installed?
95
99
  return @pro_gem_installed if defined?(@pro_gem_installed)
@@ -97,11 +101,6 @@ module GeneratorHelper
97
101
  @pro_gem_installed = Gem.loaded_specs.key?("react_on_rails_pro") || gem_in_lockfile?("react_on_rails_pro")
98
102
  end
99
103
 
100
- # TODO: CQS smell: mark_pro_gem_installed! makes pro_gem_installed? return true before install. See #3303.
101
- def mark_pro_gem_installed!
102
- @pro_gem_installed = true
103
- end
104
-
105
104
  # Check if Pro features should be enabled.
106
105
  # Returns true if --pro or --rsc is set (RSC implies Pro).
107
106
  #
@@ -252,6 +251,24 @@ module GeneratorHelper
252
251
 
253
252
  private
254
253
 
254
+ # Clear the memoized {#pro_gem_installed?} result so the next call re-checks
255
+ # Gem.loaded_specs / Gemfile.lock. Call after any operation that may change real state.
256
+ def invalidate_pro_gem_installed_cache!
257
+ remove_instance_variable(:@pro_gem_installed) if defined?(@pro_gem_installed)
258
+ end
259
+
260
+ # True when a later step in this generator run will install the Pro gem
261
+ # (e.g., the Gemfile swap performed by ProGenerator). Distinct from
262
+ # {#pro_gem_installed?}, which only reports real present state.
263
+ def pro_gem_install_deferred?
264
+ @pro_gem_install_deferred == true
265
+ end
266
+
267
+ # Record that a later step in this generator run will install the Pro gem.
268
+ def defer_pro_gem_install!
269
+ @pro_gem_install_deferred = true
270
+ end
271
+
255
272
  # NOTE: only the `default:` section is inspected — same assumption as
256
273
  # rspack_configured_in_project?. Projects that set `javascript_transpiler`
257
274
  # only in per-environment sections (without a `default:` block) will not be
@@ -138,11 +138,13 @@ module ReactOnRails
138
138
  # version because `pnpm/action-setup` requires one unless package.json declares
139
139
  # `packageManager`. Match the repo's own packageManager version so generated
140
140
  # CI defaults to the pnpm major this codebase tests with. Track the exact release
141
- # used for this fallback at https://github.com/pnpm/pnpm/releases/tag/v9.14.2;
141
+ # used for this fallback at https://github.com/pnpm/pnpm/releases/tag/v10.33.4;
142
142
  # update this URL with the constant when bumping. Users who need exact
143
143
  # reproducibility should commit `packageManager` to their package.json instead.
144
- # renovate: datasource=github-releases depName=pnpm/pnpm extractVersion=^v(?<version>.+)$
145
- CI_PNPM_FALLBACK_VERSION = "9.14.2"
144
+ # Bump checklist: heading text below is spec-asserted.
145
+ # CONTRIBUTING.md > "Updating the pnpm Fallback Version for Scaffolded CI".
146
+ # renovate: datasource=github-releases depName=pnpm/pnpm extractVersion=^v(?<version>.+)$ allowedVersions=<11
147
+ CI_PNPM_FALLBACK_VERSION = "10.33.4"
146
148
  private_constant :CI_PNPM_FALLBACK_VERSION
147
149
 
148
150
  # Main generator entry point
@@ -510,8 +510,10 @@ module ReactOnRails
510
510
  # @return [Boolean] true if successful, false otherwise
511
511
  def add_packages(packages, dev: false)
512
512
  return true if add_npm_dependencies(packages, dev: dev)
513
+ return true if install_packages_with_fallback(packages, dev: dev)
513
514
 
514
- install_packages_with_fallback(packages, dev: dev)
515
+ write_versioned_package_specs_to_package_json(packages, dev: dev)
516
+ false
515
517
  end
516
518
 
517
519
  def install_js_dependencies
@@ -559,6 +561,29 @@ module ReactOnRails
559
561
  false
560
562
  end
561
563
 
564
+ # Last-resort fallback for install failures. This rewrites package.json with
565
+ # JSON.pretty_generate so users can rerun their package manager manually.
566
+ def write_versioned_package_specs_to_package_json(packages, dev:)
567
+ return false unless File.exist?("package.json")
568
+
569
+ versioned_packages = packages.filter_map { |package_spec| package_name_and_version_from_spec(package_spec) }
570
+ return false if versioned_packages.empty?
571
+
572
+ content = JSON.parse(File.read("package.json"))
573
+ dependency_field = dev ? "devDependencies" : "dependencies"
574
+ content[dependency_field] ||= {}
575
+
576
+ versioned_packages.each do |package_name, package_version|
577
+ content[dependency_field][package_name] = package_version
578
+ end
579
+
580
+ File.write("package.json", "#{JSON.pretty_generate(content)}\n")
581
+ true
582
+ rescue StandardError => e
583
+ GeneratorMessages.add_warning("⚠️ Could not write dependency pins to package.json: #{e.message}")
584
+ false
585
+ end
586
+
562
587
  def fallback_package_manager
563
588
  package_manager = GeneratorMessages.detect_package_manager(app_root: destination_root)
564
589
  return package_manager if GeneratorMessages.supported_package_manager?(package_manager)
@@ -622,6 +647,13 @@ module ReactOnRails
622
647
  def version_specified?(package_spec, package_name)
623
648
  package_spec != package_name
624
649
  end
650
+
651
+ def package_name_and_version_from_spec(package_spec)
652
+ package_name = package_name_from_spec(package_spec)
653
+ return nil unless package_name && version_specified?(package_spec, package_name)
654
+
655
+ [package_name, package_spec.delete_prefix("#{package_name}@")]
656
+ end
625
657
  end
626
658
  end
627
659
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "generator_messages"
4
+ require "react_on_rails/node_renderer_procfile"
4
5
  require "react_on_rails/pro_migration"
5
6
 
6
7
  module ReactOnRails
@@ -19,7 +20,9 @@ module ReactOnRails
19
20
  #
20
21
  # Including classes must also include GeneratorHelper which provides:
21
22
  # - use_pro?, use_rsc?: Feature flag helpers
22
- # - pro_gem_installed?: Pro gem detection
23
+ # - pro_gem_installed?: Pro gem detection (real lockfile / loaded-specs state)
24
+ # - pro_gem_install_deferred?, defer_pro_gem_install!: deferred-install tracking
25
+ # - invalidate_pro_gem_installed_cache!: invalidate memoized pro_gem_installed?
23
26
  #
24
27
  # rubocop:disable Metrics/ModuleLength
25
28
  module ProSetup
@@ -45,7 +48,7 @@ module ReactOnRails
45
48
 
46
49
  create_pro_initializer
47
50
  legacy_renderer_detected = create_node_renderer
48
- add_pro_to_procfile unless legacy_renderer_detected
51
+ add_pro_to_procfiles unless legacy_renderer_detected
49
52
  update_webpack_config_for_pro
50
53
 
51
54
  say set_color("=" * 80, :cyan)
@@ -63,7 +66,7 @@ module ReactOnRails
63
66
  # is deferred to the Gemfile swap.
64
67
  def missing_pro_gem?(force: false)
65
68
  return false unless force || use_pro?
66
- return false if pro_gem_installed?
69
+ return false if pro_gem_installed? || pro_gem_install_deferred?
67
70
  return false if defer_pro_gem_install_to_gemfile_swap
68
71
  return false if attempt_pro_gem_auto_install
69
72
 
@@ -126,7 +129,8 @@ module ReactOnRails
126
129
 
127
130
  # The gem is now in Gemfile/lockfile but not loaded in the current Ruby process.
128
131
  # Generator code that follows must not reference ReactOnRailsPro constants directly.
129
- mark_pro_gem_installed!
132
+ # The lockfile changed, so the memoized pro_gem_installed? must be refreshed.
133
+ invalidate_pro_gem_installed_cache!
130
134
  true
131
135
  rescue StandardError => e
132
136
  say "⚠️ Failed to run bundle add: #{e.message}", :red
@@ -211,17 +215,43 @@ module ReactOnRails
211
215
  say "✅ Created #{initializer_path}", :green
212
216
  end
213
217
 
214
- # Matches active (uncommented) Procfile.dev node-renderer lines, tolerating
215
- # an optional `./` prefix that a user may have added by hand
216
- # (e.g. `node ./renderer/node-renderer.js`).
217
- NEW_RENDERER_COMMAND_REGEX = %r{^[ \t]*node-renderer:[^\n]*\bnode\s+\.?/?renderer/node-renderer\.js\b}
218
- LEGACY_RENDERER_COMMAND_REGEX = %r{^[ \t]*node-renderer:[^\n]*\bnode\s+\.?/?client/node-renderer\.js\b}
219
-
218
+ # Matches active (uncommented) Procfile.dev node-renderer lines that
219
+ # both set RENDERER_PORT and launch renderer/node-renderer.js (optionally
220
+ # prefixed with `./`). Entries missing RENDERER_PORT are intentionally
221
+ # not matched here so they fall through to NODE_RENDERER_PROCESS_REGEX
222
+ # and surface the "Update it manually" warning, keeping the generator's
223
+ # accept/skip decision aligned with the doctor's RENDERER_PORT check in
224
+ # NodeRendererProcfile::PROCESS_WITH_RENDERER_PORT_REGEX.
225
+ NEW_RENDERER_COMMAND_REGEX = %r{
226
+ ^[ \t]*(?:node-)?renderer:
227
+ (?=[^\n]*\bRENDERER_PORT\b)
228
+ [^\n]*\bnode\s+\.?/?renderer/node-renderer\.js\b
229
+ }x
230
+ LEGACY_RENDERER_COMMAND_REGEX = %r{^[ \t]*(?:node-)?renderer:[^\n]*\bnode\s+\.?/?client/node-renderer\.js\b}
231
+ # Detects an existing Node Renderer process entry. The dedicated
232
+ # `node-renderer:` label is reserved for the Pro Node Renderer, so any
233
+ # entry with that label is treated as the user's renderer regardless of
234
+ # the command (avoiding duplicate-label appends). A bare `renderer:`
235
+ # label could be anything (e.g. `renderer: vite ...`), so it only counts
236
+ # when the command actually launches a node-renderer — otherwise the
237
+ # generator would emit a misleading "update it manually" warning for an
238
+ # unrelated process.
239
+ NODE_RENDERER_PROCESS_REGEX = %r{
240
+ ^[ \t]*(?:
241
+ node-renderer:
242
+ |
243
+ renderer:[^\n]*(?:
244
+ \bnode\s+\.?/?(?:renderer|client)/node-renderer\.js\b
245
+ |
246
+ \b(?:pnpm|npm|yarn)\s+(?:run\s+)?node-renderer\b
247
+ )
248
+ )
249
+ }x
220
250
  # Creates renderer/node-renderer.js unless either the new path or the legacy
221
251
  # client/node-renderer.js already exists.
222
252
  #
223
253
  # @return [Boolean] true when a legacy client/node-renderer.js was detected
224
- # (caller should skip add_pro_to_procfile to avoid pointing Procfile.dev
254
+ # (caller should skip add_pro_to_procfiles to avoid pointing Procfile.dev
225
255
  # at a file that wasn't created); false otherwise.
226
256
  def create_node_renderer
227
257
  node_renderer_path = "renderer/node-renderer.js"
@@ -236,8 +266,7 @@ module ReactOnRails
236
266
  say "ℹ️ #{legacy_node_renderer_path} detected, keeping existing renderer; " \
237
267
  "to migrate, move it to #{node_renderer_path} and update any references " \
238
268
  "(e.g. Procfile.dev, Procfile.prod, Docker CMD / command):", :yellow
239
- say " node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=${RENDERER_PORT:-3800} " \
240
- "node #{node_renderer_path}", :yellow
269
+ say " #{node_renderer_procfile_command('Procfile.dev')}", :yellow
241
270
  warn_on_stale_legacy_procfile_entry
242
271
  return true
243
272
  end
@@ -253,34 +282,48 @@ module ReactOnRails
253
282
  false
254
283
  end
255
284
 
256
- # When a legacy client/node-renderer.js is detected, add_pro_to_procfile is
257
- # skipped, so surface a pointed warning if Procfile.dev still launches the
258
- # legacy entry. This nudges the user to update the exact line they need to
259
- # touch rather than leaving them to diff the generic migration hint against
260
- # their Procfile themselves.
285
+ # When a legacy client/node-renderer.js is detected, add_pro_to_procfiles is
286
+ # skipped, so surface a pointed warning for each Procfile that still
287
+ # launches the legacy entry. This nudges the user to update the exact
288
+ # line(s) they need to touch rather than leaving them to diff the generic
289
+ # migration hint against their Procfiles themselves.
261
290
  def warn_on_stale_legacy_procfile_entry
262
- procfile_path = File.join(destination_root, "Procfile.dev")
263
- return unless File.exist?(procfile_path)
291
+ ReactOnRails::NodeRendererProcfile::DEFAULT_COMMANDS.each_key do |procfile|
292
+ procfile_path = File.join(destination_root, procfile)
293
+ next unless File.exist?(procfile_path)
264
294
 
265
- procfile_content = File.read(procfile_path)
266
- return unless procfile_content.match?(LEGACY_RENDERER_COMMAND_REGEX)
295
+ procfile_content = File.read(procfile_path)
296
+ next unless procfile_content.match?(LEGACY_RENDERER_COMMAND_REGEX)
267
297
 
268
- GeneratorMessages.add_warning(<<~MSG.strip)
269
- ⚠️ Procfile.dev still launches the legacy client/node-renderer.js.
270
- After migrating the renderer file, update that line to:
271
- node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=${RENDERER_PORT:-3800} node renderer/node-renderer.js
272
- MSG
298
+ GeneratorMessages.add_warning(<<~MSG.strip)
299
+ ⚠️ #{procfile} still launches the legacy client/node-renderer.js.
300
+ After migrating the renderer file, update that line to:
301
+ #{node_renderer_procfile_command(procfile)}
302
+ MSG
303
+ end
273
304
  end
274
305
 
275
- def add_pro_to_procfile
276
- procfile_path = File.join(destination_root, "Procfile.dev")
306
+ def node_renderer_procfile_command(procfile)
307
+ ReactOnRails::NodeRendererProcfile.command_for(procfile)
308
+ end
309
+
310
+ def add_pro_to_procfiles
311
+ ReactOnRails::NodeRendererProcfile::DEFAULT_COMMANDS.each do |procfile, command|
312
+ add_node_renderer_to_procfile(procfile, command, warn_if_missing: procfile == "Procfile.dev")
313
+ end
314
+ end
315
+
316
+ def add_node_renderer_to_procfile(procfile, command, warn_if_missing:)
317
+ procfile_path = File.join(destination_root, procfile)
277
318
 
278
319
  unless File.exist?(procfile_path)
320
+ return unless warn_if_missing
321
+
279
322
  GeneratorMessages.add_warning(<<~MSG.strip)
280
- ⚠️ Procfile.dev not found. Skipping Node Renderer process addition.
323
+ ⚠️ #{procfile} not found. Skipping Node Renderer process addition.
281
324
 
282
325
  You'll need to add the Node Renderer to your process manager manually:
283
- node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=${RENDERER_PORT:-3800} node renderer/node-renderer.js
326
+ #{command}
284
327
  MSG
285
328
  return
286
329
  end
@@ -288,29 +331,28 @@ module ReactOnRails
288
331
  procfile_content = File.read(procfile_path)
289
332
 
290
333
  if procfile_content.match?(NEW_RENDERER_COMMAND_REGEX)
291
- say "ℹ️ Node Renderer already in Procfile.dev, skipping", :yellow
334
+ say "ℹ️ Node Renderer already in #{procfile}, skipping", :yellow
292
335
  return
293
336
  end
294
337
 
295
- if procfile_content.match?(/^[ \t]*node-renderer:/)
296
- say "⚠️ Procfile.dev has a node-renderer: entry that doesn't reference " \
338
+ if procfile_content.match?(NODE_RENDERER_PROCESS_REGEX)
339
+ say "⚠️ #{procfile} has a renderer entry that doesn't reference " \
297
340
  "renderer/node-renderer.js. Update it manually to:", :yellow
298
- say " node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=${RENDERER_PORT:-3800} " \
299
- "node renderer/node-renderer.js", :yellow
341
+ say " #{command}", :yellow
300
342
  return
301
343
  end
302
344
 
303
- say "📝 Adding Node Renderer to Procfile.dev...", :yellow
345
+ say "📝 Adding Node Renderer to #{procfile}...", :yellow
304
346
 
305
347
  node_renderer_line = <<~PROCFILE
306
348
 
307
349
  # React on Rails Pro - Node Renderer for SSR
308
- node-renderer: RENDERER_LOG_LEVEL=debug RENDERER_PORT=${RENDERER_PORT:-3800} node renderer/node-renderer.js
350
+ #{command}
309
351
  PROCFILE
310
352
 
311
- append_to_file("Procfile.dev", node_renderer_line)
353
+ append_to_file(procfile, node_renderer_line)
312
354
 
313
- say "✅ Added Node Renderer to Procfile.dev", :green
355
+ say "✅ Added Node Renderer to #{procfile}", :green
314
356
  end
315
357
 
316
358
  # Update webpack configs to enable Pro settings.
@@ -542,7 +584,7 @@ module ReactOnRails
542
584
  def defer_pro_gem_install_to_gemfile_swap
543
585
  return false unless base_react_on_rails_gem_in_gemfile?
544
586
 
545
- mark_pro_gem_installed!
587
+ defer_pro_gem_install!
546
588
  true
547
589
  end
548
590