react_on_rails 16.2.0.beta.10 → 16.2.0.beta.11
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 +4 -4
- data/CHANGELOG.md +5 -8
- data/CLAUDE.md +136 -5
- data/CONTRIBUTING.md +3 -1
- data/Gemfile.lock +1 -1
- data/Steepfile +4 -0
- data/analysis/rake-task-duplicate-analysis.md +149 -0
- data/bin/ci-run-failed-specs +6 -4
- data/bin/ci-switch-config +4 -3
- data/lib/generators/react_on_rails/base_generator.rb +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +29 -0
- data/lib/generators/react_on_rails/js_dependency_manager.rb +29 -7
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +19 -0
- data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt} +9 -0
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +38 -4
- data/lib/react_on_rails/configuration.rb +82 -8
- data/lib/react_on_rails/dev/pack_generator.rb +1 -0
- data/lib/react_on_rails/dev/server_manager.rb +1 -0
- data/lib/react_on_rails/doctor.rb +94 -4
- data/lib/react_on_rails/system_checker.rb +7 -4
- data/lib/react_on_rails/utils.rb +54 -0
- data/lib/react_on_rails/version.rb +1 -1
- data/react_on_rails_pro/Gemfile.lock +3 -3
- data/react_on_rails_pro/lib/react_on_rails_pro/version.rb +1 -1
- data/react_on_rails_pro/package.json +1 -1
- data/react_on_rails_pro/spec/dummy/Gemfile.lock +3 -3
- data/sig/react_on_rails/dev/file_manager.rbs +15 -0
- data/sig/react_on_rails/dev/pack_generator.rbs +19 -0
- data/sig/react_on_rails/dev/process_manager.rbs +22 -0
- data/sig/react_on_rails/dev/server_manager.rbs +39 -0
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 94e2c46e66774ffdeb5902068d74c22daf9b2eafd08b45f1d353be5de6df24b1
|
|
4
|
+
data.tar.gz: 49e2fc58fbc4e1df4d5a0573940b5bbe2c346c7bf226f6535e80b8e1fd82e216
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca050de67f3ae49a02674b0130b1b2532d090605565cff6055fa51f779741109d2415a4069ceb470a819fdcb988fab51795b278eff644c122599c484a1e6aada
|
|
7
|
+
data.tar.gz: 99e95152c8015ae37ca106f70ac64bb1b64e52c006b0fd0836f84a091bf00db014d2f09c81199b19624ddc8f6db68ea75c4d74ace02445a7d25cf7db3d79f529
|
data/CHANGELOG.md
CHANGED
|
@@ -23,11 +23,7 @@ After a release, please make sure to run `bundle exec rake update_changelog`. Th
|
|
|
23
23
|
|
|
24
24
|
Changes since the last non-beta release.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
- **Duplicate Rake Task Execution**: Fixed rake tasks executing twice during asset precompilation and other rake operations. Rails Engine was loading task files twice: once via explicit `load` calls in the `rake_tasks` block (Railtie layer) and once via automatic file loading from `lib/tasks/` (Engine layer). This caused `react_on_rails:assets:webpack`, `react_on_rails:generate_packs`, and `react_on_rails:locale` tasks to run twice, significantly increasing build times. Removed explicit `load` calls and now rely on Rails Engine's standard auto-loading behavior. [PR 2052](https://github.com/shakacode/react_on_rails/pull/2052) by [justin808](https://github.com/justin808).
|
|
29
|
-
|
|
30
|
-
### [v16.2.0.beta.8] - 2025-11-16
|
|
26
|
+
### [v16.2.0.beta.10] - 2025-11-18
|
|
31
27
|
|
|
32
28
|
#### Added
|
|
33
29
|
|
|
@@ -73,6 +69,8 @@ Changes since the last non-beta release.
|
|
|
73
69
|
|
|
74
70
|
#### Fixed
|
|
75
71
|
|
|
72
|
+
- **Duplicate Rake Task Execution**: Fixed rake tasks executing twice during asset precompilation and other rake operations. Rails Engine was loading task files twice: once via explicit `load` calls in the `rake_tasks` block (Railtie layer) and once via automatic file loading from `lib/tasks/` (Engine layer). This caused `react_on_rails:assets:webpack`, `react_on_rails:generate_packs`, and `react_on_rails:locale` tasks to run twice, significantly increasing build times. Removed explicit `load` calls and now rely on Rails Engine's standard auto-loading behavior. [PR 2052](https://github.com/shakacode/react_on_rails/pull/2052) by [justin808](https://github.com/justin808).
|
|
73
|
+
|
|
76
74
|
- **Node Renderer Worker Restart**: Fixed "descriptor closed" error that occurred when the node renderer restarts while handling an in-progress request (especially streaming requests). Workers now perform graceful shutdowns: they disconnect from the cluster to stop receiving new requests, wait for active requests to complete, then shut down cleanly. A configurable `gracefulWorkerRestartTimeout` ensures workers are forcibly killed if they don't shut down in time. [PR 1970](https://github.com/shakacode/react_on_rails/pull/1970) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
|
77
75
|
|
|
78
76
|
- **Body Duplication Bug On Streaming**: Fixed a bug that happens while streaming if the node renderer connection closed after streaming some chunks to the client. [PR #1995](https://github.com/shakacode/react_on_rails/pull/1995) by [AbanoubGhadban](https://github.com/AbanoubGhadban).
|
|
@@ -1845,9 +1843,8 @@ such as:
|
|
|
1845
1843
|
|
|
1846
1844
|
- Fix several generator-related issues.
|
|
1847
1845
|
|
|
1848
|
-
[unreleased]: https://github.com/shakacode/react_on_rails/compare/v16.2.0.beta.
|
|
1849
|
-
[v16.2.0.beta.
|
|
1850
|
-
[16.2.0.beta.4]: https://github.com/shakacode/react_on_rails/compare/16.1.1...16.2.0.beta.4
|
|
1846
|
+
[unreleased]: https://github.com/shakacode/react_on_rails/compare/v16.2.0.beta.10...master
|
|
1847
|
+
[v16.2.0.beta.10]: https://github.com/shakacode/react_on_rails/compare/16.1.1...v16.2.0.beta.10
|
|
1851
1848
|
[16.1.1]: https://github.com/shakacode/react_on_rails/compare/16.1.0...16.1.1
|
|
1852
1849
|
[16.1.0]: https://github.com/shakacode/react_on_rails/compare/16.0.0...16.1.0
|
|
1853
1850
|
[16.0.0]: https://github.com/shakacode/react_on_rails/compare/14.2.0...16.0.0
|
data/CLAUDE.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
4
|
|
|
5
|
+
## Project Structure Guidelines
|
|
6
|
+
|
|
7
|
+
### Analysis Documents
|
|
8
|
+
|
|
9
|
+
When creating analysis documents (deep dives, investigations, historical context):
|
|
10
|
+
- **Location**: Place in `/analysis` directory
|
|
11
|
+
- **Format**: Use Markdown (.md)
|
|
12
|
+
- **Naming**: Use descriptive kebab-case names (e.g., `rake-task-duplicate-analysis.md`)
|
|
13
|
+
- **Purpose**: Keep detailed analyses separate from top-level project files
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
- `/analysis/rake-task-duplicate-analysis.md` - Historical analysis of duplicate rake task bug
|
|
17
|
+
- `/analysis/feature-investigation.md` - Investigation of a specific feature or issue
|
|
18
|
+
|
|
19
|
+
Top-level documentation (like README.md, CONTRIBUTING.md) should remain at the root.
|
|
20
|
+
|
|
5
21
|
## ⚠️ CRITICAL REQUIREMENTS
|
|
6
22
|
|
|
7
23
|
**BEFORE EVERY COMMIT/PUSH:**
|
|
@@ -178,11 +194,24 @@ cd react_on_rails_pro && bundle exec rake rbs:validate
|
|
|
178
194
|
```
|
|
179
195
|
## Changelog
|
|
180
196
|
|
|
197
|
+
**IMPORTANT: This is a monorepo with TWO separate changelogs:**
|
|
198
|
+
- **Open Source**: `/CHANGELOG.md` - for react_on_rails gem and npm package
|
|
199
|
+
- **Pro**: `/react_on_rails_pro/CHANGELOG.md` - for react_on_rails_pro gem and npm packages
|
|
200
|
+
|
|
201
|
+
When making changes, update the **appropriate changelog(s)**:
|
|
202
|
+
- Open-source features/fixes → Update `/CHANGELOG.md`
|
|
203
|
+
- Pro-only features/fixes → Update `/react_on_rails_pro/CHANGELOG.md`
|
|
204
|
+
- Changes affecting both → Update **BOTH** changelogs
|
|
205
|
+
|
|
206
|
+
### Changelog Guidelines
|
|
207
|
+
|
|
181
208
|
- **Update CHANGELOG.md for user-visible changes only** (features, bug fixes, breaking changes, deprecations, performance improvements)
|
|
182
209
|
- **Do NOT add entries for**: linting, formatting, refactoring, tests, or documentation fixes
|
|
183
210
|
- **Format**: `[PR 1818](https://github.com/shakacode/react_on_rails/pull/1818) by [username](https://github.com/username)` (no hash in PR number)
|
|
184
211
|
- **Use `/update-changelog` command** for guided changelog updates with automatic formatting
|
|
185
|
-
- **Version management
|
|
212
|
+
- **Version management after releases**:
|
|
213
|
+
- Open source: `bundle exec rake update_changelog`
|
|
214
|
+
- Pro: `cd react_on_rails_pro && bundle exec rake update_changelog`
|
|
186
215
|
- **Examples**: Run `grep -A 3 "^#### " CHANGELOG.md | head -30` to see real formatting examples
|
|
187
216
|
|
|
188
217
|
## ⚠️ FORMATTING RULES
|
|
@@ -198,12 +227,25 @@ cd react_on_rails_pro && bundle exec rake rbs:validate
|
|
|
198
227
|
**CRITICAL**: When resolving merge conflicts, follow this exact sequence:
|
|
199
228
|
|
|
200
229
|
1. **Resolve logical conflicts only** - don't worry about formatting
|
|
201
|
-
2. **
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
230
|
+
2. **VERIFY FILE PATHS** - if the conflict involved directory structure:
|
|
231
|
+
- Check if any hardcoded paths need updating
|
|
232
|
+
- Run: `grep -r "old/path" . --exclude-dir=node_modules`
|
|
233
|
+
- Pay special attention to package-scripts.yml, webpack configs, package.json
|
|
234
|
+
- **Test affected scripts:** If package-scripts.yml changed, run `yarn run prepack`
|
|
235
|
+
3. **Add resolved files**: `git add .` (or specific files)
|
|
236
|
+
4. **Auto-fix everything**: `rake autofix`
|
|
237
|
+
5. **Add any formatting changes**: `git add .`
|
|
238
|
+
6. **Continue rebase/merge**: `git rebase --continue` or `git commit`
|
|
239
|
+
7. **TEST CRITICAL SCRIPTS if build configs changed:**
|
|
240
|
+
```bash
|
|
241
|
+
yarn run prepack # Test prepack script
|
|
242
|
+
yarn run yalc.publish # Test yalc publish if package structure changed
|
|
243
|
+
rake run_rspec:gem # Run relevant test suites
|
|
244
|
+
```
|
|
205
245
|
|
|
206
246
|
**❌ NEVER manually format during conflict resolution** - this causes formatting wars between tools.
|
|
247
|
+
**❌ NEVER blindly accept path changes** - verify they're correct for current structure.
|
|
248
|
+
**❌ NEVER skip testing after resolving conflicts in build configs** - silent failures are dangerous.
|
|
207
249
|
|
|
208
250
|
### Debugging Formatting Issues
|
|
209
251
|
- Check current formatting: `yarn start format.listDifferent`
|
|
@@ -223,6 +265,18 @@ cd react_on_rails_pro && bundle exec rake rbs:validate
|
|
|
223
265
|
- **Gem-only tests**: `rake run_rspec:gem`
|
|
224
266
|
- **All tests except examples**: `rake all_but_examples`
|
|
225
267
|
|
|
268
|
+
## Testing Build and Package Scripts
|
|
269
|
+
|
|
270
|
+
@.claude/docs/testing-build-scripts.md
|
|
271
|
+
|
|
272
|
+
## Master Branch Health Monitoring
|
|
273
|
+
|
|
274
|
+
@.claude/docs/master-health-monitoring.md
|
|
275
|
+
|
|
276
|
+
## Managing File Paths in Configuration Files
|
|
277
|
+
|
|
278
|
+
@.claude/docs/managing-file-paths.md
|
|
279
|
+
|
|
226
280
|
## Project Architecture
|
|
227
281
|
|
|
228
282
|
### Monorepo Structure
|
|
@@ -504,6 +558,83 @@ Playwright E2E tests run automatically in CI via GitHub Actions (`.github/workfl
|
|
|
504
558
|
- Uploads HTML reports as artifacts (available for 30 days)
|
|
505
559
|
- Auto-starts Rails server before running tests
|
|
506
560
|
|
|
561
|
+
## Rails Engine Development Nuances
|
|
562
|
+
|
|
563
|
+
React on Rails is a **Rails Engine**, which has important implications for development:
|
|
564
|
+
|
|
565
|
+
### Automatic Rake Task Loading
|
|
566
|
+
|
|
567
|
+
**CRITICAL**: Rails::Engine automatically loads all `.rake` files from `lib/tasks/` directory. **DO NOT** use a `rake_tasks` block to explicitly load them, as this causes duplicate task execution.
|
|
568
|
+
|
|
569
|
+
```ruby
|
|
570
|
+
# ❌ WRONG - Causes duplicate execution
|
|
571
|
+
module ReactOnRails
|
|
572
|
+
class Engine < ::Rails::Engine
|
|
573
|
+
rake_tasks do
|
|
574
|
+
load File.expand_path("../tasks/generate_packs.rake", __dir__)
|
|
575
|
+
load File.expand_path("../tasks/assets.rake", __dir__)
|
|
576
|
+
load File.expand_path("../tasks/locale.rake", __dir__)
|
|
577
|
+
end
|
|
578
|
+
end
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# ✅ CORRECT - Rails::Engine loads lib/tasks/*.rake automatically
|
|
582
|
+
module ReactOnRails
|
|
583
|
+
class Engine < ::Rails::Engine
|
|
584
|
+
# Rake tasks are automatically loaded from lib/tasks/*.rake by Rails::Engine
|
|
585
|
+
# No explicit loading needed
|
|
586
|
+
end
|
|
587
|
+
end
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
**When to use `rake_tasks` block:**
|
|
591
|
+
- Tasks are in a **non-standard location** (not `lib/tasks/`)
|
|
592
|
+
- You need to **programmatically generate** tasks
|
|
593
|
+
- You need to **pass context** to the tasks
|
|
594
|
+
|
|
595
|
+
**Historical Context**: PR #1770 added explicit rake task loading, causing webpack builds and pack generation to run twice during `rake assets:precompile`. This was fixed in PR #2052. See `analysis/rake-task-duplicate-analysis.md` for full details.
|
|
596
|
+
|
|
597
|
+
### Engine Initializers and Hooks
|
|
598
|
+
|
|
599
|
+
Engines have specific initialization hooks that run at different times:
|
|
600
|
+
|
|
601
|
+
```ruby
|
|
602
|
+
module ReactOnRails
|
|
603
|
+
class Engine < ::Rails::Engine
|
|
604
|
+
# Runs after Rails initializes but before routes are loaded
|
|
605
|
+
config.to_prepare do
|
|
606
|
+
ReactOnRails::ServerRenderingPool.reset_pool
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
# Runs during Rails initialization, use for validations
|
|
610
|
+
initializer "react_on_rails.validate_version" do
|
|
611
|
+
config.after_initialize do
|
|
612
|
+
# Validation logic here
|
|
613
|
+
end
|
|
614
|
+
end
|
|
615
|
+
end
|
|
616
|
+
end
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Engine vs Application Code
|
|
620
|
+
|
|
621
|
+
- **Engine code** (`lib/react_on_rails/`): Runs in the gem context, has limited access to host application
|
|
622
|
+
- **Host application code**: The Rails app that includes the gem
|
|
623
|
+
- **Generators** (`lib/generators/react_on_rails/`): Run in host app context during setup
|
|
624
|
+
|
|
625
|
+
### Testing Engines
|
|
626
|
+
|
|
627
|
+
- **Dummy app** (`spec/dummy/`): Full Rails app for integration testing
|
|
628
|
+
- **Unit tests** (`spec/react_on_rails/`): Test gem code in isolation
|
|
629
|
+
- Always test both contexts: gem code alone and gem + host app integration
|
|
630
|
+
|
|
631
|
+
### Common Pitfalls
|
|
632
|
+
|
|
633
|
+
1. **Assuming host app structure**: Don't assume `app/javascript/` exists—it might not in older apps
|
|
634
|
+
2. **Path resolution**: Use `Rails.root` for host app paths, not relative paths
|
|
635
|
+
3. **Autoloading**: Engine code follows Rails autoloading rules but with a different load path
|
|
636
|
+
4. **Configuration**: Engine config is separate from host app config—use `ReactOnRails.configure`
|
|
637
|
+
|
|
507
638
|
## IDE Configuration
|
|
508
639
|
|
|
509
640
|
Exclude these directories to prevent IDE slowdowns:
|
data/CONTRIBUTING.md
CHANGED
|
@@ -426,12 +426,14 @@ For more details, see [`docs/CI_OPTIMIZATION.md`](./docs/CI_OPTIMIZATION.md).
|
|
|
426
426
|
|
|
427
427
|
React on Rails provides PR comment commands to control CI behavior:
|
|
428
428
|
|
|
429
|
-
#### `/run-skipped-ci` - Enable Full CI Mode
|
|
429
|
+
#### `/run-skipped-ci` (or `/run-skipped-tests`) - Enable Full CI Mode
|
|
430
430
|
|
|
431
431
|
Runs all skipped CI checks and enables full CI mode for the PR:
|
|
432
432
|
|
|
433
433
|
```
|
|
434
434
|
/run-skipped-ci
|
|
435
|
+
# or use the shorter alias:
|
|
436
|
+
/run-skipped-tests
|
|
435
437
|
```
|
|
436
438
|
|
|
437
439
|
**What it does:**
|
data/Gemfile.lock
CHANGED
data/Steepfile
CHANGED
|
@@ -28,6 +28,10 @@ target :lib do
|
|
|
28
28
|
check "lib/react_on_rails.rb"
|
|
29
29
|
check "lib/react_on_rails/configuration.rb"
|
|
30
30
|
check "lib/react_on_rails/controller.rb"
|
|
31
|
+
check "lib/react_on_rails/dev/file_manager.rb"
|
|
32
|
+
check "lib/react_on_rails/dev/pack_generator.rb"
|
|
33
|
+
check "lib/react_on_rails/dev/process_manager.rb"
|
|
34
|
+
check "lib/react_on_rails/dev/server_manager.rb"
|
|
31
35
|
check "lib/react_on_rails/git_utils.rb"
|
|
32
36
|
check "lib/react_on_rails/helper.rb"
|
|
33
37
|
check "lib/react_on_rails/packer_utils.rb"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Analysis: Why rake_tasks Block Was Added in PR #1770 and Caused Duplicate Execution
|
|
2
|
+
|
|
3
|
+
## Summary
|
|
4
|
+
|
|
5
|
+
In PR #1770 (commit `8f3d178` - "Generator Overhaul & Developer Experience Enhancement"), Ihab added a `rake_tasks` block to `lib/react_on_rails/engine.rb` that explicitly loaded three rake task files. This was part of a **massive generator overhaul** that introduced new rake tasks for the file-system auto-registration feature. However, this caused those tasks to execute **twice** during operations like `rake assets:precompile`, which was fixed in PR #2052.
|
|
6
|
+
|
|
7
|
+
## The Problem: Double Loading of Rake Tasks
|
|
8
|
+
|
|
9
|
+
### What Was Added in PR #1770 (8f3d178)
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# lib/react_on_rails/engine.rb
|
|
13
|
+
module ReactOnRails
|
|
14
|
+
class Engine < ::Rails::Engine
|
|
15
|
+
# ... existing code ...
|
|
16
|
+
|
|
17
|
+
rake_tasks do
|
|
18
|
+
load File.expand_path("../tasks/generate_packs.rake", __dir__)
|
|
19
|
+
load File.expand_path("../tasks/assets.rake", __dir__)
|
|
20
|
+
load File.expand_path("../tasks/locale.rake", __dir__)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Why This Caused Duplicate Execution
|
|
27
|
+
|
|
28
|
+
Rails Engines have **two different mechanisms** for loading rake tasks, and this code inadvertently activated both:
|
|
29
|
+
|
|
30
|
+
1. **Automatic Loading (Engine Layer)**: Rails::Engine automatically loads all `.rake` files from `lib/tasks/` directory
|
|
31
|
+
2. **Manual Loading (Railtie Layer)**: The `rake_tasks` block explicitly loads specific files
|
|
32
|
+
|
|
33
|
+
Because the task files existed in `lib/tasks/`:
|
|
34
|
+
|
|
35
|
+
- `lib/tasks/assets.rake`
|
|
36
|
+
- `lib/tasks/generate_packs.rake`
|
|
37
|
+
- `lib/tasks/locale.rake`
|
|
38
|
+
|
|
39
|
+
They were being loaded **twice**:
|
|
40
|
+
|
|
41
|
+
- Once automatically by Rails::Engine from the `lib/tasks/` directory
|
|
42
|
+
- Once explicitly by the `rake_tasks` block
|
|
43
|
+
|
|
44
|
+
## Why Was This Added in PR #1770?
|
|
45
|
+
|
|
46
|
+
PR #1770 was a **major overhaul** with 97 files changed. Looking at the context:
|
|
47
|
+
|
|
48
|
+
### The Generator Overhaul Introduced:
|
|
49
|
+
|
|
50
|
+
1. **File-system auto-registration**: New feature where components auto-register under `app/javascript/src/.../ror_components`
|
|
51
|
+
2. **New `react_on_rails:generate_packs` rake task**: Critical new task for the auto-registration system
|
|
52
|
+
3. **Enhanced dev tooling**: New `ReactOnRails::Dev` namespace with ServerManager, ProcessManager, PackGenerator
|
|
53
|
+
4. **Shakapacker as required dependency**: Made Shakapacker mandatory (removed Webpacker support)
|
|
54
|
+
|
|
55
|
+
### Why the Explicit Loading Was Added:
|
|
56
|
+
|
|
57
|
+
Based on the PR context and commit message, the most likely reasons:
|
|
58
|
+
|
|
59
|
+
1. **Ensuring Critical Task Availability**: The `react_on_rails:generate_packs` task was brand new and absolutely critical to the file-system auto-registration feature. Ihab may have wanted to guarantee it would be loaded in all contexts.
|
|
60
|
+
|
|
61
|
+
2. **Following Common Rails Engine Patterns**: The `rake_tasks` block is a well-documented pattern in Rails engines. Many gems use it explicitly, even when files are in `lib/tasks/`. Ihab likely followed this pattern as "best practice."
|
|
62
|
+
|
|
63
|
+
3. **Massive PR Complexity**: With 97 files changed, this was a huge refactor. The `rake_tasks` block addition was a tiny part of the overall changes, and the duplicate loading issue was subtle enough that it wasn't caught during review.
|
|
64
|
+
|
|
65
|
+
4. **Lack of Awareness About Automatic Loading**: Rails::Engine's automatic loading of `lib/tasks/*.rake` files is not as well-known as it should be. Many developers (even experienced ones) don't realize this happens automatically.
|
|
66
|
+
|
|
67
|
+
5. **"Belt and Suspenders" Approach**: Given the criticality of the new auto-registration feature, Ihab may have intentionally added explicit loading as a safety measure, not realizing it would cause duplication.
|
|
68
|
+
|
|
69
|
+
**The commit message doesn't mention the rake_tasks addition at all**—it focuses on generator improvements, dev experience, and component architecture. This suggests the `rake_tasks` block was added as a routine implementation detail, not something Ihab thought needed explanation.
|
|
70
|
+
|
|
71
|
+
## The Impact
|
|
72
|
+
|
|
73
|
+
Tasks affected by duplicate execution:
|
|
74
|
+
|
|
75
|
+
- `react_on_rails:assets:webpack` - Webpack builds ran twice
|
|
76
|
+
- `react_on_rails:generate_packs` - Pack generation ran twice
|
|
77
|
+
- `react_on_rails:locale` - Locale file generation ran twice
|
|
78
|
+
|
|
79
|
+
This meant:
|
|
80
|
+
|
|
81
|
+
- **2x build times** during asset precompilation
|
|
82
|
+
- **Slower CI** builds
|
|
83
|
+
- **Confusing console output** showing duplicate webpack compilation messages
|
|
84
|
+
- **Wasted resources** running the same expensive operations twice
|
|
85
|
+
|
|
86
|
+
## The Fix (PR #2052)
|
|
87
|
+
|
|
88
|
+
The fix was simple—remove the redundant `rake_tasks` block and rely solely on Rails' automatic loading:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# lib/react_on_rails/engine.rb
|
|
92
|
+
module ReactOnRails
|
|
93
|
+
class Engine < ::Rails::Engine
|
|
94
|
+
# ... existing code ...
|
|
95
|
+
|
|
96
|
+
# Rake tasks are automatically loaded from lib/tasks/*.rake by Rails::Engine
|
|
97
|
+
# No need to explicitly load them here to avoid duplicate loading
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Key Lesson
|
|
103
|
+
|
|
104
|
+
**Rails::Engine Best Practice**: If your rake task files are in `lib/tasks/`, you don't need a `rake_tasks` block. Rails will load them automatically. Only use `rake_tasks do` if:
|
|
105
|
+
|
|
106
|
+
- Tasks are in a non-standard location
|
|
107
|
+
- You need to programmatically generate tasks
|
|
108
|
+
- You need to pass context to the tasks
|
|
109
|
+
|
|
110
|
+
## Timeline
|
|
111
|
+
|
|
112
|
+
- **Sep 16, 2025** (PR #1770, commit 8f3d178): Ihab adds `rake_tasks` block as part of massive Generator Overhaul (97 files changed)
|
|
113
|
+
- **Nov 18, 2025** (PR #2052, commit 3f6df6be9): Justin discovers and fixes duplicate execution issue by removing the block (~2 months later)
|
|
114
|
+
|
|
115
|
+
## What We Learned
|
|
116
|
+
|
|
117
|
+
### For Code Reviews
|
|
118
|
+
|
|
119
|
+
This incident highlights the challenge of reviewing massive PRs:
|
|
120
|
+
|
|
121
|
+
- **97 files changed** made it nearly impossible to catch subtle issues
|
|
122
|
+
- The `rake_tasks` addition was 6 lines in a file that wasn't the focus of the PR
|
|
123
|
+
- The duplicate loading bug only manifested during asset precompilation, not during normal development
|
|
124
|
+
- Smaller, focused PRs would have made this easier to catch
|
|
125
|
+
|
|
126
|
+
### For Testing
|
|
127
|
+
|
|
128
|
+
The duplicate execution bug was subtle:
|
|
129
|
+
|
|
130
|
+
- **Didn't cause failures**—just slower builds (2x time)
|
|
131
|
+
- **Hard to notice locally**—developers might not realize builds were taking twice as long
|
|
132
|
+
- **Only obvious in CI**—where build times are closely monitored
|
|
133
|
+
- **Needed production-like scenarios**—requires running `rake assets:precompile` to trigger
|
|
134
|
+
|
|
135
|
+
### For Documentation
|
|
136
|
+
|
|
137
|
+
Better documentation of Rails::Engine automatic loading would help:
|
|
138
|
+
|
|
139
|
+
- Many Rails guides show `rake_tasks` blocks without mentioning automatic loading
|
|
140
|
+
- The Rails Engine guide doesn't clearly state when NOT to use `rake_tasks`
|
|
141
|
+
- This leads to cargo-culting of the pattern
|
|
142
|
+
|
|
143
|
+
## References
|
|
144
|
+
|
|
145
|
+
- **Original PR**: [#1770 - "React on Rails Generator Overhaul & Developer Experience Enhancement"](https://github.com/shakacode/react_on_rails/pull/1770)
|
|
146
|
+
- **Original commit**: `8f3d178` - 97 files changed, massive refactor
|
|
147
|
+
- **Fix PR**: [#2052 - "Fix duplicate rake task execution by removing explicit task loading"](https://github.com/shakacode/react_on_rails/pull/2052)
|
|
148
|
+
- **Fix commit**: `3f6df6be9` - Simple 6-line removal
|
|
149
|
+
- **Rails Engine documentation**: https://guides.rubyonrails.org/engines.html#rake-tasks
|
data/bin/ci-run-failed-specs
CHANGED
|
@@ -139,10 +139,12 @@ echo ""
|
|
|
139
139
|
|
|
140
140
|
# Determine the working directory (check if we need to be in spec/dummy)
|
|
141
141
|
WORKING_DIR="."
|
|
142
|
-
if [ ${#UNIQUE_SPECS[@]} -gt 0 ]
|
|
143
|
-
if [
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
if [ ${#UNIQUE_SPECS[@]} -gt 0 ]; then
|
|
143
|
+
if [[ "${UNIQUE_SPECS[0]}" == *"spec/system"* ]] || [[ "${UNIQUE_SPECS[0]}" == *"spec/helpers"* ]]; then
|
|
144
|
+
if [ -d "spec/dummy" ]; then
|
|
145
|
+
WORKING_DIR="spec/dummy"
|
|
146
|
+
echo -e "${BLUE}Running from spec/dummy directory${NC}"
|
|
147
|
+
fi
|
|
146
148
|
fi
|
|
147
149
|
fi
|
|
148
150
|
|
data/bin/ci-switch-config
CHANGED
|
@@ -255,9 +255,10 @@ EOF
|
|
|
255
255
|
set_node_version "20.18.1" "$VERSION_MANAGER"
|
|
256
256
|
|
|
257
257
|
# Run conversion script
|
|
258
|
-
# NOTE: This
|
|
259
|
-
# The
|
|
260
|
-
#
|
|
258
|
+
# NOTE: This executes 'ruby' before the version manager reloads in your current shell.
|
|
259
|
+
# The script/convert file requires Ruby 2.6+ and uses basic file I/O operations.
|
|
260
|
+
# Most modern Ruby versions (2.6+) are compatible. The version manager changes above
|
|
261
|
+
# only take effect after shell reload, so this uses your current Ruby installation.
|
|
261
262
|
print_header "Running script/convert to downgrade dependencies"
|
|
262
263
|
cd "$PROJECT_ROOT"
|
|
263
264
|
ruby script/convert
|
|
@@ -101,7 +101,8 @@ module ReactOnRails
|
|
|
101
101
|
puts "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
|
|
102
102
|
base_path = "base/base/"
|
|
103
103
|
config = "config/shakapacker.yml"
|
|
104
|
-
|
|
104
|
+
# Use template to enable version-aware configuration
|
|
105
|
+
template("#{base_path}#{config}.tt", config)
|
|
105
106
|
configure_rspack_in_shakapacker if options.rspack?
|
|
106
107
|
end
|
|
107
108
|
|
|
@@ -95,4 +95,33 @@ module GeneratorHelper
|
|
|
95
95
|
def component_extension(options)
|
|
96
96
|
options.typescript? ? "tsx" : "jsx"
|
|
97
97
|
end
|
|
98
|
+
|
|
99
|
+
# Check if Shakapacker 9.0 or higher is available
|
|
100
|
+
# Returns true if Shakapacker >= 9.0, false otherwise
|
|
101
|
+
#
|
|
102
|
+
# This method is used during code generation to determine which configuration
|
|
103
|
+
# patterns to use in generated files (e.g., config.privateOutputPath vs hardcoded paths).
|
|
104
|
+
#
|
|
105
|
+
# @return [Boolean] true if Shakapacker 9.0+ is available or likely to be installed
|
|
106
|
+
#
|
|
107
|
+
# @note Default behavior: Returns true when Shakapacker is not yet installed
|
|
108
|
+
# Rationale: During fresh installations, we optimistically assume users will install
|
|
109
|
+
# the latest Shakapacker version. This ensures new projects get best-practice configs.
|
|
110
|
+
# If users later install an older version, the generated webpack config includes
|
|
111
|
+
# fallback logic (e.g., `config.privateOutputPath || hardcodedPath`) that prevents
|
|
112
|
+
# breakage, and validation warnings guide them to fix any misconfigurations.
|
|
113
|
+
def shakapacker_version_9_or_higher?
|
|
114
|
+
return @shakapacker_version_9_or_higher if defined?(@shakapacker_version_9_or_higher)
|
|
115
|
+
|
|
116
|
+
@shakapacker_version_9_or_higher = begin
|
|
117
|
+
# If Shakapacker is not available yet (fresh install), default to true
|
|
118
|
+
# since we're likely installing the latest version
|
|
119
|
+
return true unless defined?(ReactOnRails::PackerUtils)
|
|
120
|
+
|
|
121
|
+
ReactOnRails::PackerUtils.shakapacker_version_requirement_met?("9.0.0")
|
|
122
|
+
rescue StandardError
|
|
123
|
+
# If we can't determine version, assume latest
|
|
124
|
+
true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
98
127
|
end
|
|
@@ -123,14 +123,36 @@ module ReactOnRails
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
def add_react_on_rails_package
|
|
126
|
-
# Use exact version match between gem and npm package for
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
# Use exact version match between gem and npm package for all versions including pre-releases
|
|
127
|
+
# Ruby gem versions use dots (16.2.0.beta.10) but npm requires hyphens (16.2.0-beta.10)
|
|
128
|
+
# This method converts between the two formats.
|
|
129
|
+
#
|
|
130
|
+
# The regex matches:
|
|
131
|
+
# - Stable: 16.2.0
|
|
132
|
+
# - Beta (Ruby): 16.2.0.beta.10 or (npm): 16.2.0-beta.10
|
|
133
|
+
# - RC (Ruby): 16.1.0.rc.1 or (npm): 16.1.0-rc.1
|
|
134
|
+
# - Alpha (Ruby): 16.0.0.alpha.5 or (npm): 16.0.0-alpha.5
|
|
135
|
+
# This ensures beta/rc versions use the exact version instead of "latest" which would
|
|
136
|
+
# install the latest stable release and cause version mismatches.
|
|
137
|
+
|
|
138
|
+
# Accept both dot and hyphen separators for pre-release versions
|
|
139
|
+
version_with_optional_prerelease = /\A(\d+\.\d+\.\d+)([-.]([a-zA-Z0-9.]+))?\z/
|
|
140
|
+
|
|
141
|
+
react_on_rails_pkg = if (match = ReactOnRails::VERSION.match(version_with_optional_prerelease))
|
|
142
|
+
base_version = match[1]
|
|
143
|
+
prerelease = match[3]
|
|
144
|
+
|
|
145
|
+
# Convert Ruby gem format (dot) to npm semver format (hyphen)
|
|
146
|
+
npm_version = if prerelease
|
|
147
|
+
"#{base_version}-#{prerelease}"
|
|
148
|
+
else
|
|
149
|
+
base_version
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
"react-on-rails@#{npm_version}"
|
|
132
153
|
else
|
|
133
|
-
puts "
|
|
154
|
+
puts "WARNING: Unrecognized version format #{ReactOnRails::VERSION}. " \
|
|
155
|
+
"Adding the latest react-on-rails NPM module. " \
|
|
134
156
|
"Double check this is correct in package.json"
|
|
135
157
|
"react-on-rails"
|
|
136
158
|
end
|
data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt
CHANGED
|
@@ -12,6 +12,25 @@ ReactOnRails.configure do |config|
|
|
|
12
12
|
# Set to "" if you're not using server rendering
|
|
13
13
|
config.server_bundle_js_file = "server-bundle.js"
|
|
14
14
|
|
|
15
|
+
# ⚠️ RECOMMENDED: Use Shakapacker 9.0+ private_output_path instead
|
|
16
|
+
#
|
|
17
|
+
# If using Shakapacker 9.0+, add to config/shakapacker.yml:
|
|
18
|
+
# private_output_path: ssr-generated
|
|
19
|
+
#
|
|
20
|
+
# React on Rails will auto-detect this value, eliminating the need to set it here.
|
|
21
|
+
# This keeps your webpack and Rails configs in sync automatically.
|
|
22
|
+
#
|
|
23
|
+
# For older Shakapacker versions or custom setups, manually configure:
|
|
24
|
+
# config.server_bundle_output_path = "ssr-generated"
|
|
25
|
+
#
|
|
26
|
+
# The path is relative to Rails.root and should point to a private directory
|
|
27
|
+
# (outside of public/) for security. Run 'rails react_on_rails:doctor' to verify.
|
|
28
|
+
|
|
29
|
+
# Enforce that server bundles are only loaded from private (non-public) directories.
|
|
30
|
+
# When true, server bundles will only be loaded from the configured server_bundle_output_path.
|
|
31
|
+
# This is recommended for production to prevent server-side code from being exposed.
|
|
32
|
+
config.enforce_private_server_bundles = true
|
|
33
|
+
|
|
15
34
|
################################################################################
|
|
16
35
|
# Test Configuration (Optional)
|
|
17
36
|
################################################################################
|
data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt}
RENAMED
|
@@ -29,6 +29,15 @@ default: &default
|
|
|
29
29
|
# Location for manifest.json, defaults to {public_output_path}/manifest.json if unset
|
|
30
30
|
# manifest_path: public/packs/manifest.json
|
|
31
31
|
|
|
32
|
+
# Location for private server-side bundles (e.g., for SSR)
|
|
33
|
+
# These bundles are not served publicly, unlike public_output_path
|
|
34
|
+
# Shakapacker 9.0+ feature - automatically detected by React on Rails
|
|
35
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
36
|
+
private_output_path: ssr-generated
|
|
37
|
+
<% else -%>
|
|
38
|
+
# private_output_path: ssr-generated # Uncomment to enable (requires Shakapacker 9.0+)
|
|
39
|
+
<% end -%>
|
|
40
|
+
|
|
32
41
|
# Additional paths webpack should look up modules
|
|
33
42
|
# ['app/assets', 'engine/foo/app/assets']
|
|
34
43
|
additional_paths: []
|
data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt
CHANGED
|
@@ -44,19 +44,53 @@ const configureServer = () => {
|
|
|
44
44
|
};
|
|
45
45
|
serverWebpackConfig.plugins.unshift(new bundler.optimize.LimitChunkCountPlugin({ maxChunks: 1 }));
|
|
46
46
|
|
|
47
|
-
// Custom output for the server-bundle
|
|
48
|
-
|
|
49
|
-
//
|
|
47
|
+
// Custom output for the server-bundle
|
|
48
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
49
|
+
// Using Shakapacker 9.0+ privateOutputPath for automatic sync with shakapacker.yml
|
|
50
|
+
// This eliminates manual path configuration and keeps configs in sync.
|
|
51
|
+
// Falls back to hardcoded path if private_output_path is not configured.
|
|
52
|
+
const serverBundleOutputPath = config.privateOutputPath ||
|
|
53
|
+
require('path').resolve(__dirname, '../../ssr-generated');
|
|
54
|
+
<% else -%>
|
|
55
|
+
// Using hardcoded path (Shakapacker < 9.0)
|
|
56
|
+
// For Shakapacker 9.0+, consider using config.privateOutputPath instead
|
|
57
|
+
// to automatically sync with shakapacker.yml private_output_path.
|
|
58
|
+
const serverBundleOutputPath = require('path').resolve(__dirname, '../../ssr-generated');
|
|
59
|
+
<% end -%>
|
|
60
|
+
|
|
50
61
|
serverWebpackConfig.output = {
|
|
51
62
|
filename: 'server-bundle.js',
|
|
52
63
|
globalObject: 'this',
|
|
53
64
|
// If using the React on Rails Pro node server renderer, uncomment the next line
|
|
54
65
|
// libraryTarget: 'commonjs2',
|
|
55
|
-
path:
|
|
66
|
+
path: serverBundleOutputPath,
|
|
56
67
|
// No publicPath needed since server bundles are not served via web
|
|
57
68
|
// https://webpack.js.org/configuration/output/#outputglobalobject
|
|
58
69
|
};
|
|
59
70
|
|
|
71
|
+
// Validate server bundle output path configuration
|
|
72
|
+
<% if shakapacker_version_9_or_higher? -%>
|
|
73
|
+
// For Shakapacker 9.0+, verify privateOutputPath is configured in shakapacker.yml
|
|
74
|
+
if (!config.privateOutputPath) {
|
|
75
|
+
console.warn('⚠️ Shakapacker 9.0+ detected but private_output_path not configured in shakapacker.yml');
|
|
76
|
+
console.warn(' Add to config/shakapacker.yml:');
|
|
77
|
+
console.warn(' private_output_path: ssr-generated');
|
|
78
|
+
console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
|
|
79
|
+
}
|
|
80
|
+
<% else -%>
|
|
81
|
+
// For Shakapacker < 9.0, verify hardcoded path syncs with Rails config
|
|
82
|
+
// 1. Ensure config/initializers/react_on_rails.rb has: config.server_bundle_output_path = "ssr-generated"
|
|
83
|
+
// 2. Run: rails react_on_rails:doctor to verify configuration
|
|
84
|
+
const fs = require('fs');
|
|
85
|
+
if (!fs.existsSync(serverBundleOutputPath)) {
|
|
86
|
+
console.warn(`⚠️ Server bundle output directory does not exist: ${serverBundleOutputPath}`);
|
|
87
|
+
console.warn(' It will be created during build, but ensure React on Rails is configured:');
|
|
88
|
+
console.warn(' config.server_bundle_output_path = "ssr-generated" in config/initializers/react_on_rails.rb');
|
|
89
|
+
console.warn(' Run: rails react_on_rails:doctor to validate your configuration');
|
|
90
|
+
}
|
|
91
|
+
<% end -%>
|
|
92
|
+
|
|
93
|
+
|
|
60
94
|
// Don't hash the server bundle b/c would conflict with the client manifest
|
|
61
95
|
// And no need for the MiniCssExtractPlugin
|
|
62
96
|
serverWebpackConfig.plugins = serverWebpackConfig.plugins.filter(
|
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "active_support/core_ext/enumerable"
|
|
4
|
+
require "active_support/core_ext/object/blank"
|
|
5
|
+
|
|
6
|
+
# Polyfill for compact_blank (added in Rails 6.1) to support Rails 5.2-6.0
|
|
7
|
+
unless [].respond_to?(:compact_blank)
|
|
8
|
+
module Enumerable
|
|
9
|
+
def compact_blank
|
|
10
|
+
reject(&:blank?)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Array
|
|
15
|
+
def compact_blank
|
|
16
|
+
reject(&:blank?)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
3
21
|
# rubocop:disable Metrics/ClassLength
|
|
4
22
|
|
|
5
23
|
module ReactOnRails
|
|
@@ -10,6 +28,7 @@ module ReactOnRails
|
|
|
10
28
|
|
|
11
29
|
DEFAULT_GENERATED_ASSETS_DIR = File.join(%w[public webpack], Rails.env).freeze
|
|
12
30
|
DEFAULT_COMPONENT_REGISTRY_TIMEOUT = 5000
|
|
31
|
+
DEFAULT_SERVER_BUNDLE_OUTPUT_PATH = "ssr-generated"
|
|
13
32
|
|
|
14
33
|
def self.configuration
|
|
15
34
|
@configuration ||= Configuration.new(
|
|
@@ -46,7 +65,7 @@ module ReactOnRails
|
|
|
46
65
|
# Set to 0 to disable the timeout and wait indefinitely for component registration.
|
|
47
66
|
component_registry_timeout: DEFAULT_COMPONENT_REGISTRY_TIMEOUT,
|
|
48
67
|
generated_component_packs_loading_strategy: nil,
|
|
49
|
-
server_bundle_output_path:
|
|
68
|
+
server_bundle_output_path: DEFAULT_SERVER_BUNDLE_OUTPUT_PATH,
|
|
50
69
|
enforce_private_server_bundles: false
|
|
51
70
|
)
|
|
52
71
|
end
|
|
@@ -184,6 +203,7 @@ module ReactOnRails
|
|
|
184
203
|
check_component_registry_timeout
|
|
185
204
|
validate_generated_component_packs_loading_strategy
|
|
186
205
|
validate_enforce_private_server_bundles
|
|
206
|
+
auto_detect_server_bundle_path_from_shakapacker
|
|
187
207
|
end
|
|
188
208
|
|
|
189
209
|
private
|
|
@@ -257,6 +277,57 @@ module ReactOnRails
|
|
|
257
277
|
"the public directory. Please set it to a directory outside of public."
|
|
258
278
|
end
|
|
259
279
|
|
|
280
|
+
# Auto-detect server_bundle_output_path from Shakapacker 9.0+ private_output_path
|
|
281
|
+
# Checks if user explicitly set a value and warns them to use auto-detection instead
|
|
282
|
+
def auto_detect_server_bundle_path_from_shakapacker
|
|
283
|
+
# Skip if Shakapacker is not available
|
|
284
|
+
return unless defined?(::Shakapacker)
|
|
285
|
+
|
|
286
|
+
# Check if Shakapacker config has private_output_path method (9.0+)
|
|
287
|
+
return unless ::Shakapacker.config.respond_to?(:private_output_path)
|
|
288
|
+
|
|
289
|
+
# Get the private_output_path from Shakapacker
|
|
290
|
+
private_path = ::Shakapacker.config.private_output_path
|
|
291
|
+
return unless private_path
|
|
292
|
+
|
|
293
|
+
relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
|
|
294
|
+
|
|
295
|
+
# Check if user explicitly configured server_bundle_output_path
|
|
296
|
+
if server_bundle_output_path != ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
|
|
297
|
+
warn_about_explicit_configuration(relative_path)
|
|
298
|
+
return
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
apply_shakapacker_private_output_path(relative_path)
|
|
302
|
+
rescue StandardError => e
|
|
303
|
+
# Fail gracefully - if auto-detection fails, keep the default
|
|
304
|
+
Rails.logger&.debug("ReactOnRails: Could not auto-detect server bundle path from " \
|
|
305
|
+
"Shakapacker: #{e.message}")
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def warn_about_explicit_configuration(shakapacker_path)
|
|
309
|
+
# Normalize both paths for comparison
|
|
310
|
+
normalized_config = server_bundle_output_path.to_s.chomp("/")
|
|
311
|
+
normalized_shakapacker = shakapacker_path.to_s.chomp("/")
|
|
312
|
+
|
|
313
|
+
# Only warn if there's a mismatch
|
|
314
|
+
return if normalized_config == normalized_shakapacker
|
|
315
|
+
|
|
316
|
+
Rails.logger&.warn(
|
|
317
|
+
"ReactOnRails: server_bundle_output_path is explicitly set to '#{server_bundle_output_path}' " \
|
|
318
|
+
"but shakapacker.yml private_output_path is '#{shakapacker_path}'. " \
|
|
319
|
+
"Consider removing server_bundle_output_path from your React on Rails initializer " \
|
|
320
|
+
"to use the auto-detected value from shakapacker.yml."
|
|
321
|
+
)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def apply_shakapacker_private_output_path(relative_path)
|
|
325
|
+
self.server_bundle_output_path = relative_path
|
|
326
|
+
|
|
327
|
+
Rails.logger&.debug("ReactOnRails: Auto-detected server_bundle_output_path from " \
|
|
328
|
+
"shakapacker.yml private_output_path: '#{relative_path}'")
|
|
329
|
+
end
|
|
330
|
+
|
|
260
331
|
def check_minimum_shakapacker_version
|
|
261
332
|
ReactOnRails::PackerUtils.raise_shakapacker_version_incompatible_for_basic_pack_generation unless
|
|
262
333
|
ReactOnRails::PackerUtils.supports_basic_pack_generation?
|
|
@@ -360,13 +431,16 @@ module ReactOnRails
|
|
|
360
431
|
def ensure_webpack_generated_files_exists
|
|
361
432
|
return unless webpack_generated_files.empty?
|
|
362
433
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
434
|
+
files = ["manifest.json", server_bundle_js_file]
|
|
435
|
+
|
|
436
|
+
if ReactOnRails::Utils.react_on_rails_pro?
|
|
437
|
+
pro_config = ReactOnRailsPro.configuration
|
|
438
|
+
files << pro_config.rsc_bundle_js_file
|
|
439
|
+
files << pro_config.react_client_manifest_file
|
|
440
|
+
files << pro_config.react_server_client_manifest_file
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
self.webpack_generated_files = files.compact_blank
|
|
370
444
|
end
|
|
371
445
|
|
|
372
446
|
def configure_skip_display_none_deprecation
|
|
@@ -667,6 +667,7 @@ module ReactOnRails
|
|
|
667
667
|
end
|
|
668
668
|
end
|
|
669
669
|
|
|
670
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
670
671
|
def analyze_server_rendering_config(content)
|
|
671
672
|
checker.add_info("\n🖥️ Server Rendering:")
|
|
672
673
|
|
|
@@ -678,6 +679,19 @@ module ReactOnRails
|
|
|
678
679
|
checker.add_info(" server_bundle_js_file: server-bundle.js (default)")
|
|
679
680
|
end
|
|
680
681
|
|
|
682
|
+
# Server bundle output path
|
|
683
|
+
server_bundle_path_match = content.match(/config\.server_bundle_output_path\s*=\s*["']([^"']+)["']/)
|
|
684
|
+
default_path = ReactOnRails::DEFAULT_SERVER_BUNDLE_OUTPUT_PATH
|
|
685
|
+
rails_bundle_path = server_bundle_path_match ? server_bundle_path_match[1] : default_path
|
|
686
|
+
checker.add_info(" server_bundle_output_path: #{rails_bundle_path}")
|
|
687
|
+
|
|
688
|
+
# Enforce private server bundles
|
|
689
|
+
enforce_private_match = content.match(/config\.enforce_private_server_bundles\s*=\s*([^\s\n,]+)/)
|
|
690
|
+
checker.add_info(" enforce_private_server_bundles: #{enforce_private_match[1]}") if enforce_private_match
|
|
691
|
+
|
|
692
|
+
# Check Shakapacker integration and provide recommendations
|
|
693
|
+
check_shakapacker_private_output_path(rails_bundle_path)
|
|
694
|
+
|
|
681
695
|
# RSC bundle file (Pro feature)
|
|
682
696
|
rsc_bundle_match = content.match(/config\.rsc_bundle_js_file\s*=\s*["']([^"']+)["']/)
|
|
683
697
|
if rsc_bundle_match
|
|
@@ -702,9 +716,9 @@ module ReactOnRails
|
|
|
702
716
|
|
|
703
717
|
checker.add_info(" raise_on_prerender_error: #{raise_on_error_match[1]}")
|
|
704
718
|
end
|
|
705
|
-
# rubocop:enable Metrics/
|
|
719
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
706
720
|
|
|
707
|
-
# rubocop:disable Metrics/
|
|
721
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
708
722
|
def analyze_performance_config(content)
|
|
709
723
|
checker.add_info("\n⚡ Performance & Loading:")
|
|
710
724
|
|
|
@@ -1387,9 +1401,85 @@ module ReactOnRails
|
|
|
1387
1401
|
end
|
|
1388
1402
|
|
|
1389
1403
|
def log_debug(message)
|
|
1390
|
-
|
|
1404
|
+
Rails.logger&.debug(message)
|
|
1405
|
+
end
|
|
1406
|
+
|
|
1407
|
+
# Check Shakapacker private_output_path integration and provide recommendations
|
|
1408
|
+
def check_shakapacker_private_output_path(rails_bundle_path)
|
|
1409
|
+
return report_no_shakapacker unless defined?(::Shakapacker)
|
|
1410
|
+
return report_upgrade_shakapacker unless ::Shakapacker.config.respond_to?(:private_output_path)
|
|
1411
|
+
|
|
1412
|
+
check_shakapacker_9_private_output_path(rails_bundle_path)
|
|
1413
|
+
rescue StandardError => e
|
|
1414
|
+
checker.add_info("\n ℹ️ Could not check Shakapacker config: #{e.message}")
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
def report_no_shakapacker
|
|
1418
|
+
checker.add_info("\n ℹ️ Shakapacker not detected - using manual configuration")
|
|
1419
|
+
end
|
|
1420
|
+
|
|
1421
|
+
def report_upgrade_shakapacker
|
|
1422
|
+
checker.add_info(<<~MSG.strip)
|
|
1423
|
+
\n 💡 Recommendation: Upgrade to Shakapacker 9.0+
|
|
1424
|
+
|
|
1425
|
+
Shakapacker 9.0+ adds 'private_output_path' in shakapacker.yml for server bundles.
|
|
1426
|
+
This eliminates the need to configure server_bundle_output_path separately.
|
|
1427
|
+
|
|
1428
|
+
Benefits:
|
|
1429
|
+
- Single source of truth in shakapacker.yml
|
|
1430
|
+
- Automatic detection by React on Rails
|
|
1431
|
+
- No configuration duplication
|
|
1432
|
+
MSG
|
|
1433
|
+
end
|
|
1434
|
+
|
|
1435
|
+
def check_shakapacker_9_private_output_path(rails_bundle_path)
|
|
1436
|
+
private_path = ::Shakapacker.config.private_output_path
|
|
1437
|
+
|
|
1438
|
+
if private_path
|
|
1439
|
+
report_shakapacker_path_status(private_path, rails_bundle_path)
|
|
1440
|
+
else
|
|
1441
|
+
report_configure_private_output_path(rails_bundle_path)
|
|
1442
|
+
end
|
|
1443
|
+
end
|
|
1444
|
+
|
|
1445
|
+
def report_shakapacker_path_status(private_path, rails_bundle_path)
|
|
1446
|
+
relative_path = ReactOnRails::Utils.normalize_to_relative_path(private_path)
|
|
1447
|
+
# Normalize both paths for comparison (remove trailing slashes)
|
|
1448
|
+
normalized_relative = relative_path.to_s.chomp("/")
|
|
1449
|
+
normalized_rails = rails_bundle_path.to_s.chomp("/")
|
|
1450
|
+
|
|
1451
|
+
if normalized_relative == normalized_rails
|
|
1452
|
+
checker.add_success("\n ✅ Using Shakapacker 9.0+ private_output_path: '#{relative_path}'")
|
|
1453
|
+
checker.add_info(" Auto-detected from shakapacker.yml - no manual config needed")
|
|
1454
|
+
else
|
|
1455
|
+
report_configuration_mismatch(relative_path, rails_bundle_path)
|
|
1456
|
+
end
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
def report_configuration_mismatch(relative_path, rails_bundle_path)
|
|
1460
|
+
checker.add_warning(<<~MSG.strip)
|
|
1461
|
+
\n ⚠️ Configuration mismatch detected!
|
|
1462
|
+
|
|
1463
|
+
Shakapacker private_output_path: '#{relative_path}'
|
|
1464
|
+
React on Rails server_bundle_output_path: '#{rails_bundle_path}'
|
|
1465
|
+
|
|
1466
|
+
Recommendation: Remove server_bundle_output_path from your React on Rails
|
|
1467
|
+
initializer and let it auto-detect from shakapacker.yml private_output_path.
|
|
1468
|
+
MSG
|
|
1469
|
+
end
|
|
1470
|
+
|
|
1471
|
+
def report_configure_private_output_path(rails_bundle_path)
|
|
1472
|
+
checker.add_info(<<~MSG.strip)
|
|
1473
|
+
\n 💡 Recommendation: Configure private_output_path in shakapacker.yml
|
|
1474
|
+
|
|
1475
|
+
Add to config/shakapacker.yml:
|
|
1476
|
+
private_output_path: #{rails_bundle_path}
|
|
1391
1477
|
|
|
1392
|
-
|
|
1478
|
+
This will:
|
|
1479
|
+
- Keep webpack and Rails configs in sync automatically
|
|
1480
|
+
- Enable auto-detection by React on Rails
|
|
1481
|
+
- Serve as single source of truth for server bundle location
|
|
1482
|
+
MSG
|
|
1393
1483
|
end
|
|
1394
1484
|
end
|
|
1395
1485
|
# rubocop:enable Metrics/ClassLength
|
|
@@ -213,17 +213,20 @@ module ReactOnRails
|
|
|
213
213
|
|
|
214
214
|
return unless npm_version && defined?(ReactOnRails::VERSION)
|
|
215
215
|
|
|
216
|
-
#
|
|
217
|
-
|
|
216
|
+
# Normalize NPM version format to Ruby gem format for comparison
|
|
217
|
+
# Uses existing VersionSyntaxConverter to handle dash/dot differences
|
|
218
|
+
# (e.g., "16.2.0-beta.10" → "16.2.0.beta.10")
|
|
219
|
+
converter = ReactOnRails::VersionSyntaxConverter.new
|
|
220
|
+
normalized_npm_version = converter.npm_to_rubygem(npm_version)
|
|
218
221
|
gem_version = ReactOnRails::VERSION
|
|
219
222
|
|
|
220
|
-
if
|
|
223
|
+
if normalized_npm_version == gem_version
|
|
221
224
|
add_success("✅ React on Rails gem and NPM package versions match (#{gem_version})")
|
|
222
225
|
check_version_patterns(npm_version, gem_version)
|
|
223
226
|
else
|
|
224
227
|
# Check for major version differences
|
|
225
228
|
gem_major = gem_version.split(".")[0].to_i
|
|
226
|
-
npm_major =
|
|
229
|
+
npm_major = normalized_npm_version.split(".")[0].to_i
|
|
227
230
|
|
|
228
231
|
if gem_major != npm_major # rubocop:disable Style/NegatedIfElseCondition
|
|
229
232
|
add_error(<<~MSG.strip)
|
data/lib/react_on_rails/utils.rb
CHANGED
|
@@ -443,6 +443,60 @@ module ReactOnRails
|
|
|
443
443
|
end
|
|
444
444
|
end
|
|
445
445
|
|
|
446
|
+
# Converts an absolute path (String or Pathname) to a path relative to Rails.root.
|
|
447
|
+
# If the path is already relative or doesn't contain Rails.root, returns it as-is.
|
|
448
|
+
#
|
|
449
|
+
# This method is used to normalize paths from Shakapacker's privateOutputPath (which is
|
|
450
|
+
# absolute) to relative paths suitable for React on Rails configuration.
|
|
451
|
+
#
|
|
452
|
+
# Note: Absolute paths that don't start with Rails.root are intentionally passed through
|
|
453
|
+
# unchanged. While there's no known use case for server bundles outside Rails.root,
|
|
454
|
+
# this behavior preserves the original path for debugging and error messages.
|
|
455
|
+
#
|
|
456
|
+
# @param path [String, Pathname] The path to normalize
|
|
457
|
+
# @return [String, nil] The relative path as a string, or nil if path is nil
|
|
458
|
+
#
|
|
459
|
+
# @example Converting absolute paths within Rails.root
|
|
460
|
+
# # Assuming Rails.root is "/app"
|
|
461
|
+
# normalize_to_relative_path("/app/ssr-generated") # => "ssr-generated"
|
|
462
|
+
# normalize_to_relative_path("/app/foo/bar") # => "foo/bar"
|
|
463
|
+
#
|
|
464
|
+
# @example Already relative paths pass through
|
|
465
|
+
# normalize_to_relative_path("ssr-generated") # => "ssr-generated"
|
|
466
|
+
# normalize_to_relative_path("./ssr-generated") # => "./ssr-generated"
|
|
467
|
+
#
|
|
468
|
+
# @example Absolute paths outside Rails.root (edge case)
|
|
469
|
+
# normalize_to_relative_path("/other/path/bundles") # => "/other/path/bundles"
|
|
470
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
|
471
|
+
def self.normalize_to_relative_path(path)
|
|
472
|
+
return nil if path.nil?
|
|
473
|
+
|
|
474
|
+
path_str = path.to_s
|
|
475
|
+
rails_root_str = Rails.root.to_s.chomp("/")
|
|
476
|
+
|
|
477
|
+
# Treat as "inside Rails.root" only for exact match or a subdirectory
|
|
478
|
+
inside_rails_root = rails_root_str.present? &&
|
|
479
|
+
(path_str == rails_root_str || path_str.start_with?("#{rails_root_str}/"))
|
|
480
|
+
|
|
481
|
+
# If path is within Rails.root, remove that prefix
|
|
482
|
+
if inside_rails_root
|
|
483
|
+
# Remove Rails.root and any leading slash
|
|
484
|
+
path_str.sub(%r{^#{Regexp.escape(rails_root_str)}/?}, "")
|
|
485
|
+
else
|
|
486
|
+
# Path is already relative or outside Rails.root
|
|
487
|
+
# Warn if it's an absolute path outside Rails.root (edge case)
|
|
488
|
+
if path_str.start_with?("/") && !inside_rails_root
|
|
489
|
+
Rails.logger&.warn(
|
|
490
|
+
"ReactOnRails: Detected absolute path outside Rails.root: '#{path_str}'. " \
|
|
491
|
+
"Server bundles are typically stored within Rails.root. " \
|
|
492
|
+
"Verify this is intentional."
|
|
493
|
+
)
|
|
494
|
+
end
|
|
495
|
+
path_str
|
|
496
|
+
end
|
|
497
|
+
end
|
|
498
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
499
|
+
|
|
446
500
|
def self.default_troubleshooting_section
|
|
447
501
|
<<~DEFAULT
|
|
448
502
|
📞 Get Help & Support:
|
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.2.0.beta.
|
|
12
|
+
react_on_rails (16.2.0.beta.11)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,7 +20,7 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: .
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.2.0.beta.
|
|
23
|
+
react_on_rails_pro (16.2.0.beta.11)
|
|
24
24
|
addressable
|
|
25
25
|
async (>= 2.6)
|
|
26
26
|
connection_pool
|
|
@@ -28,7 +28,7 @@ PATH
|
|
|
28
28
|
httpx (~> 1.5)
|
|
29
29
|
jwt (~> 2.7)
|
|
30
30
|
rainbow
|
|
31
|
-
react_on_rails (= 16.2.0.beta.
|
|
31
|
+
react_on_rails (= 16.2.0.beta.11)
|
|
32
32
|
|
|
33
33
|
GEM
|
|
34
34
|
remote: https://rubygems.org/
|
|
@@ -9,7 +9,7 @@ GIT
|
|
|
9
9
|
PATH
|
|
10
10
|
remote: ../../..
|
|
11
11
|
specs:
|
|
12
|
-
react_on_rails (16.2.0.beta.
|
|
12
|
+
react_on_rails (16.2.0.beta.11)
|
|
13
13
|
addressable
|
|
14
14
|
connection_pool
|
|
15
15
|
execjs (~> 2.5)
|
|
@@ -20,7 +20,7 @@ PATH
|
|
|
20
20
|
PATH
|
|
21
21
|
remote: ../..
|
|
22
22
|
specs:
|
|
23
|
-
react_on_rails_pro (16.2.0.beta.
|
|
23
|
+
react_on_rails_pro (16.2.0.beta.11)
|
|
24
24
|
addressable
|
|
25
25
|
async (>= 2.6)
|
|
26
26
|
connection_pool
|
|
@@ -28,7 +28,7 @@ PATH
|
|
|
28
28
|
httpx (~> 1.5)
|
|
29
29
|
jwt (~> 2.7)
|
|
30
30
|
rainbow
|
|
31
|
-
react_on_rails (= 16.2.0.beta.
|
|
31
|
+
react_on_rails (= 16.2.0.beta.11)
|
|
32
32
|
|
|
33
33
|
GEM
|
|
34
34
|
remote: https://rubygems.org/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module ReactOnRails
|
|
2
|
+
module Dev
|
|
3
|
+
class FileManager
|
|
4
|
+
def self.cleanup_stale_files: () -> bool
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def self.cleanup_overmind_sockets: () -> bool
|
|
9
|
+
def self.cleanup_rails_pid_file: () -> bool
|
|
10
|
+
def self.overmind_running?: () -> bool
|
|
11
|
+
def self.process_running?: (Integer) -> bool
|
|
12
|
+
def self.remove_file_if_exists: (String, String) -> bool
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module ReactOnRails
|
|
2
|
+
module Dev
|
|
3
|
+
class PackGenerator
|
|
4
|
+
def self.generate: (?verbose: bool) -> void
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def self.run_pack_generation: (?silent: bool) -> bool
|
|
9
|
+
def self.should_run_directly?: () -> bool
|
|
10
|
+
def self.rails_available?: () -> bool
|
|
11
|
+
def self.run_rake_task_directly: (?silent: bool) -> bool
|
|
12
|
+
def self.load_rake_tasks: () -> void
|
|
13
|
+
def self.prepare_rake_task: () -> untyped
|
|
14
|
+
def self.capture_output: (bool) { () -> bool } -> bool
|
|
15
|
+
def self.handle_rake_error: (Exception, bool) -> void
|
|
16
|
+
def self.run_via_bundle_exec: (?silent: bool) -> (bool | nil)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module ReactOnRails
|
|
2
|
+
module Dev
|
|
3
|
+
class ProcessManager
|
|
4
|
+
VERSION_CHECK_TIMEOUT: Integer
|
|
5
|
+
|
|
6
|
+
def self.installed?: (String) -> bool
|
|
7
|
+
def self.ensure_procfile: (String) -> void
|
|
8
|
+
def self.run_with_process_manager: (String) -> void
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def self.installed_in_current_context?: (String) -> bool
|
|
13
|
+
def self.version_flags_for: (String) -> Array[String]
|
|
14
|
+
def self.run_process_if_available: (String, Array[String]) -> bool
|
|
15
|
+
def self.run_process_outside_bundle: (String, Array[String]) -> bool
|
|
16
|
+
def self.process_available_in_system?: (String) -> bool
|
|
17
|
+
def self.with_unbundled_context: () { () -> untyped } -> untyped
|
|
18
|
+
def self.show_process_manager_installation_help: () -> void
|
|
19
|
+
def self.valid_procfile_path?: (String) -> bool
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module ReactOnRails
|
|
2
|
+
module Dev
|
|
3
|
+
class ServerManager
|
|
4
|
+
type mode = :development | :production_like | :static | :hmr
|
|
5
|
+
|
|
6
|
+
def self.start: (mode, String?, ?verbose: bool, ?route: String?, ?rails_env: String?) -> void
|
|
7
|
+
def self.kill_processes: () -> void
|
|
8
|
+
def self.development_processes: () -> Hash[String, String]
|
|
9
|
+
def self.kill_running_processes: () -> bool
|
|
10
|
+
def self.find_process_pids: (String) -> Array[Integer]
|
|
11
|
+
def self.terminate_processes: (Array[Integer]) -> void
|
|
12
|
+
def self.kill_port_processes: (Array[Integer]) -> bool
|
|
13
|
+
def self.find_port_pids: (Integer) -> Array[Integer]
|
|
14
|
+
def self.cleanup_socket_files: () -> bool
|
|
15
|
+
def self.print_kill_summary: (bool) -> void
|
|
16
|
+
def self.show_help: () -> void
|
|
17
|
+
def self.run_from_command_line: (?Array[String]) -> void
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def self.help_usage: () -> String
|
|
22
|
+
def self.help_commands: () -> String
|
|
23
|
+
def self.help_options: () -> String
|
|
24
|
+
def self.help_customization: () -> String
|
|
25
|
+
def self.help_mode_details: () -> String
|
|
26
|
+
def self.help_troubleshooting: () -> String
|
|
27
|
+
def self.run_production_like: (?_verbose: bool, ?route: String?, ?rails_env: String?) -> void
|
|
28
|
+
def self.run_static_development: (String, ?verbose: bool, ?route: String?) -> void
|
|
29
|
+
def self.run_development: (String, ?verbose: bool, ?route: String?) -> void
|
|
30
|
+
def self.print_server_info: (String, Array[String], ?Integer, ?route: String?) -> void
|
|
31
|
+
def self.print_procfile_info: (String, ?route: String?) -> void
|
|
32
|
+
def self.procfile_port: (String) -> Integer
|
|
33
|
+
def self.box_border: (Integer) -> String
|
|
34
|
+
def self.box_bottom: (Integer) -> String
|
|
35
|
+
def self.box_empty_line: (Integer) -> String
|
|
36
|
+
def self.format_box_line: (String, Integer) -> String
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
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.2.0.beta.
|
|
4
|
+
version: 16.2.0.beta.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Gordon
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-11-
|
|
11
|
+
date: 2025-11-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: addressable
|
|
@@ -140,6 +140,7 @@ files:
|
|
|
140
140
|
- Steepfile
|
|
141
141
|
- TODO.md
|
|
142
142
|
- WARP.md
|
|
143
|
+
- analysis/rake-task-duplicate-analysis.md
|
|
143
144
|
- app/helpers/react_on_rails_helper.rb
|
|
144
145
|
- bin/ci-local
|
|
145
146
|
- bin/ci-rerun-failures
|
|
@@ -191,7 +192,7 @@ files:
|
|
|
191
192
|
- lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook
|
|
192
193
|
- lib/generators/react_on_rails/templates/base/base/bin/switch-bundler
|
|
193
194
|
- lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt
|
|
194
|
-
- lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml
|
|
195
|
+
- lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml.tt
|
|
195
196
|
- lib/generators/react_on_rails/templates/base/base/config/webpack/clientWebpackConfig.js.tt
|
|
196
197
|
- lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt
|
|
197
198
|
- lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt
|
|
@@ -974,6 +975,10 @@ files:
|
|
|
974
975
|
- sig/react_on_rails.rbs
|
|
975
976
|
- sig/react_on_rails/configuration.rbs
|
|
976
977
|
- sig/react_on_rails/controller.rbs
|
|
978
|
+
- sig/react_on_rails/dev/file_manager.rbs
|
|
979
|
+
- sig/react_on_rails/dev/pack_generator.rbs
|
|
980
|
+
- sig/react_on_rails/dev/process_manager.rbs
|
|
981
|
+
- sig/react_on_rails/dev/server_manager.rbs
|
|
977
982
|
- sig/react_on_rails/error.rbs
|
|
978
983
|
- sig/react_on_rails/generators/js_dependency_manager.rbs
|
|
979
984
|
- sig/react_on_rails/git_utils.rbs
|