react_on_rails 16.4.0.rc.10 → 16.4.0

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: cdd0253666ff913084d12f9f5b3f24b41f0f33ed418165f54a5d038cb567012d
4
- data.tar.gz: 510bcdc628f66dd6c9ddfae7be24582fef28ea35c263440e86a640b419bff379
3
+ metadata.gz: 2e8711eddc91f2c2afd343c203a466e320e3c98231a6cea82f950f91de9c234c
4
+ data.tar.gz: 3e833073ef81b6051e2484075288e7aca18026eafb9d7e1727a84a7ae53e22fc
5
5
  SHA512:
6
- metadata.gz: fa0ec02748d25524f70fa7fe73803fc25c8c73249a17b953517ab3b226fa2101efc0443b3bab201737711f91d4a4f4d9d280e29005c28b505ae3d2d6d4bda153
7
- data.tar.gz: 365c80cbf379d64e9c74958e96334fe494d2f9770f8fa0f1b01eae03f89e11fd08590459bbe3a021f6a4e3ff697a7ad78bcfa9fd93ac0646ada6007f6d471b8a
6
+ metadata.gz: fb4f879f38e2a7fce93204c22efaf2c360dc5031ad52384d7abe3cfcf0f712365dbfed53ae3385f93106d4d9549bb36a714caacb820d633d7c21a4864dce3c00
7
+ data.tar.gz: df85baa5aecb849d6b28636975540a2102ab0f70c1efdc3b00e26923dd4524f4bda758a6153eb541c8db86dfc8e6860830c6336785e50c1d5416d12486b2d5e7
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.4.0.rc.10)
4
+ react_on_rails (16.4.0)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -267,6 +267,7 @@ module ReactOnRails
267
267
 
268
268
  def copy_webpack_main_config(base_path, config)
269
269
  webpack_config_path = bundler_main_config_path
270
+ template_path = bundler_main_config_template_path(base_path, webpack_config_path)
270
271
 
271
272
  if File.exist?(webpack_config_path)
272
273
  existing_content = File.read(webpack_config_path)
@@ -279,7 +280,7 @@ module ReactOnRails
279
280
  say_status :replace,
280
281
  "#{webpack_config_path} (auto-upgrading from standard Shakapacker to React on Rails config)",
281
282
  :green
282
- template("#{base_path}/config/webpack/webpack.config.js.tt", webpack_config_path, config)
283
+ template(template_path, webpack_config_path, config)
283
284
  elsif react_on_rails_config?(existing_content)
284
285
  say_status :identical, "#{webpack_config_path} (already React on Rails compatible)", :blue
285
286
  # Skip - don't need to do anything
@@ -288,7 +289,7 @@ module ReactOnRails
288
289
  end
289
290
  else
290
291
  # File doesn't exist, create it
291
- template("#{base_path}/config/webpack/webpack.config.js.tt", webpack_config_path, config)
292
+ template(template_path, webpack_config_path, config)
292
293
  end
293
294
  end
294
295
 
@@ -309,7 +310,7 @@ module ReactOnRails
309
310
  say_status :create, "#{backup_path} (backup of your custom config)", :green
310
311
  end
311
312
 
312
- template("#{base_path}/config/webpack/webpack.config.js.tt", webpack_config_path, config)
313
+ template(bundler_main_config_template_path(base_path, webpack_config_path), webpack_config_path, config)
313
314
  else
314
315
  say_status :skip, webpack_config_path, :yellow
315
316
  say_status :warning,
@@ -320,7 +321,13 @@ module ReactOnRails
320
321
 
321
322
  def bundler_main_config_path
322
323
  if using_rspack?
323
- "config/rspack/rspack.config.js"
324
+ if File.exist?("config/rspack/rspack.config.ts")
325
+ "config/rspack/rspack.config.ts"
326
+ else
327
+ "config/rspack/rspack.config.js"
328
+ end
329
+ elsif File.exist?("config/webpack/webpack.config.ts")
330
+ "config/webpack/webpack.config.ts"
324
331
  else
325
332
  "config/webpack/webpack.config.js"
326
333
  end
@@ -584,10 +591,26 @@ module ReactOnRails
584
591
 
585
592
  # Normalize whitespace while preserving comments by default so added comments
586
593
  # count as potential customizations and keep cleanup conservative.
