react_on_rails 15.0.0.rc.2 → 16.0.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 +4 -4
- data/CHANGELOG.md +65 -36
- data/CLAUDE.md +90 -0
- data/CODING_AGENTS.md +312 -0
- data/CONTRIBUTING.md +378 -3
- data/Gemfile.lock +2 -1
- data/LICENSE.md +16 -4
- data/LICENSES/README.md +14 -0
- data/REACT-ON-RAILS-PRO-LICENSE.md +129 -0
- data/README.md +2 -2
- data/TODO.md +135 -0
- data/eslint.config.ts +2 -0
- data/lib/generators/USAGE +4 -5
- data/lib/generators/react_on_rails/base_generator.rb +263 -57
- data/lib/generators/react_on_rails/bin/dev +38 -22
- data/lib/generators/react_on_rails/dev_tests_generator.rb +1 -0
- data/lib/generators/react_on_rails/generator_helper.rb +31 -1
- data/lib/generators/react_on_rails/generator_messages.rb +138 -17
- data/lib/generators/react_on_rails/install_generator.rb +222 -20
- data/lib/generators/react_on_rails/react_no_redux_generator.rb +6 -5
- data/lib/generators/react_on_rails/react_with_redux_generator.rb +37 -13
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev +5 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-prod-assets +8 -0
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static-assets +2 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/server-bundle.js +1 -8
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.client.jsx +21 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/src/HelloWorld/ror_components/HelloWorld.server.jsx +5 -0
- data/lib/generators/react_on_rails/templates/base/base/app/views/hello_world/index.html.erb.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/app/views/layouts/hello_world.html.erb +4 -2
- data/lib/generators/react_on_rails/templates/base/base/babel.config.js.tt +5 -2
- data/lib/generators/react_on_rails/templates/base/base/bin/dev +46 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +3 -3
- data/lib/generators/react_on_rails/templates/base/base/config/shakapacker.yml +76 -7
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/commonWebpackConfig.js.tt +1 -1
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +8 -8
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/production.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/test.js.tt +2 -2
- data/lib/generators/react_on_rails/templates/dev_tests/spec/system/hello_world_spec.rb +0 -2
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.jsx +0 -6
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/components/HelloWorld.module.css +4 -0
- data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/HelloWorldApp.server.jsx +5 -0
- data/lib/react_on_rails/configuration.rb +5 -5
- data/lib/react_on_rails/controller.rb +5 -3
- data/lib/react_on_rails/dev/file_manager.rb +78 -0
- data/lib/react_on_rails/dev/pack_generator.rb +27 -0
- data/lib/react_on_rails/dev/process_manager.rb +61 -0
- data/lib/react_on_rails/dev/server_manager.rb +330 -0
- data/lib/react_on_rails/dev.rb +20 -0
- data/lib/react_on_rails/engine.rb +6 -0
- data/lib/react_on_rails/git_utils.rb +12 -2
- data/lib/react_on_rails/helper.rb +61 -17
- data/lib/react_on_rails/packer_utils.rb +4 -18
- data/lib/react_on_rails/packs_generator.rb +134 -8
- data/lib/react_on_rails/react_component/render_options.rb +2 -2
- data/lib/react_on_rails/server_rendering_js_code.rb +0 -1
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +1 -0
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +1 -0
- data/lib/react_on_rails/utils.rb +16 -1
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_syntax_converter.rb +1 -1
- data/lib/react_on_rails.rb +1 -0
- data/lib/tasks/generate_packs.rake +20 -0
- data/react_on_rails.gemspec +1 -0
- metadata +40 -11
- data/REACT-ON-RAILS-PRO-LICENSE +0 -95
- data/lib/generators/react_on_rails/adapt_for_older_shakapacker_generator.rb +0 -41
- data/lib/generators/react_on_rails/bin/dev-static +0 -30
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev-static.tt +0 -9
- data/lib/generators/react_on_rails/templates/base/base/Procfile.dev.tt +0 -5
- data/lib/generators/react_on_rails/templates/base/base/app/javascript/packs/registration.js.tt +0 -8
- /data/lib/generators/react_on_rails/templates/base/base/config/webpack/{webpackConfig.js.tt → generateWebpackConfigs.js.tt} +0 -0
- /data/lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/startup/{HelloWorldApp.jsx → HelloWorldApp.client.jsx} +0 -0
data/TODO.md
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
# React on Rails TODO
|
2
|
+
|
3
|
+
## Generator Improvements
|
4
|
+
|
5
|
+
### HelloWorld Component Structure
|
6
|
+
|
7
|
+
- [x] Fix bad import in HelloWorld.server.jsx (server importing from client)
|
8
|
+
- [x] Simplify to single HelloWorld.jsx file with documentation
|
9
|
+
- [ ] **Consider alternative approach**: Create second example component showing client/server split
|
10
|
+
- Add `client_server_different.jsx` in sibling directory like `/examples/` or `/advanced/`
|
11
|
+
- Show real-world use case (React Router, styled-components, etc.)
|
12
|
+
- Keep HelloWorld simple for beginners
|
13
|
+
|
14
|
+
### File Organization
|
15
|
+
|
16
|
+
- [x] **Improved ror_components directory structure**
|
17
|
+
- Documentation now suggests moving shared components to `../components/` directory
|
18
|
+
- Keeps ror_components clean for React on Rails specific entry points
|
19
|
+
- Recommended structure:
|
20
|
+
```
|
21
|
+
src/HelloWorld/
|
22
|
+
├── components/
|
23
|
+
│ └── HelloWorld.jsx # Shared component implementation
|
24
|
+
└── ror_components/
|
25
|
+
├── HelloWorld.client.jsx # Client entry point (when needed)
|
26
|
+
└── HelloWorld.server.jsx # Server entry point (when needed)
|
27
|
+
```
|
28
|
+
- [ ] **Consider adding generator flag to create this structure automatically**
|
29
|
+
|
30
|
+
### Generator Options
|
31
|
+
|
32
|
+
- [ ] **Add generator flags for different patterns**
|
33
|
+
- `--simple` (default): Single component file
|
34
|
+
- `--split`: Generate client/server split example
|
35
|
+
- `--example-name`: Customize component name beyond HelloWorld
|
36
|
+
|
37
|
+
## Documentation Improvements
|
38
|
+
|
39
|
+
### Component Architecture Guide
|
40
|
+
|
41
|
+
- [ ] **Add comprehensive docs on client/server patterns**
|
42
|
+
- When to use single vs split files
|
43
|
+
- Common libraries requiring server setup (React Router, styled-components, Apollo)
|
44
|
+
- Migration path from simple to split architecture
|
45
|
+
- Auto-registration behavior explanation
|
46
|
+
|
47
|
+
### Code Comments
|
48
|
+
|
49
|
+
- [x] Add inline documentation to HelloWorld.jsx explaining split pattern
|
50
|
+
- [ ] Add JSDoc comments for better IDE support
|
51
|
+
- [ ] Include links to relevant documentation sections
|
52
|
+
|
53
|
+
## Testing Infrastructure
|
54
|
+
|
55
|
+
- [ ] **Test generator output for both simple and split patterns**
|
56
|
+
- [ ] **Validate that auto-registration works correctly**
|
57
|
+
- [ ] **Add integration tests for client/server rendering differences**
|
58
|
+
|
59
|
+
## Developer Experience
|
60
|
+
|
61
|
+
- [ ] **bin/dev help command enhancements**
|
62
|
+
|
63
|
+
- [x] Add emojis and colors for better readability
|
64
|
+
- [ ] Add section about component development patterns
|
65
|
+
- [ ] Include troubleshooting for client/server split issues
|
66
|
+
|
67
|
+
- [ ] **Babel Configuration Conflict Detection**
|
68
|
+
|
69
|
+
- [ ] Add validation in generator/initializer to detect conflicting Babel configs
|
70
|
+
- [ ] Improve error messaging for duplicate preset issues
|
71
|
+
- [ ] Common conflict: babel.config.js + package.json "babel" section
|
72
|
+
- [ ] Specific guidance for yalc development workflow
|
73
|
+
- [ ] Add troubleshooting section for this common issue:
|
74
|
+
|
75
|
+
```
|
76
|
+
❌ BABEL CONFIGURATION CONFLICT DETECTED
|
77
|
+
Found duplicate Babel configurations:
|
78
|
+
• babel.config.js ✓ (recommended)
|
79
|
+
• package.json "babel" section ❌ (conflicting)
|
80
|
+
|
81
|
+
🔧 FIX: Remove the "babel" section from package.json
|
82
|
+
```
|
83
|
+
|
84
|
+
### IDE Support
|
85
|
+
|
86
|
+
- [ ] **Improve TypeScript support**
|
87
|
+
- Add .d.ts files for better type inference
|
88
|
+
- Document TypeScript patterns for client/server split
|
89
|
+
- Consider TypeScript generator templates
|
90
|
+
|
91
|
+
## Performance & Bundle Analysis
|
92
|
+
|
93
|
+
- [ ] **Bundle splitting documentation**
|
94
|
+
- How React on Rails handles client/server bundles
|
95
|
+
- Best practices for code splitting
|
96
|
+
- webpack bundle analysis guidance
|
97
|
+
|
98
|
+
## Real-World Examples
|
99
|
+
|
100
|
+
- [ ] **Create example apps showing advanced patterns**
|
101
|
+
- React Router with SSR
|
102
|
+
- styled-components with server-side rendering
|
103
|
+
- Apollo Client hydration
|
104
|
+
- Next.js-style patterns
|
105
|
+
|
106
|
+
## Migration Guide
|
107
|
+
|
108
|
+
- [ ] **Document upgrade paths**
|
109
|
+
- Converting from Webpacker to Shakapacker
|
110
|
+
- Migrating from single to split components
|
111
|
+
- Updating existing projects to new patterns
|
112
|
+
|
113
|
+
## Community & Ecosystem
|
114
|
+
|
115
|
+
- [ ] **Plugin ecosystem considerations**
|
116
|
+
- Standard patterns for community components
|
117
|
+
- Guidelines for React on Rails compatible libraries
|
118
|
+
- Template repository for component patterns
|
119
|
+
|
120
|
+
---
|
121
|
+
|
122
|
+
## Current Known Issues
|
123
|
+
|
124
|
+
- Generator installer still has remaining issues (mentioned in context)
|
125
|
+
- Version mismatch warnings with yalc during development
|
126
|
+
- Need clearer documentation on when to use different patterns
|
127
|
+
- **Babel configuration conflicts** - Common during yalc development when package.json and babel.config.js both define presets
|
128
|
+
|
129
|
+
## Priority Order
|
130
|
+
|
131
|
+
1. Fix remaining generator installer issues
|
132
|
+
2. Improve HelloWorld component documentation
|
133
|
+
3. Add alternative example showing client/server split
|
134
|
+
4. Create comprehensive architecture documentation
|
135
|
+
5. Add generator flags for different patterns
|
data/eslint.config.ts
CHANGED
@@ -152,6 +152,8 @@ const config = tsEslint.config([
|
|
152
152
|
'import/no-unresolved': 'off',
|
153
153
|
// We have `const [name, setName] = useState(props.name)` so can't just destructure props
|
154
154
|
'react/destructuring-assignment': 'off',
|
155
|
+
// React 19 doesn't need PropTypes - we're targeting modern React
|
156
|
+
'react/prop-types': 'off',
|
155
157
|
},
|
156
158
|
},
|
157
159
|
{
|
data/lib/generators/USAGE
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
Description:
|
2
2
|
|
3
|
-
The react_on_rails:install generator integrates
|
4
|
-
can pass the redux option if you'd like to have redux setup for you automatically.
|
3
|
+
The react_on_rails:install generator integrates a React frontend, including SSR, with Rails.
|
5
4
|
|
6
|
-
* Redux
|
5
|
+
* Redux (Optional)
|
7
6
|
|
8
7
|
Passing the --redux generator option causes the generated Hello World example
|
9
8
|
to integrate the Redux state container framework. The necessary node modules
|
@@ -13,11 +12,11 @@ can pass the redux option if you'd like to have redux setup for you automaticall
|
|
13
12
|
|
14
13
|
After running the generator, you will want to:
|
15
14
|
|
16
|
-
bundle && yarn
|
15
|
+
bundle && npm install # or yarn install, or pnpm install
|
17
16
|
|
18
17
|
Then you may run
|
19
18
|
|
20
|
-
|
19
|
+
./bin/dev
|
21
20
|
|
22
21
|
More Details:
|
23
22
|
|
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails/generators"
|
4
|
+
require "fileutils"
|
4
5
|
require_relative "generator_messages"
|
5
6
|
require_relative "generator_helper"
|
6
7
|
module ReactOnRails
|
7
8
|
module Generators
|
8
9
|
class BaseGenerator < Rails::Generators::Base
|
9
10
|
include GeneratorHelper
|
11
|
+
|
10
12
|
Rails::Generators.hide_namespace(namespace)
|
11
13
|
source_root(File.expand_path("templates", __dir__))
|
12
14
|
|
@@ -14,7 +16,7 @@ module ReactOnRails
|
|
14
16
|
class_option :redux,
|
15
17
|
type: :boolean,
|
16
18
|
default: false,
|
17
|
-
desc: "Install Redux
|
19
|
+
desc: "Install Redux package and Redux version of Hello World Example",
|
18
20
|
aliases: "-R"
|
19
21
|
|
20
22
|
def add_hello_world_route
|
@@ -22,17 +24,21 @@ module ReactOnRails
|
|
22
24
|
end
|
23
25
|
|
24
26
|
def create_react_directories
|
25
|
-
|
26
|
-
|
27
|
+
# Create auto-registration directory structure for non-Redux components only
|
28
|
+
# Redux components handle their own directory structure
|
29
|
+
return if options.redux?
|
30
|
+
|
31
|
+
empty_directory("app/javascript/src/HelloWorld/ror_components")
|
27
32
|
end
|
28
33
|
|
29
34
|
def copy_base_files
|
30
35
|
base_path = "base/base/"
|
31
36
|
base_files = %w[app/controllers/hello_world_controller.rb
|
32
|
-
app/views/layouts/hello_world.html.erb
|
33
|
-
|
34
|
-
|
35
|
-
|
37
|
+
app/views/layouts/hello_world.html.erb
|
38
|
+
Procfile.dev
|
39
|
+
Procfile.dev-static-assets
|
40
|
+
Procfile.dev-prod-assets]
|
41
|
+
base_templates = %w[config/initializers/react_on_rails.rb]
|
36
42
|
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
37
43
|
base_templates.each do |file|
|
38
44
|
template("#{base_path}/#{file}.tt", file, { packer_type: ReactOnRails::PackerUtils.packer_type })
|
@@ -41,9 +47,12 @@ module ReactOnRails
|
|
41
47
|
|
42
48
|
def copy_js_bundle_files
|
43
49
|
base_path = "base/base/"
|
44
|
-
base_files = %w[app/javascript/packs/server-bundle.js
|
45
|
-
|
46
|
-
|
50
|
+
base_files = %w[app/javascript/packs/server-bundle.js]
|
51
|
+
|
52
|
+
# Only copy HelloWorld.module.css for non-Redux components
|
53
|
+
# Redux components handle their own CSS files
|
54
|
+
base_files << "app/javascript/src/HelloWorld/ror_components/HelloWorld.module.css" unless options.redux?
|
55
|
+
|
47
56
|
base_files.each { |file| copy_file("#{base_path}#{file}", file) }
|
48
57
|
end
|
49
58
|
|
@@ -57,15 +66,25 @@ module ReactOnRails
|
|
57
66
|
config/webpack/development.js
|
58
67
|
config/webpack/production.js
|
59
68
|
config/webpack/serverWebpackConfig.js
|
60
|
-
config/webpack/
|
61
|
-
config/webpack/webpackConfig.js]
|
69
|
+
config/webpack/generateWebpackConfigs.js]
|
62
70
|
config = {
|
63
71
|
message: "// The source code including full typescript support is available at:"
|
64
72
|
}
|
65
73
|
base_files.each { |file| template("#{base_path}/#{file}.tt", file, config) }
|
74
|
+
|
75
|
+
# Handle webpack.config.js separately with smart replacement
|
76
|
+
copy_webpack_main_config(base_path, config)
|
66
77
|
end
|
67
78
|
|
68
79
|
def copy_packer_config
|
80
|
+
# Skip copying if Shakapacker was just installed (to avoid conflicts)
|
81
|
+
# Check for a temporary marker file that indicates fresh Shakapacker install
|
82
|
+
if File.exist?(".shakapacker_just_installed")
|
83
|
+
puts "Skipping Shakapacker config copy (already installed by Shakapacker installer)"
|
84
|
+
File.delete(".shakapacker_just_installed") # Clean up marker
|
85
|
+
return
|
86
|
+
end
|
87
|
+
|
69
88
|
puts "Adding Shakapacker #{ReactOnRails::PackerUtils.shakapacker_version} config"
|
70
89
|
base_path = "base/base/"
|
71
90
|
config = "config/shakapacker.yml"
|
@@ -77,39 +96,55 @@ module ReactOnRails
|
|
77
96
|
end
|
78
97
|
|
79
98
|
def add_js_dependencies
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
99
|
+
add_react_on_rails_package
|
100
|
+
add_react_dependencies
|
101
|
+
add_css_dependencies
|
102
|
+
add_dev_dependencies
|
103
|
+
end
|
104
|
+
|
105
|
+
def install_js_dependencies
|
106
|
+
# Detect which package manager to use
|
107
|
+
success = if File.exist?(File.join(destination_root, "yarn.lock"))
|
108
|
+
run "yarn install"
|
109
|
+
elsif File.exist?(File.join(destination_root, "pnpm-lock.yaml"))
|
110
|
+
run "pnpm install"
|
111
|
+
elsif File.exist?(File.join(destination_root, "package-lock.json")) ||
|
112
|
+
File.exist?(File.join(destination_root, "package.json"))
|
113
|
+
# Use npm for package-lock.json or as default fallback
|
114
|
+
run "npm install"
|
115
|
+
else
|
116
|
+
true # No package manager detected, skip
|
117
|
+
end
|
118
|
+
|
119
|
+
unless success
|
120
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
121
|
+
⚠️ JavaScript dependencies installation failed.
|
122
|
+
|
123
|
+
This could be due to network issues or missing package manager.
|
124
|
+
You can install dependencies manually later by running:
|
125
|
+
• npm install (if using npm)
|
126
|
+
• yarn install (if using yarn)
|
127
|
+
• pnpm install (if using pnpm)
|
128
|
+
MSG
|
87
129
|
end
|
88
130
|
|
89
|
-
|
90
|
-
|
91
|
-
"react",
|
92
|
-
"react-dom",
|
93
|
-
"@babel/preset-react",
|
94
|
-
"prop-types",
|
95
|
-
"babel-plugin-transform-react-remove-prop-types",
|
96
|
-
"babel-plugin-macros"
|
97
|
-
])
|
131
|
+
success
|
132
|
+
end
|
98
133
|
|
99
|
-
|
134
|
+
def update_gitignore_for_auto_registration
|
135
|
+
gitignore_path = File.join(destination_root, ".gitignore")
|
136
|
+
return unless File.exist?(gitignore_path)
|
100
137
|
|
101
|
-
|
102
|
-
|
103
|
-
css-minimizer-webpack-plugin
|
104
|
-
mini-css-extract-plugin
|
105
|
-
style-loader
|
106
|
-
])
|
138
|
+
gitignore_content = File.read(gitignore_path)
|
139
|
+
return if gitignore_content.include?("**/generated/**")
|
107
140
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
141
|
+
append_to_file ".gitignore" do
|
142
|
+
<<~GITIGNORE
|
143
|
+
|
144
|
+
# Generated React on Rails packs
|
145
|
+
**/generated/**
|
146
|
+
GITIGNORE
|
147
|
+
end
|
113
148
|
end
|
114
149
|
|
115
150
|
def append_to_spec_rails_helper
|
@@ -118,26 +153,70 @@ module ReactOnRails
|
|
118
153
|
add_configure_rspec_to_compile_assets(rails_helper)
|
119
154
|
else
|
120
155
|
spec_helper = File.join(destination_root, "spec/spec_helper.rb")
|
121
|
-
if File.exist?(spec_helper)
|
122
|
-
|
123
|
-
|
124
|
-
# rubocop:disable Layout/EmptyLinesAroundArguments
|
125
|
-
GeneratorMessages.add_info(
|
126
|
-
<<-MSG.strip_heredoc
|
156
|
+
add_configure_rspec_to_compile_assets(spec_helper) if File.exist?(spec_helper)
|
157
|
+
end
|
158
|
+
end
|
127
159
|
|
128
|
-
|
129
|
-
|
130
|
-
js tests, then we are using latest webpack assets. You can later add
|
131
|
-
this to your rspec config:
|
160
|
+
def add_react_on_rails_package
|
161
|
+
major_minor_patch_only = /\A\d+\.\d+\.\d+\z/
|
132
162
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
163
|
+
# Try to use package_json gem first, fall back to direct npm commands
|
164
|
+
react_on_rails_pkg = if ReactOnRails::VERSION.match?(major_minor_patch_only)
|
165
|
+
["react-on-rails@#{ReactOnRails::VERSION}"]
|
166
|
+
else
|
167
|
+
puts "Adding the latest react-on-rails NPM module. " \
|
168
|
+
"Double check this is correct in package.json"
|
169
|
+
["react-on-rails"]
|
170
|
+
end
|
138
171
|
|
139
|
-
|
140
|
-
|
172
|
+
puts "Installing React on Rails package..."
|
173
|
+
return if add_npm_dependencies(react_on_rails_pkg)
|
174
|
+
|
175
|
+
puts "Using direct npm commands as fallback"
|
176
|
+
success = run "npm install #{react_on_rails_pkg.join(' ')}"
|
177
|
+
handle_npm_failure("react-on-rails package", react_on_rails_pkg) unless success
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_react_dependencies
|
181
|
+
puts "Installing React dependencies..."
|
182
|
+
react_deps = %w[
|
183
|
+
react
|
184
|
+
react-dom
|
185
|
+
@babel/preset-react
|
186
|
+
prop-types
|
187
|
+
babel-plugin-transform-react-remove-prop-types
|
188
|
+
babel-plugin-macros
|
189
|
+
]
|
190
|
+
return if add_npm_dependencies(react_deps)
|
191
|
+
|
192
|
+
success = run "npm install #{react_deps.join(' ')}"
|
193
|
+
handle_npm_failure("React dependencies", react_deps) unless success
|
194
|
+
end
|
195
|
+
|
196
|
+
def add_css_dependencies
|
197
|
+
puts "Installing CSS handling dependencies..."
|
198
|
+
css_deps = %w[
|
199
|
+
css-loader
|
200
|
+
css-minimizer-webpack-plugin
|
201
|
+
mini-css-extract-plugin
|
202
|
+
style-loader
|
203
|
+
]
|
204
|
+
return if add_npm_dependencies(css_deps)
|
205
|
+
|
206
|
+
success = run "npm install #{css_deps.join(' ')}"
|
207
|
+
handle_npm_failure("CSS dependencies", css_deps) unless success
|
208
|
+
end
|
209
|
+
|
210
|
+
def add_dev_dependencies
|
211
|
+
puts "Installing development dependencies..."
|
212
|
+
dev_deps = %w[
|
213
|
+
@pmmmwh/react-refresh-webpack-plugin
|
214
|
+
react-refresh
|
215
|
+
]
|
216
|
+
return if add_npm_dependencies(dev_deps, dev: true)
|
217
|
+
|
218
|
+
success = run "npm install --save-dev #{dev_deps.join(' ')}"
|
219
|
+
handle_npm_failure("development dependencies", dev_deps, dev: true) unless success
|
141
220
|
end
|
142
221
|
|
143
222
|
CONFIGURE_RSPEC_TO_COMPILE_ASSETS = <<-STR.strip_heredoc
|
@@ -145,10 +224,137 @@ module ReactOnRails
|
|
145
224
|
# Ensure that if we are running js tests, we are using latest webpack assets
|
146
225
|
# This will use the defaults of :js and :server_rendering meta tags
|
147
226
|
ReactOnRails::TestHelper.configure_rspec_to_compile_assets(config)
|
227
|
+
end
|
148
228
|
STR
|
149
229
|
|
150
230
|
private
|
151
231
|
|
232
|
+
def handle_npm_failure(dependency_type, packages, dev: false)
|
233
|
+
install_command = dev ? "npm install --save-dev" : "npm install"
|
234
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
235
|
+
⚠️ Failed to install #{dependency_type}.
|
236
|
+
|
237
|
+
The following packages could not be installed automatically:
|
238
|
+
#{packages.map { |pkg| " • #{pkg}" }.join("\n")}
|
239
|
+
|
240
|
+
This could be due to network issues or missing package manager.
|
241
|
+
You can install them manually later by running:
|
242
|
+
#{install_command} #{packages.join(' ')}
|
243
|
+
MSG
|
244
|
+
end
|
245
|
+
|
246
|
+
def copy_webpack_main_config(base_path, config)
|
247
|
+
webpack_config_path = "config/webpack/webpack.config.js"
|
248
|
+
|
249
|
+
if File.exist?(webpack_config_path)
|
250
|
+
existing_content = File.read(webpack_config_path)
|
251
|
+
|
252
|
+
# Check if it's the standard Shakapacker config that we can safely replace
|
253
|
+
if standard_shakapacker_config?(existing_content)
|
254
|
+
# Remove the file first to avoid conflict prompt, then recreate it
|
255
|
+
remove_file(webpack_config_path, verbose: false)
|
256
|
+
# Show what we're doing
|
257
|
+
puts " #{set_color('replace', :green)} #{webpack_config_path} " \
|
258
|
+
"(auto-upgrading from standard Shakapacker to React on Rails config)"
|
259
|
+
template("#{base_path}/#{webpack_config_path}.tt", webpack_config_path, config)
|
260
|
+
elsif react_on_rails_config?(existing_content)
|
261
|
+
puts " #{set_color('identical', :blue)} #{webpack_config_path} " \
|
262
|
+
"(already React on Rails compatible)"
|
263
|
+
# Skip - don't need to do anything
|
264
|
+
else
|
265
|
+
handle_custom_webpack_config(base_path, config, webpack_config_path)
|
266
|
+
end
|
267
|
+
else
|
268
|
+
# File doesn't exist, create it
|
269
|
+
template("#{base_path}/#{webpack_config_path}.tt", webpack_config_path, config)
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def handle_custom_webpack_config(base_path, config, webpack_config_path)
|
274
|
+
# Custom config - ask user
|
275
|
+
puts "\n#{set_color('NOTICE:', :yellow)} Your webpack.config.js appears to be customized."
|
276
|
+
puts "React on Rails needs to replace it with an environment-specific loader."
|
277
|
+
puts "Your current config will be backed up to webpack.config.js.backup"
|
278
|
+
|
279
|
+
if yes?("Replace webpack.config.js with React on Rails version? (Y/n)")
|
280
|
+
# Create backup
|
281
|
+
backup_path = "#{webpack_config_path}.backup"
|
282
|
+
if File.exist?(webpack_config_path)
|
283
|
+
FileUtils.cp(webpack_config_path, backup_path)
|
284
|
+
puts " #{set_color('create', :green)} #{backup_path} (backup of your custom config)"
|
285
|
+
end
|
286
|
+
|
287
|
+
template("#{base_path}/#{webpack_config_path}.tt", webpack_config_path, config)
|
288
|
+
else
|
289
|
+
puts " #{set_color('skip', :yellow)} #{webpack_config_path}"
|
290
|
+
puts " #{set_color('WARNING:', :red)} React on Rails may not work correctly " \
|
291
|
+
"without the environment-specific webpack config"
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def standard_shakapacker_config?(content)
|
296
|
+
# Get the expected default config based on Shakapacker version
|
297
|
+
expected_configs = shakapacker_default_configs
|
298
|
+
|
299
|
+
# Check if the content matches any of the known default configurations
|
300
|
+
expected_configs.any? { |config| content_matches_template?(content, config) }
|
301
|
+
end
|
302
|
+
|
303
|
+
def content_matches_template?(content, template)
|
304
|
+
# Normalize whitespace and compare
|
305
|
+
normalize_config_content(content) == normalize_config_content(template)
|
306
|
+
end
|
307
|
+
|
308
|
+
def normalize_config_content(content)
|
309
|
+
# Remove comments, normalize whitespace, and clean up for comparison
|
310
|
+
content.gsub(%r{//.*$}, "") # Remove single-line comments
|
311
|
+
.gsub(%r{/\*.*?\*/}m, "") # Remove multi-line comments
|
312
|
+
.gsub(/\s+/, " ") # Normalize whitespace
|
313
|
+
.strip
|
314
|
+
end
|
315
|
+
|
316
|
+
def shakapacker_default_configs
|
317
|
+
configs = []
|
318
|
+
|
319
|
+
# Shakapacker v7+ (generateWebpackConfig function)
|
320
|
+
configs << <<~CONFIG
|
321
|
+
// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.
|
322
|
+
const { generateWebpackConfig } = require('shakapacker')
|
323
|
+
|
324
|
+
const webpackConfig = generateWebpackConfig()
|
325
|
+
|
326
|
+
module.exports = webpackConfig
|
327
|
+
CONFIG
|
328
|
+
|
329
|
+
# Shakapacker v6 (webpackConfig object)
|
330
|
+
configs << <<~CONFIG
|
331
|
+
const { webpackConfig } = require('shakapacker')
|
332
|
+
|
333
|
+
// See the shakacode/shakapacker README and docs directory for advice on customizing your webpackConfig.
|
334
|
+
|
335
|
+
module.exports = webpackConfig
|
336
|
+
CONFIG
|
337
|
+
|
338
|
+
# Also check without comments for variations
|
339
|
+
configs << <<~CONFIG
|
340
|
+
const { generateWebpackConfig } = require('shakapacker')
|
341
|
+
const webpackConfig = generateWebpackConfig()
|
342
|
+
module.exports = webpackConfig
|
343
|
+
CONFIG
|
344
|
+
|
345
|
+
configs << <<~CONFIG
|
346
|
+
const { webpackConfig } = require('shakapacker')
|
347
|
+
module.exports = webpackConfig
|
348
|
+
CONFIG
|
349
|
+
|
350
|
+
configs
|
351
|
+
end
|
352
|
+
|
353
|
+
def react_on_rails_config?(content)
|
354
|
+
# Check if it already has React on Rails environment-specific loading
|
355
|
+
content.include?("envSpecificConfig") || content.include?("env.nodeEnv")
|
356
|
+
end
|
357
|
+
|
152
358
|
# From https://github.com/rails/rails/blob/4c940b2dbfb457f67c6250b720f63501d74a45fd/railties/lib/rails/generators/rails/app/app_generator.rb
|
153
359
|
def app_name
|
154
360
|
@app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root))
|
@@ -1,30 +1,46 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
# ReactOnRails Development Server
|
5
|
+
#
|
6
|
+
# This script provides a simple interface to the ReactOnRails development
|
7
|
+
# server management. The core logic is implemented in ReactOnRails::Dev
|
8
|
+
# classes for better maintainability and testing.
|
9
|
+
#
|
10
|
+
# Each command uses a specific Procfile for process management:
|
11
|
+
# - bin/dev (default/hmr): Uses Procfile.dev
|
12
|
+
# - bin/dev static: Uses Procfile.dev-static-assets
|
13
|
+
# - bin/dev prod: Uses Procfile.dev-prod-assets
|
14
|
+
#
|
15
|
+
# To customize development environment:
|
16
|
+
# 1. Edit the appropriate Procfile to modify which processes run
|
17
|
+
# 2. Modify this script for project-specific command-line behavior
|
18
|
+
# 3. Extend ReactOnRails::Dev classes in your Rails app for advanced customization
|
19
|
+
# 4. Use classes directly: ReactOnRails::Dev::ServerManager.start(:development, "Custom.procfile")
|
9
20
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
exit!
|
21
|
+
begin
|
22
|
+
require "bundler/setup"
|
23
|
+
require "react_on_rails/dev"
|
24
|
+
rescue LoadError
|
25
|
+
# Fallback for when gem is not yet installed
|
26
|
+
puts "Loading ReactOnRails development tools..."
|
27
|
+
require_relative "../../lib/react_on_rails/dev"
|
18
28
|
end
|
19
29
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
30
|
+
# Main execution
|
31
|
+
case ARGV[0]
|
32
|
+
when "production-assets", "prod"
|
33
|
+
ReactOnRails::Dev::ServerManager.start(:production_like)
|
34
|
+
when "static"
|
35
|
+
ReactOnRails::Dev::ServerManager.start(:static, "Procfile.dev-static-assets")
|
36
|
+
when "kill"
|
37
|
+
ReactOnRails::Dev::ServerManager.kill_processes
|
38
|
+
when "help", "--help", "-h"
|
39
|
+
ReactOnRails::Dev::ServerManager.show_help
|
40
|
+
when "hmr", nil
|
41
|
+
ReactOnRails::Dev::ServerManager.start(:development, "Procfile.dev")
|
24
42
|
else
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
MSG
|
29
|
-
exit!
|
43
|
+
puts "Unknown argument: #{ARGV[0]}"
|
44
|
+
puts "Run 'bin/dev help' for usage information"
|
45
|
+
exit 1
|
30
46
|
end
|