react_on_rails 16.5.1 → 16.6.0.rc.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -3
  3. data/lib/generators/react_on_rails/base_generator.rb +426 -8
  4. data/lib/generators/react_on_rails/demo_page_config.rb +225 -0
  5. data/lib/generators/react_on_rails/generator_helper.rb +38 -14
  6. data/lib/generators/react_on_rails/generator_messages.rb +24 -6
  7. data/lib/generators/react_on_rails/install_generator.rb +179 -19
  8. data/lib/generators/react_on_rails/js_dependency_manager.rb +134 -38
  9. data/lib/generators/react_on_rails/pro_generator.rb +776 -0
  10. data/lib/generators/react_on_rails/pro_setup.rb +40 -8
  11. data/lib/generators/react_on_rails/react_no_redux_generator.rb +15 -4
  12. data/lib/generators/react_on_rails/react_with_redux_generator.rb +20 -4
  13. data/lib/generators/react_on_rails/rsc_generator.rb +10 -0
  14. data/lib/generators/react_on_rails/rsc_setup.rb +11 -3
  15. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +1 -1
  16. data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static-assets +1 -1
  17. data/lib/generators/react_on_rails/templates/base/base/app/controllers/home_controller.rb +7 -0
  18. data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +200 -2
  19. data/lib/generators/react_on_rails/templates/base/base/app/views/home/index.html.erb.tt +422 -0
  20. data/lib/generators/react_on_rails/templates/base/base/bin/dev +8 -0
  21. data/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-watch +26 -0
  22. data/lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb +2 -2
  23. data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb.tt +200 -0
  24. data/lib/react_on_rails/config_path_resolver.rb +63 -13
  25. data/lib/react_on_rails/configuration.rb +4 -2
  26. data/lib/react_on_rails/dev/process_manager.rb +3 -0
  27. data/lib/react_on_rails/dev/server_manager.rb +275 -47
  28. data/lib/react_on_rails/doctor.rb +343 -123
  29. data/lib/react_on_rails/system_checker.rb +97 -41
  30. data/lib/react_on_rails/version.rb +1 -1
  31. metadata +7 -3
  32. data/lib/generators/react_on_rails/templates/rsc/base/app/views/hello_server/index.html.erb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4952f875c502a91d85699aee567b2f7f682ef818faf8bc3eb584a20b8cbd617
4
- data.tar.gz: 40d9fb9a20e26322a2a67a3da1815f36ad75bfd018e8db84f37fb34d318f9d00
3
+ metadata.gz: 2294c0aab02fdb0995b81b139099a0585b25ee39ebe903d6238e91a40e2a0341
4
+ data.tar.gz: 76c6b154c56c639566069a5840496e4ba142b6130429f38ab7580f6bb33bbc29
5
5
  SHA512:
6
- metadata.gz: 0fc060fcfab135a7f237f44b640a56ac220c18e69ceeeaae107159085855ead5edfc116f207a539decf605006ad4162f59a0f9191602a666de92e7ab1c9dd11a
7
- data.tar.gz: d64e7656d3a0ddc657495b36c71cda152e7159aacfc9edbd1a5e10a22c149292498849d44443031b1c4fff49d55cc2fbaa81d853c43115136a6c6250323f2a42
6
+ metadata.gz: 0521bd2c98262935f0f7bac35e779aec25a6cb8a8039906141ab7e560d27deade2c3b1601d389d4e362ead52ed64b4be0e851ae22a07cb61e15948407e925a69
7
+ data.tar.gz: bd80ca64b259c5e303111d7f46aeaa2b1e1bcda60af3fcc1873db9e51b39db2bf42bb4f846b9678ea9b8d6b5d4dac0b70183ce6fa30b7953ad2d0a65ee6d7dc4
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- react_on_rails (16.5.1)
4
+ react_on_rails (16.6.0.rc.0)
5
5
  addressable
6
6
  connection_pool
7
7
  execjs (~> 2.5)