587
- normalized_content.gsub(/\s+/, " ").strip
594
+ normalized_content.gsub(/\s+/, " ")
595
+ .tr('"', "'") # Normalize quote style for import/require statements
596
+ .strip
597
+ end
598
+
599
+ def bundler_main_config_template_path(base_path, config_path)
600
+ template_ext = config_path.end_with?(".ts") ? "ts.tt" : "js.tt"
601
+ template_base = if config_path.include?("/rspack/") || File.basename(config_path).start_with?("rspack.config")
602
+ "rspack.config"
603
+ else
604
+ "webpack.config"
605
+ end
606
+ "#{base_path}/config/webpack/#{template_base}.#{template_ext}"
588
607
  end
589
608
 
590
609
  def shakapacker_default_configs
610
+ shakapacker_cjs_default_configs + shakapacker_esm_default_configs
611
+ end
612
+
613
+ def shakapacker_cjs_default_configs
591
614
  configs = []
592
615
 
593
616
  # Shakapacker v7+ (generateWebpackConfig function)
@@ -640,6 +663,40 @@ module ReactOnRails
640
663
  configs
641
664
  end
642
665
 
666
+ def shakapacker_esm_default_configs
667
+ configs = []
668
+
669
+ # Shakapacker v9.4+ TypeScript webpack configs (ESM syntax)
670
+ configs << <<~CONFIG
671
+ import { generateWebpackConfig } from 'shakapacker'
672
+ import type { Configuration } from 'webpack'
673
+ const webpackConfig: Configuration = generateWebpackConfig()
674
+ export default webpackConfig
675
+ CONFIG
676
+
677
+ configs << <<~CONFIG
678
+ import { generateWebpackConfig } from 'shakapacker'
679
+ const webpackConfig = generateWebpackConfig()
680
+ export default webpackConfig
681
+ CONFIG
682
+
683
+ # Shakapacker v9.4+ TypeScript rspack configs (ESM syntax)
684
+ configs << <<~CONFIG
685
+ import { generateRspackConfig } from 'shakapacker/rspack'
686
+ import type { RspackOptions } from '@rspack/core'
687
+ const rspackConfig: RspackOptions = generateRspackConfig()
688
+ export default rspackConfig
689
+ CONFIG
690
+
691
+ configs << <<~CONFIG
692
+ import { generateRspackConfig } from 'shakapacker/rspack'
693
+ const rspackConfig = generateRspackConfig()
694
+ export default rspackConfig
695
+ CONFIG
696
+
697
+ configs
698
+ end
699
+
643
700
  def react_on_rails_config?(content)
644
701
  # Check if it already has React on Rails environment-specific loading
645
702
  content.include?("envSpecificConfig") || content.include?("env.nodeEnv")
@@ -0,0 +1,15 @@
1
+ const { env } = require('shakapacker')
2
+ const { existsSync } = require('fs')
3
+ const { resolve } = require('path')
4
+
5
+ const envSpecificConfig = () => {
6
+ const path = resolve(__dirname, `${env.nodeEnv}.js`)
7
+ if (existsSync(path)) {
8
+ console.log(`Loading ENV specific rspack configuration file ${path}`)
9
+ return require(path)
10
+ } else {
11
+ throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
12
+ }
13
+ }
14
+
15
+ module.exports = envSpecificConfig()
@@ -0,0 +1,15 @@
1
+ import { env } from 'shakapacker'
2
+ import { existsSync } from 'fs'
3
+ import { resolve } from 'path'
4
+
5
+ const envSpecificConfig = () => {
6
+ const path = resolve(__dirname, `${env.nodeEnv}.js`)
7
+ if (existsSync(path)) {
8
+ console.log(`Loading ENV specific rspack configuration file ${path}`)
9
+ return require(path)
10
+ }
11
+
12
+ throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
13
+ }
14
+
15
+ export default envSpecificConfig()
@@ -0,0 +1,15 @@
1
+ import { env } from 'shakapacker'
2
+ import { existsSync } from 'fs'
3
+ import { resolve } from 'path'
4
+
5
+ const envSpecificConfig = () => {
6
+ const path = resolve(__dirname, `${env.nodeEnv}.js`)
7
+ if (existsSync(path)) {
8
+ console.log(`Loading ENV specific webpack configuration file ${path}`)
9
+ return require(path)
10
+ }
11
+
12
+ throw new Error(`Could not find file to load ${path}, based on NODE_ENV`)
13
+ }
14
+
15
+ export default envSpecificConfig()
@@ -134,7 +134,7 @@ module ReactOnRails
134
134
  • bin/shakapacker
135
135
  • bin/shakapacker-dev-server
136
136
  • config/shakapacker.yml
137
- • config/webpack/webpack.config.js
137
+ • config/{webpack,rspack}/{webpack,rspack}.config.{js,ts}
138
138
 
139
139
  Run: bundle exec rails shakapacker:install
140
140
  MSG
@@ -291,48 +291,80 @@ module ReactOnRails
291
291
 
292
292
  # Webpack configuration validation
293
293
  def check_webpack_configuration
294
- webpack_config_path = "config/webpack/webpack.config.js"
295
- if File.exist?(webpack_config_path)
296
- add_success("✅ Webpack configuration exists")
297
- check_webpack_config_content
298
- suggest_webpack_inspection
294
+ config_path = detect_bundler_config_path
295
+ if config_path
296
+ add_success("✅ Bundler configuration exists (#{config_path})")
297
+ check_webpack_config_content(config_path)
298
+ suggest_webpack_inspection(config_path)
299
299
  else
300
300
  add_error(<<~MSG.strip)
301
- 🚫 Webpack configuration not found.
301
+ 🚫 Bundler configuration not found.
302
302
 
303
- Expected: config/webpack/webpack.config.js
303
+ Expected one of: config/webpack/webpack.config.{js,ts} or config/rspack/rspack.config.{js,ts}
304
304
  Run: rails generate react_on_rails:install
305
305
  MSG
306
306
  end
307
307
  end
308
308
 
309
- def suggest_webpack_inspection
310
- add_info("💡 To debug webpack builds:")
309
+ def detect_bundler_config_path
310
+ paths_by_bundler = {
311
+ "rspack" => existing_bundler_config_paths("rspack"),
312
+ "webpack" => existing_bundler_config_paths("webpack")
313
+ }
314
+
315
+ present_paths = paths_by_bundler.select { |_bundler, paths| paths.any? }
316
+ return nil if present_paths.empty?
317
+ return present_paths.values.first.first if present_paths.one?
318
+
319
+ configured_bundler = configured_assets_bundler
320
+ if configured_bundler && paths_by_bundler[configured_bundler].any?
321
+ add_warning(
322
+ "⚠️ Found both webpack and rspack configs. Using #{configured_bundler} from config/shakapacker.yml."
323
+ )
324
+ return paths_by_bundler[configured_bundler].first
325
+ end
326
+
327
+ add_warning(
328
+ "⚠️ Found both webpack and rspack configs. Could not determine active bundler; defaulting to rspack."
329
+ )
330
+ paths_by_bundler["rspack"].first || paths_by_bundler["webpack"].first
331
+ end
332
+
333
+ def suggest_webpack_inspection(config_path)
334
+ bundler_name = config_path.include?("rspack") ? "rspack" : "webpack"
335
+ export_style = config_path.end_with?(".ts") ? "export default" : "module.exports"
336
+
337
+ add_info("💡 To debug #{bundler_name} builds:")
311
338
  add_info(" bin/shakapacker --mode=development --progress")
312
339
  add_info(" bin/shakapacker --mode=production --progress")
313
340
  add_info(" bin/shakapacker --debug-shakapacker # Debug Shakapacker configuration")
314
341
 
315
- add_info("💡 Advanced webpack debugging:")
316
- add_info(" 1. Add 'debugger;' before 'module.exports' in config/webpack/webpack.config.js")
342
+ add_info("💡 Advanced #{bundler_name} debugging:")
343
+ add_info(" 1. Add 'debugger;' before '#{export_style}' in #{config_path}")
317
344
  add_info(" 2. Run: ./bin/shakapacker --debug-shakapacker")
318
345
  add_info(" 3. Open Chrome DevTools to inspect config object")
319
- add_info(" 📖 See: https://github.com/shakacode/shakapacker/blob/main/docs/troubleshooting.md#debugging-your-webpack-config")
346
+ add_info(
347
+ " 📖 See: https://github.com/shakacode/shakapacker/blob/main/docs/troubleshooting.md#debugging-your-webpack-config"
348
+ )
320
349
 
321
350
  add_info("💡 To analyze bundle size:")
322
351
  if bundle_analyzer_available?