@@ -175,7 +175,7 @@ GEM
175
175
  rb-fsevent (~> 0.10, >= 0.10.3)
176
176
  rb-inotify (~> 0.9, >= 0.9.10)
177
177
  logger (1.7.0)
178
- loofah (2.25.0)
178
+ loofah (2.25.1)
179
179
  crass (~> 1.0.2)
180
180
  nokogiri (>= 1.12.0)
181
181
  mail (2.9.0)
@@ -204,7 +204,7 @@ GEM
204
204
  net-smtp (0.5.1)
205
205
  net-protocol
206
206
  nio4r (2.7.5)
207
- nokogiri (1.19.1)
207
+ nokogiri (1.19.2)
208
208
  mini_portile2 (~> 2.8.2)
209
209
  racc (~> 1.4)
210
210
  ostruct (0.6.1)
@@ -48,6 +48,13 @@ module ReactOnRails
48
48
  default: false,
49
49
  hide: true
50
50
 
51
+ # Hidden option: used by create-react-on-rails-app so fresh apps get a
52
+ # generated home page without changing existing-app installs.
53
+ class_option :new_app,
54
+ type: :boolean,
55
+ default: false,
56
+ hide: true
57
+
51
58
  # Keep this map in sync with templates under:
52
59
  # lib/generators/react_on_rails/templates/**/config/webpack/*.tt