323
352
  add_info(" ANALYZE=true bin/shakapacker")
324
- add_info(" This opens webpack-bundle-analyzer in your browser")
325
- else
353
+ add_info(" This opens the configured bundle analyzer in your browser")
354
+ elsif bundler_name == "webpack"
326
355
  add_info(" 1. yarn add --dev webpack-bundle-analyzer")
327
- add_info(" 2. Add to config/webpack/webpack.config.js:")
356
+ add_info(" 2. Add to #{config_path}:")
328
357
  add_info(" const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');")
329
358
  add_info(" // Add to plugins array when process.env.ANALYZE")
330
359
  add_info(" 3. ANALYZE=true bin/shakapacker")
331
- add_info(" Or use Shakapacker's built-in support if available")
360
+ else
361
+ add_info(" 1. Install a compatible analyzer for your rspack setup")
362
+ add_info(" 2. Run: ANALYZE=true bin/shakapacker")
332
363
  end
333
364
 
334
- add_info("💡 Generate webpack stats for analysis:")
335
- add_info(" bin/shakapacker --json > webpack-stats.json")
365
+ stats_file = bundler_name == "rspack" ? "rspack-stats.json" : "webpack-stats.json"
366
+ add_info("💡 Generate #{bundler_name} stats for analysis:")
367
+ add_info(" bin/shakapacker --json > #{stats_file}")
336
368
  add_info(" Upload to webpack.github.io/analyse or webpack-bundle-analyzer.com")
337
369
  end
338
370
 
@@ -348,23 +380,23 @@ module ReactOnRails
348
380
  end
349
381
  end
350
382
 
351
- def check_webpack_config_content
352
- webpack_config_path = "config/webpack/webpack.config.js"
353
- content = File.read(webpack_config_path)
383
+ def check_webpack_config_content(config_path)
384
+ content = File.read(config_path)
385
+ bundler_name = config_path.include?("rspack") ? "rspack" : "webpack"
354
386
 
355
387
  if react_on_rails_config?(content)
356
- add_success("✅ Webpack config includes React on Rails environment configuration")
388
+ add_success("✅ #{bundler_name.capitalize} config includes React on Rails environment configuration")
357
389
  add_info(" ℹ️ Environment-specific configs detected for optimal React on Rails integration")
358
390
  elsif standard_shakapacker_config?(content)
359
391
  add_warning(<<~MSG.strip)
360
- ⚠️ Standard Shakapacker webpack config detected.
392
+ ⚠️ Standard Shakapacker #{bundler_name} config detected.
361
393
 
362
394
  React on Rails works better with environment-specific configuration.
363
395
  Consider running: rails generate react_on_rails:install --force
364
396
  This adds client and server environment configs for better performance.
365
397
  MSG
366
398
  else
367
- add_info("ℹ️ Custom webpack config detected")
399
+ add_info("ℹ️ Custom #{bundler_name} config detected")
368
400
  add_info(" 💡 Ensure config supports both client and server rendering")
369
401
  add_info(" 💡 Verify React JSX transformation is configured")
370
402
  add_info(" 💡 Check that asset output paths match Rails expectations")
@@ -427,7 +459,14 @@ module ReactOnRails
427
459
  File.exist?("bin/shakapacker") &&
428
460
  File.exist?("bin/shakapacker-dev-server") &&
429
461
  File.exist?("config/shakapacker.yml") &&
430
- File.exist?("config/webpack/webpack.config.js")
462
+ bundler_config_file_exists?
463
+ end
464
+
465
+ def bundler_config_file_exists?
466
+ File.exist?("config/webpack/webpack.config.js") ||
467
+ File.exist?("config/webpack/webpack.config.ts") ||
468
+ File.exist?("config/rspack/rspack.config.js") ||
469
+ File.exist?("config/rspack/rspack.config.ts")
431
470
  end
432
471
 
433
472
  def shakapacker_in_gemfile?
@@ -441,10 +480,18 @@ module ReactOnRails
441
480
  end
442
481
 
443
482
  def standard_shakapacker_config?(content)
483
+ # NOTE: Uses loose regex matching, unlike base_generator.rb's exact-string matching.
484
+ # Intentional: the system checker only needs to detect whether a config is
485
+ # "Shakapacker-flavored", not whether it's byte-for-byte identical to a default template.
444
486
  normalized = normalize_config_content(content)
445
487
  shakapacker_patterns = [
488
+ # CommonJS patterns (JS configs)
446
489
  /generateWebpackConfig.*require.*shakapacker/,
447
- /webpackConfig.*require.*shakapacker/
490
+ /webpackConfig.*require.*shakapacker/,
491
+ /generateRspackConfig.*require.*shakapacker/,
492
+ # ESM patterns (TS configs)
493
+ /generateWebpackConfig.*from ['"]shakapacker['"]/,
494
+ %r{generateRspackConfig.*from ['"]shakapacker/rspack['"]}
448
495
  ]
449
496
  shakapacker_patterns.any? { |pattern| normalized.match?(pattern) }
450
497
  end
@@ -456,6 +503,32 @@ module ReactOnRails
456
503
  .strip
457
504
  end
458
505
 
506
+ def existing_bundler_config_paths(bundler)
507
+ candidate_paths = if bundler == "rspack"
508
+ %w[
509
+ config/rspack/rspack.config.ts
510
+ config/rspack/rspack.config.js
511
+ ]
512
+ else
513
+ %w[
514
+ config/webpack/webpack.config.ts
515
+ config/webpack/webpack.config.js
516
+ ]
517
+ end
518
+ candidate_paths.select { |path| File.exist?(path) }
519
+ end
520
+
521
+ def configured_assets_bundler
522
+ shakapacker_config_path = "config/shakapacker.yml"
523
+ return nil unless File.exist?(shakapacker_config_path)
524
+
525
+ config_content = File.read(shakapacker_config_path)
526
+ match = config_content.match(/^\s*assets_bundler:\s*["']?(webpack|rspack)["']?\s*$/)
527
+ match&.captures&.first
528
+ rescue StandardError
529
+ nil
530
+ end
531
+
459
532
  def required_react_dependencies
460
533
  deps = {
461
534
  "react" => "React library",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ReactOnRails
4
- VERSION = "16.4.0.rc.10"
4
+ VERSION = "16.4.0"
5
5
  end
@@ -207,7 +207,7 @@ def cleanup_collapsed_prerelease_links(changelog, base_version)
207
207
  # Find the "from" version in prerelease links that points to a non-prerelease (stable) version
208
208
  stable_from = nil
209
209
  changelog.scan(/^\[#{prerelease_pattern}\]:\s*#{compare_prefix}(\S+)\.\.\./i) do |from_version,|
210
- stable_from = from_version unless from_version.match?(prerelease_pattern)
210
+ stable_from = from_version unless from_version.delete_prefix("v").match?(prerelease_pattern)
211
211
  end
212
212
 
213
213
  if stable_from
@@ -430,8 +430,8 @@ def update_changelog_links(changelog, version, anchor)
430
430
  return unless match_data
431
431
 
432
432
  prev_version = match_data[:prev_version]
433
- new_unreleased_link = "#{compare_link_prefix}/#{version}...master"
434
- new_version_link = "#{anchor}: #{compare_link_prefix}/#{prev_version}...#{version}"
433
+ new_unreleased_link = "#{compare_link_prefix}/v#{version}...master"
434
+ new_version_link = "#{anchor}: #{compare_link_prefix}/#{prev_version}...v#{version}"
435
435
  changelog.sub!(match_data[0], "#{new_unreleased_link}\n#{new_version_link}")
436
436
  end
437
437
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 16.4.0.rc.10
4
+ version: 16.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-16 00:00:00.000000000 Z
11
+ date: 2026-03-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable
@@ -168,9 +168,12 @@ files:
168
168
  - lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt
169
169
  - lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt
170
170
  - lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt
171
+ - lib/generators/react_on_rails/templates/base/base/config/webpack/rspack.config.js.tt
172
+ - lib/generators/react_on_rails/templates/base/base/config/webpack/rspack.config.ts.tt
171
173
  - lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt
172
174
  - lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt
173
175
  - lib/generators/react_on_rails/templates/base/base/config/webpack/webpack.config.js.tt
176
+ - lib/generators/react_on_rails/templates/base/base/config/webpack/webpack.config.ts.tt
174
177
  - lib/generators/react_on_rails/templates/dev_tests/.eslintrc
175
178
  - lib/generators/react_on_rails/templates/dev_tests/.rspec
176
179
  - lib/generators/react_on_rails/templates/dev_tests/spec/rails_helper.rb