53
60
  MANAGED_WEBPACK_FILE_TEMPLATES = {
@@ -98,6 +105,51 @@ module ReactOnRails
98
105
  private_constant :MANAGED_WEBPACK_FILE_TEMPLATES, :REMOVABLE_WEBPACK_FILES, :TemplateRenderContext,
99
106
  :DOCS_REFERENCE_MESSAGE, :TEMPLATE_RENDER_FAILED
100
107
 
108
+ def add_root_route
109
+ return unless options.new_app?
110
+ # add_root_route normally runs before copy_base_files as a generator action.
111
+ # Guard against accidental double invocation (for example, if future
112
+ # refactors trigger lazy initialization in generate_new_app_home_page?).
113
+ return if defined?(@new_app_root_route_added)
114
+
115
+ @new_app_root_route_added = false
116
+
117
+ if preexisting_root_route?
118
+ say_status :skip, "Root route already exists; keeping existing root route", :yellow
119
+ return
120
+ end
121
+
122
+ routes_path = "config/routes.rb"
123
+ routes_full_path = File.join(destination_root, routes_path)
124
+
125
+ unless File.file?(routes_full_path)
126
+ say_status :warn, "Could not inject root route; config/routes.rb was not found", :yellow
127
+ return
128
+ end
129
+
130
+ # Support both LF and CRLF route files so new-app onboarding works on Windows checkouts too.
131
+ routes_draw_declaration = /^\s*Rails\.application\.routes\.draw do\r?\n/
132
+ unless File.read(routes_full_path).match?(routes_draw_declaration)
133
+ say_status :warn, "Could not inject root route; config/routes.rb format was unexpected", :yellow
134
+ return
135
+ end
136
+
137
+ inject_into_file routes_path,
138
+ %( root to: "home#index"\n),
139
+ after: routes_draw_declaration
140
+ if options[:pretend]
141
+ @new_app_root_route_added = true
142
+ return
143
+ end
144
+
145
+ if File.read(routes_full_path).include?('root to: "home#index"')
146
+ @new_app_root_route_added = true
147
+ return
148
+ end
149
+
150
+ say_status :warn, "Could not inject root route; config/routes.rb format was unexpected", :yellow
151
+ end
152
+
101
153
  def add_hello_world_route
102
154
  # RSC uses HelloServer instead of HelloWorld, but Redux still needs hello_world route
103
155
  return if use_rsc? && !options.redux?
@@ -113,6 +165,8 @@ module ReactOnRails
113
165
  end
114
166
 
115
167
  def copy_base_files
168
+ ensure_new_app_root_route_initialized
169
+
116
170
  base_path = "base/base/"
117
171
  base_files = %w[Procfile.dev
118
172
  Procfile.dev-static-assets
@@ -128,12 +182,18 @@ module ReactOnRails
128
182
  # HelloWorld controller only when not using RSC (RSC uses HelloServer)
129
183
  # Exception: Redux still needs the HelloWorld controller even with RSC
130
184
  base_files << "app/controllers/hello_world_controller.rb" unless use_rsc? && !options.redux?
185
+ base_files << "app/controllers/home_controller.rb" if generate_new_app_home_page?
131
186
  base_templates = %w[config/initializers/react_on_rails.rb]
132
187
  base_files.each { |file| copy_file("#{base_path}#{file}", file) }
133
188
  base_templates.each do |file|
134
189
  template("#{base_path}/#{file}.tt", file)
135
190
  end
136
191
 
192
+ if generate_new_app_home_page?
193
+ empty_directory("app/views/home")
194
+ template("#{base_path}/app/views/home/index.html.erb.tt", "app/views/home/index.html.erb", home_page_config)
195
+ end
196
+
137
197
  # Make the hook script executable (copy_file guarantees it exists)
138
198
  if options[:pretend]
139
199
  say_status :pretend, "Skipping chmod on shakapacker-precompile-hook in --pretend mode", :yellow
@@ -237,13 +297,11 @@ module ReactOnRails
237
297
  end
238
298
 
239
299
  CONFIGURE_RSPEC_TO_COMPILE_ASSETS = <<~STR
240
- RSpec.configure do |config|
241
- # Ensure that if we are running js tests, we are using latest webpack assets
242
- # This will use the defaults of :js and :server_rendering meta tags
243
- # Requires config.build_test_command in config/initializers/react_on_rails.rb.
244
- # This is the default setup for React on Rails generated apps.
245
- ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
246
- end
300
+ # Ensure that if we are running js tests, we are using latest webpack assets
301
+ # This will use the defaults of :js and :server_rendering meta tags
302
+ # Requires config.build_test_command in config/initializers/react_on_rails.rb.
303
+ # This is the default setup for React on Rails generated apps.
304
+ ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
247
305
  STR
248
306
 
249
307
  CONFIGURE_MINITEST_TO_COMPILE_ASSETS = <<~STR
@@ -255,6 +313,362 @@ module ReactOnRails
255
313
 
256
314
  private
257
315
 
316
+ def generate_new_app_home_page?
317
+ options.new_app? && new_app_root_route_added?
318
+ end
319
+
320
+ def new_app_root_route_added?
321
+ return false unless options.new_app?
322
+ return @new_app_root_route_added if defined?(@new_app_root_route_added)
323
+
324
+ false
325
+ end
326
+
327
+ def preexisting_root_route?
328
+ return @preexisting_root_route if defined?(@preexisting_root_route)
329
+
330
+ @preexisting_root_route = root_route_present?
331
+ end
332
+
333
+ def ensure_new_app_root_route_initialized
334
+ return unless options.new_app?
335
+ return if defined?(@new_app_root_route_added)
336
+
337
+ # add_root_route should run as a generator action first, but keep this
338
+ # explicit call so copy_base_files remains safe if action ordering changes.
339
+ add_root_route
340
+ end
341
+
342
+ def home_page_config
343
+ docs_url = if use_rsc?
344
+ "https://reactonrails.com/docs/pro/react-server-components/"
345
+ else
346
+ "https://reactonrails.com/docs/"
347
+ end
348
+
349
+ {
350
+ app_name: app_name,
351
+ docs_url: docs_url,
352
+ examples: home_page_examples,
353
+ file_hints: home_page_file_hints,
354
+ stack_badges: home_page_stack_badges,
355
+ learning_links: home_page_learning_links,
356
+ pro_cta: home_page_pro_cta,
357
+ pro_section: home_page_pro_section,
358
+ rendering_paths: home_page_rendering_paths
359
+ }
360
+ end
361
+
362
+ def home_page_examples
363
+ examples = []
364
+
365
+ if use_rsc?
366
+ examples << {
367
+ label: "Open RSC demo",
368
+ title: "HelloServer",
369
+ path: "/hello_server",
370
+ badge: "RSC",
371
+ description: "Async React Server Components streamed from Rails " \
372
+ "with only client islands shipping JavaScript."
373
+ }
374
+ end
375
+
376
+ unless use_rsc? && !options.redux?
377
+ example_description = if options.redux?
378
+ "Redux-backed server rendering with hydration."
379
+ else
380
+ "Server-rendered React with hydration and hot reloading."
381
+ end
382
+
383
+ examples << {
384
+ label: "Open SSR demo",
385
+ title: options.redux? ? "HelloWorldApp" : "HelloWorld",
386
+ path: "/hello_world",
387
+ badge: "SSR",
388
+ description: example_description
389
+ }
390
+ end
391
+
392
+ examples
393
+ end
394
+
395
+ def home_page_file_hints
396
+ hints = [
397
+ {
398
+ path: "app/views/home/index.html.erb",
399
+ description: "Generated landing page. Replace this once your product has a real root route."
400
+ },
401
+ {
402
+ path: example_source_path,
403
+ description: "React source for the generated example components."
404
+ },
405
+ {
406
+ path: example_view_path,
407
+ description: "Rails view that mounts the generated example."
408
+ },
409
+ {
410
+ path: using_rspack? ? "config/rspack/" : "config/webpack/",
411
+ description: "Bundler configuration generated for this app."
412
+ },
413
+ {
414
+ path: "bin/dev",
415
+ description: "Launch Rails and the asset watcher together from one command."
416
+ }
417
+ ]
418
+
419
+ if use_pro?
420
+ hints << {
421
+ path: "client/node-renderer.js",
422
+ description: "Node renderer entrypoint used for Pro SSR and RSC."
423
+ }
424
+ end
425
+
426
+ hints
427
+ end
428
+
429
+ def home_page_learning_links
430
+ links = [
431
+ {
432
+ title: "Documentation guide",
433
+ url: "https://reactonrails.com/docs/",
434
+ description: "Core install, generator, and API docs for the OSS stack."
435
+ },
436
+ {
437
+ title: "Compare OSS and Pro",
438
+ url: "https://reactonrails.com/docs/getting-started/oss-vs-pro/",
439
+ description: "See which capabilities stay in OSS and which move into the Pro track."
440
+ },
441
+ {
442
+ title: "Pro quick start",
443
+ url: "https://reactonrails.com/docs/getting-started/pro-quick-start/",
444
+ description: "Add the Pro gem and package changes when you are ready for the upgrade."
445
+ },
446
+ {
447
+ title: "Marketplace RSC demo",
448
+ url: "https://github.com/shakacode/react-server-components-marketplace-demo",
449
+ description: "Study a larger app comparing traditional SSR, client boundaries, and streamed RSC."
450
+ }
451
+ ]
452
+
453
+ return links unless use_rsc?
454
+
455
+ [
456
+ {
457
+ title: "React Server Components guide",
458
+ url: "https://reactonrails.com/docs/pro/react-server-components/",
459
+ description: "Read the architecture, rendering flow, and migration guidance for the Pro RSC stack."
460
+ },
461
+ {
462
+ title: "RSC tutorial",
463
+ url: "https://reactonrails.com/docs/pro/react-server-components/tutorial/",
464
+ description: "Walk through the generated HelloServer example end to end."
465
+ }
466
+ ] + links
467
+ end
468
+
469
+ def home_page_pro_cta
470
+ if use_rsc?
471
+ {
472
+ label: "RSC tutorial",
473
+ url: "https://reactonrails.com/docs/pro/react-server-components/tutorial/"
474
+ }
475
+ elsif use_pro?
476
+ {
477
+ label: "See Pro docs",
478
+ url: "https://reactonrails.com/pro/"
479
+ }
480
+ else
481
+ {
482
+ label: "Compare OSS and Pro",
483
+ url: "https://reactonrails.com/docs/getting-started/oss-vs-pro/"
484
+ }
485
+ end
486
+ end
487
+
488
+ def home_page_pro_section
489
+ {
490
+ eyebrow: use_pro? ? "Included in this app" : "Worth evaluating next",
491
+ title: use_pro? ? "React on Rails Pro is already wired in" : "Why teams move from OSS to Pro",
492
+ description: use_pro? ? home_page_pro_description_for_enabled_app : home_page_pro_description_for_oss_app,
493
+ note: use_pro? ? home_page_pro_note_for_enabled_app : home_page_pro_note_for_oss_app,
494
+ features: home_page_pro_features,
495
+ links: home_page_pro_links
496
+ }
497
+ end
498
+
499
+ def home_page_pro_features
500
+ [
501
+ {
502
+ title: "React Server Components",
503
+ description: "Stream async server components from Rails and keep JavaScript on the client " \
504
+ "only where it adds value."
505
+ },
506
+ {
507
+ title: "Node renderer",
508
+ description: "Use a Node-based rendering path when you need higher-throughput SSR or " \
509
+ "richer runtime support."
510
+ },
511
+ {
512
+ title: "Upgrade path",
513
+ description: "Compare OSS and Pro, follow the quick start, and study the marketplace " \
514
+ "demo before rolling changes into a real app."
515
+ }
516
+ ]
517
+ end
518
+
519
+ def home_page_pro_links
520
+ links = [
521
+ {
522
+ label: "React on Rails Pro",
523
+ url: "https://reactonrails.com/pro/"
524
+ },
525
+ {
526
+ label: "Marketplace demo",
527
+ url: "https://github.com/shakacode/react-server-components-marketplace-demo"
528
+ }
529
+ ]
530
+
531
+ if use_rsc?
532
+ links.unshift(
533
+ {
534
+ label: "RSC guide",
535
+ url: "https://reactonrails.com/docs/pro/react-server-components/"
536
+ }
537
+ )
538
+ else
539
+ links.unshift(
540
+ {
541
+ label: "OSS vs Pro",
542
+ url: "https://reactonrails.com/docs/getting-started/oss-vs-pro/"
543
+ }
544
+ )
545
+ end
546
+
547
+ links
548
+ end
549
+
550
+ def home_page_rendering_paths
551
+ [
552
+ home_page_ssr_path,
553
+ home_page_rsc_path,
554
+ home_page_compare_path
555
+ ]
556
+ end
557
+
558
+ def home_page_ssr_path
559
+ if use_rsc? && !options.redux?
560
+ {
561
+ badge: "SSR",
562
+ title: "Server render + hydrate",
563
+ description: "The OSS baseline: render HTML on the server, then hydrate React in the browser.",
564
+ url: "https://reactonrails.com/docs/getting-started/tutorial/",
565
+ cta: "Read the SSR tutorial",
566
+ external: true
567
+ }
568
+ else
569
+ {
570
+ badge: "SSR",
571
+ title: "Server render + hydrate",
572
+ description: "Rendered on the server, hydrated in the browser, and ready for hot reloading in development.",
573
+ url: "/hello_world",
574
+ cta: "Open SSR demo",
575
+ external: false
576
+ }
577
+ end
578
+ end
579
+
580
+ def home_page_rsc_path
581
+ if use_rsc?
582
+ {
583
+ badge: "RSC",
584
+ title: "Async server components",
585
+ description: "This app already streams React Server Components from Rails with small client islands.",
586
+ url: "/hello_server",
587
+ cta: "Open RSC demo",
588
+ external: false
589
+ }
590
+ else
591
+ {
592
+ badge: "RSC",
593
+ title: "Streaming with server/client boundaries",
594
+ description: "Use the Pro stack when you want React Server Components and streamed rendering.",
595
+ url: "https://reactonrails.com/docs/pro/react-server-components/",
596
+ cta: "See RSC docs",
597
+ external: true
598
+ }
599
+ end
600
+ end
601
+
602
+ def home_page_compare_path
603
+ if use_pro?
604
+ {
605
+ badge: "PRO",
606
+ title: "Node renderer + upgrade docs",
607
+ description: "Pro keeps the Rails integration story but adds the Node renderer, RSC " \
608
+ "docs, and support paths.",
609
+ url: "https://reactonrails.com/pro/",
610
+ cta: "Open Pro overview",
611
+ external: true
612
+ }
613
+ else
614
+ {
615
+ badge: "COMPARE",
616
+ title: "Know when to upgrade",
617
+ description: "Stay on OSS for the baseline, then compare with Pro before you need RSC " \
618
+ "or higher-throughput SSR.",
619
+ url: "https://reactonrails.com/docs/getting-started/oss-vs-pro/",
620
+ cta: "Compare OSS and Pro",
621
+ external: true
622
+ }
623
+ end
624
+ end
625
+
626
+ def home_page_stack_badges
627
+ badges = [
628
+ options.typescript? ? "TypeScript" : "JavaScript",
629
+ using_rspack? ? "Rspack" : "Webpack",
630
+ use_rsc? ? "React Server Components" : "Server-side rendering",
631
+ "Rails + PostgreSQL"
632
+ ]
633
+ badges << "React on Rails Pro" if use_pro?
634
+ badges
635
+ end
636
+
637
+ def example_source_path
638
+ return "app/javascript/src/HelloServer/" if use_rsc? && !options.redux?
639
+ return "app/javascript/src/HelloWorldApp/" if options.redux?
640
+
641
+ "app/javascript/src/HelloWorld/"
642
+ end
643
+
644
+ def example_view_path
645
+ use_rsc? && !options.redux? ? "app/views/hello_server/index.html.erb" : "app/views/hello_world/index.html.erb"
646
+ end
647
+
648
+ def home_page_pro_description_for_enabled_app
649
+ if use_rsc?
650
+ "This fresh app already includes the Pro RSC stack. Use the links below to go deeper on " \
651
+ "the generated HelloServer route, the Node renderer, and larger example apps."
652
+ else
653
+ "This fresh app already includes the Pro stack. Use the links below to learn the Node " \
654
+ "renderer and the broader upgrade story before you shape the app into your own product."
655
+ end
656
+ end
657
+
658
+ def home_page_pro_description_for_oss_app
659
+ "Stay on OSS for the base Rails + React workflow. Move to Pro when you want React Server Components, " \
660
+ "the Node renderer, or a clearer path for performance-focused rendering work."
661
+ end
662
+
663
+ def home_page_pro_note_for_enabled_app
664
+ "React on Rails Pro can be enabled route by route, so validate the flows that matter before " \
665
+ "expanding the footprint."
666
+ end
667
+
668
+ def home_page_pro_note_for_oss_app
669
+ "You can evaluate React on Rails Pro without a license while deciding whether it fits your app."
670
+ end
671
+
258
672
  def preferred_rspec_helper_file
259
673
  rails_helper = File.join(destination_root, "spec/rails_helper.rb")
260
674
  return rails_helper if File.exist?(rails_helper)
@@ -731,7 +1145,11 @@ module ReactOnRails
731
1145
  content = File.read(helper_file)
732
1146
  return if content.match?(/^\s*[^#\s][^#]*ReactOnRails::TestHelper\.configure_rspec_to_compile_assets/)
733
1147
 
734
- updated_content = content.sub("RSpec.configure do |config|", CONFIGURE_RSPEC_TO_COMPILE_ASSETS)
1148
+ updated_content = content.sub(/^(?<indent>\s*)RSpec\.configure do \|config\|\s*$/) do |header|
1149
+ indent = Regexp.last_match[:indent]
1150
+ insertion = CONFIGURE_RSPEC_TO_COMPILE_ASSETS.lines.map { |line| "#{indent} #{line}" }.join
1151
+ "#{header}\n#{insertion}"
1152
+ end
735
1153
  return if updated_content == content
736
1154
 
737
1155
  File.write(helper_file, updated_content)