react_on_rails 16.1.2 → 16.2.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/.rspec +2 -0
- data/.rubocop.yml +85 -0
- data/Gemfile.development_dependencies +8 -7
- data/Gemfile.lock +158 -119
- data/Steepfile +56 -0
- data/lib/generators/react_on_rails/base_generator.rb +43 -120
- data/lib/generators/react_on_rails/dev_tests_generator.rb +2 -1
- data/lib/generators/react_on_rails/generator_helper.rb +102 -2
- data/lib/generators/react_on_rails/install_generator.rb +36 -156
- data/lib/generators/react_on_rails/js_dependency_manager.rb +383 -0
- data/lib/generators/react_on_rails/templates/base/base/.dev-services.yml.example +76 -0
- data/lib/generators/react_on_rails/templates/base/base/bin/shakapacker-precompile-hook +30 -0
- data/lib/generators/react_on_rails/templates/base/base/bin/switch-bundler +141 -0
- data/lib/generators/react_on_rails/templates/base/base/config/initializers/react_on_rails.rb.tt +44 -45
- data/lib/generators/react_on_rails/templates/base/base/config/{shakapacker.yml → shakapacker.yml.tt} +28 -3
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/development.js.tt +15 -9
- data/lib/generators/react_on_rails/templates/base/base/config/webpack/serverWebpackConfig.js.tt +42 -6
- data/lib/react_on_rails/configuration.rb +149 -32
- data/lib/react_on_rails/controller.rb +3 -3
- data/lib/react_on_rails/dev/pack_generator.rb +168 -2
- data/lib/react_on_rails/dev/process_manager.rb +136 -14
- data/lib/react_on_rails/dev/server_manager.rb +194 -26
- data/lib/react_on_rails/dev/service_checker.rb +200 -0
- data/lib/react_on_rails/doctor.rb +341 -12
- data/lib/react_on_rails/engine.rb +75 -1
- data/lib/react_on_rails/git_utils.rb +3 -1
- data/lib/react_on_rails/helper.rb +70 -192
- data/lib/react_on_rails/locales/base.rb +17 -5
- data/lib/react_on_rails/packer_utils.rb +79 -2
- data/lib/react_on_rails/packs_generator.rb +57 -39
- data/lib/react_on_rails/prerender_error.rb +74 -17
- data/lib/react_on_rails/pro_helper.rb +64 -0
- data/lib/react_on_rails/react_component/render_options.rb +7 -7
- data/lib/react_on_rails/server_rendering_pool/ruby_embedded_java_script.rb +2 -5
- data/lib/react_on_rails/smart_error.rb +326 -0
- data/lib/react_on_rails/system_checker.rb +8 -9
- data/lib/react_on_rails/test_helper/webpack_assets_status_checker.rb +16 -7
- data/lib/react_on_rails/utils.rb +241 -55
- data/lib/react_on_rails/version.rb +1 -1
- data/lib/react_on_rails/version_checker.rb +383 -35
- data/lib/tasks/generate_packs.rake +12 -6
- data/lib/tasks/locale.rake +6 -1
- data/rakelib/docker.rake +26 -0
- data/rakelib/dummy_apps.rake +30 -0
- data/rakelib/example_type.rb +121 -0
- data/rakelib/examples_config.yml +52 -0
- data/rakelib/lint.rake +52 -0
- data/rakelib/node_package.rake +15 -0
- data/rakelib/rbs.rake +70 -0
- data/rakelib/run_rspec.rake +223 -0
- data/rakelib/shakapacker_examples.rake +171 -0
- data/rakelib/task_helpers.rb +134 -0
- data/rakelib/update_changelog.rake +73 -0
- data/react_on_rails.gemspec +4 -3
- data/sig/README.md +52 -0
- data/sig/react_on_rails/configuration.rbs +96 -0
- data/sig/react_on_rails/controller.rbs +15 -0
- 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
- data/sig/react_on_rails/dev/service_checker.rbs +22 -0
- data/sig/react_on_rails/error.rbs +4 -0
- data/sig/react_on_rails/generators/js_dependency_manager.rbs +123 -0
- data/sig/react_on_rails/git_utils.rbs +8 -0
- data/sig/react_on_rails/helper.rbs +65 -0
- data/sig/react_on_rails/json_parse_error.rbs +10 -0
- data/sig/react_on_rails/locales.rbs +46 -0
- data/sig/react_on_rails/packer_utils.rbs +15 -0
- data/sig/react_on_rails/prerender_error.rbs +21 -0
- data/sig/react_on_rails/server_rendering_pool.rbs +12 -0
- data/sig/react_on_rails/smart_error.rbs +28 -0
- data/sig/react_on_rails/test_helper.rbs +11 -0
- data/sig/react_on_rails/utils.rbs +34 -0
- data/sig/react_on_rails/version_checker.rbs +12 -0
- data/sig/react_on_rails.rbs +17 -0
- metadata +49 -32
- data/AI_AGENT_INSTRUCTIONS.md +0 -63
- data/CHANGELOG.md +0 -1836
- data/CLAUDE.md +0 -135
- data/CODING_AGENTS.md +0 -313
- data/CONTRIBUTING.md +0 -668
- data/Dockerfile_tests +0 -12
- data/KUDOS.md +0 -114
- data/LICENSE.md +0 -47
- data/LICENSES/README.md +0 -14
- data/NEWS.md +0 -62
- data/PROJECTS.md +0 -63
- data/REACT-ON-RAILS-PRO-LICENSE.md +0 -129
- data/README.md +0 -217
- data/SUMMARY.md +0 -88
- data/TODO.md +0 -135
- data/bin/lefthook/check-trailing-newlines +0 -38
- data/bin/lefthook/get-changed-files +0 -26
- data/bin/lefthook/prettier-format +0 -26
- data/bin/lefthook/ruby-autofix +0 -26
- data/bin/lefthook/ruby-lint +0 -27
- data/docker-compose.yml +0 -11
- data/eslint.config.ts +0 -232
- data/knip.ts +0 -114
- data/lib/react_on_rails/pro/NOTICE +0 -21
- data/lib/react_on_rails/pro/helper.rb +0 -122
- data/lib/react_on_rails/pro/utils.rb +0 -53
- data/tsconfig.eslint.json +0 -6
- data/tsconfig.json +0 -19
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "generator_messages"
|
|
4
|
+
|
|
5
|
+
# rubocop:disable Metrics/ModuleLength
|
|
6
|
+
module ReactOnRails
|
|
7
|
+
module Generators
|
|
8
|
+
# Shared module for managing JavaScript dependencies across generators
|
|
9
|
+
# This module provides common functionality for adding and installing
|
|
10
|
+
# JS dependencies to avoid code duplication between generators.
|
|
11
|
+
#
|
|
12
|
+
# Since react_on_rails requires shakapacker, and shakapacker includes
|
|
13
|
+
# package_json as a dependency, the package_json gem is always available.
|
|
14
|
+
#
|
|
15
|
+
# == Required Methods
|
|
16
|
+
# Including classes must include GeneratorHelper module which provides:
|
|
17
|
+
# - add_npm_dependencies(packages, dev: false): Add packages via package_json gem
|
|
18
|
+
# - package_json: Access to PackageJson instance (always available via shakapacker)
|
|
19
|
+
# - destination_root: Generator destination directory
|
|
20
|
+
#
|
|
21
|
+
# == Optional Methods
|
|
22
|
+
# Including classes may define:
|
|
23
|
+
# - options.rspack?: Returns true if --rspack flag is set (for Rspack support)
|
|
24
|
+
# - options.typescript?: Returns true if --typescript flag is set (for TypeScript support)
|
|
25
|
+
#
|
|
26
|
+
# == Installation Behavior
|
|
27
|
+
# The module ALWAYS runs package manager install after adding dependencies.
|
|
28
|
+
# This is safe because package_json gem's install method is idempotent - it only
|
|
29
|
+
# installs what's actually needed from package.json. This prevents edge cases
|
|
30
|
+
# where package.json was modified but dependencies weren't installed.
|
|
31
|
+
#
|
|
32
|
+
# == Error Handling Philosophy
|
|
33
|
+
# All dependency addition methods use a graceful degradation approach:
|
|
34
|
+
# - Methods return false on failure instead of raising exceptions
|
|
35
|
+
# - StandardError is caught at the lowest level (add_package) and higher levels (add_*_dependencies)
|
|
36
|
+
# - Failures trigger user-facing warnings via GeneratorMessages
|
|
37
|
+
# - Warnings provide clear manual installation instructions
|
|
38
|
+
#
|
|
39
|
+
# This ensures the generator ALWAYS completes successfully, even when:
|
|
40
|
+
# - Network connectivity issues prevent package downloads
|
|
41
|
+
# - Package manager (npm/yarn/pnpm) has permission errors
|
|
42
|
+
# - package_json gem encounters unexpected states
|
|
43
|
+
#
|
|
44
|
+
# Users can manually run package installation commands after generator completion.
|
|
45
|
+
# This is preferable to generator crashes that leave Rails apps in incomplete states.
|
|
46
|
+
#
|
|
47
|
+
# == Usage
|
|
48
|
+
# Include this module in generator classes and call setup_js_dependencies
|
|
49
|
+
# to handle all JS dependency installation via package_json gem.
|
|
50
|
+
module JsDependencyManager
|
|
51
|
+
# Core React dependencies required for React on Rails
|
|
52
|
+
# Note: @babel/preset-react and babel plugins are NOT included here because:
|
|
53
|
+
# - Shakapacker handles JavaScript transpiler configuration (babel, swc, or esbuild)
|
|
54
|
+
# - Users configure their preferred transpiler via shakapacker.yml javascript_transpiler setting
|
|
55
|
+
# - SWC is now the default and doesn't need Babel presets
|
|
56
|
+
# - For Babel users, shakapacker will install babel-loader and its dependencies
|
|
57
|
+
REACT_DEPENDENCIES = %w[
|
|
58
|
+
react
|
|
59
|
+
react-dom
|
|
60
|
+
prop-types
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
# CSS processing dependencies for webpack
|
|
64
|
+
CSS_DEPENDENCIES = %w[
|
|
65
|
+
css-loader
|
|
66
|
+
css-minimizer-webpack-plugin
|
|
67
|
+
mini-css-extract-plugin
|
|
68
|
+
style-loader
|
|
69
|
+
].freeze
|
|
70
|
+
|
|
71
|
+
# Development-only dependencies for hot reloading (Webpack)
|
|
72
|
+
DEV_DEPENDENCIES = %w[
|
|
73
|
+
@pmmmwh/react-refresh-webpack-plugin
|
|
74
|
+
react-refresh
|
|
75
|
+
].freeze
|
|
76
|
+
|
|
77
|
+
# Rspack core dependencies (only installed when --rspack flag is used)
|
|
78
|
+
RSPACK_DEPENDENCIES = %w[
|
|
79
|
+
@rspack/core
|
|
80
|
+
rspack-manifest-plugin
|
|
81
|
+
].freeze
|
|
82
|
+
|
|
83
|
+
# Rspack development dependencies for hot reloading
|
|
84
|
+
RSPACK_DEV_DEPENDENCIES = %w[
|
|
85
|
+
@rspack/cli
|
|
86
|
+
@rspack/plugin-react-refresh
|
|
87
|
+
react-refresh
|
|
88
|
+
].freeze
|
|
89
|
+
|
|
90
|
+
# TypeScript dependencies (only installed when --typescript flag is used)
|
|
91
|
+
# Note: @babel/preset-typescript is NOT included because:
|
|
92
|
+
# - SWC is now the default javascript_transpiler (has built-in TypeScript support)
|
|
93
|
+
# - Shakapacker handles the transpiler configuration via shakapacker.yml
|
|
94
|
+
# - If users choose javascript_transpiler: 'babel', they should manually add @babel/preset-typescript
|
|
95
|
+
# and configure it in their babel.config.js
|
|
96
|
+
TYPESCRIPT_DEPENDENCIES = %w[
|
|
97
|
+
typescript
|
|
98
|
+
@types/react
|
|
99
|
+
@types/react-dom
|
|
100
|
+
].freeze
|
|
101
|
+
|
|
102
|
+
# SWC transpiler dependencies (for Shakapacker 9.3.0+ default transpiler)
|
|
103
|
+
# SWC is ~20x faster than Babel and is the default for new Shakapacker installations
|
|
104
|
+
SWC_DEPENDENCIES = %w[
|
|
105
|
+
@swc/core
|
|
106
|
+
swc-loader
|
|
107
|
+
].freeze
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
def setup_js_dependencies
|
|
112
|
+
add_js_dependencies
|
|
113
|
+
|
|
114
|
+
# Always run install to ensure all dependencies are properly installed.
|
|
115
|
+
# The package_json gem's install method is idempotent and safe to call
|
|
116
|
+
# even if packages were already added - it will only install what's needed.
|
|
117
|
+
# This ensures edge cases where package.json was modified but install wasn't
|
|
118
|
+
# run are handled correctly.
|
|
119
|
+
install_js_dependencies
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def add_js_dependencies
|
|
123
|
+
add_react_on_rails_package
|
|
124
|
+
add_react_dependencies
|
|
125
|
+
add_css_dependencies
|
|
126
|
+
# Rspack dependencies are only added when --rspack flag is used
|
|
127
|
+
add_rspack_dependencies if respond_to?(:options) && options&.rspack?
|
|
128
|
+
# SWC dependencies are only added when SWC is the configured transpiler
|
|
129
|
+
add_swc_dependencies if using_swc?
|
|
130
|
+
# Dev dependencies vary based on bundler choice
|
|
131
|
+
add_dev_dependencies
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def add_react_on_rails_package
|
|
135
|
+
# Use exact version match between gem and npm package for all versions including pre-releases
|
|
136
|
+
# Ruby gem versions use dots (16.2.0.beta.10) but npm requires hyphens (16.2.0-beta.10)
|
|
137
|
+
# This method converts between the two formats.
|
|
138
|
+
#
|
|
139
|
+
# The regex matches:
|
|
140
|
+
# - Stable: 16.2.0
|
|
141
|
+
# - Beta (Ruby): 16.2.0.beta.10 or (npm): 16.2.0-beta.10
|
|
142
|
+
# - RC (Ruby): 16.1.0.rc.1 or (npm): 16.1.0-rc.1
|
|
143
|
+
# - Alpha (Ruby): 16.0.0.alpha.5 or (npm): 16.0.0-alpha.5
|
|
144
|
+
# This ensures beta/rc versions use the exact version instead of "latest" which would
|
|
145
|
+
# install the latest stable release and cause version mismatches.
|
|
146
|
+
|
|
147
|
+
# Accept both dot and hyphen separators for pre-release versions
|
|
148
|
+
version_with_optional_prerelease = /\A(\d+\.\d+\.\d+)([-.]([a-zA-Z0-9.]+))?\z/
|
|
149
|
+
|
|
150
|
+
react_on_rails_pkg = if (match = ReactOnRails::VERSION.match(version_with_optional_prerelease))
|
|
151
|
+
base_version = match[1]
|
|
152
|
+
prerelease = match[3]
|
|
153
|
+
|
|
154
|
+
# Convert Ruby gem format (dot) to npm semver format (hyphen)
|
|
155
|
+
npm_version = if prerelease
|
|
156
|
+
"#{base_version}-#{prerelease}"
|
|
157
|
+
else
|
|
158
|
+
base_version
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
"react-on-rails@#{npm_version}"
|
|
162
|
+
else
|
|
163
|
+
puts "WARNING: Unrecognized version format #{ReactOnRails::VERSION}. " \
|
|
164
|
+
"Adding the latest react-on-rails NPM module. " \
|
|
165
|
+
"Double check this is correct in package.json"
|
|
166
|
+
"react-on-rails"
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
puts "Installing React on Rails package..."
|
|
170
|
+
return if add_package(react_on_rails_pkg)
|
|
171
|
+
|
|
172
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
173
|
+
⚠️ Failed to add react-on-rails package.
|
|
174
|
+
|
|
175
|
+
You can install it manually by running:
|
|
176
|
+
npm install #{react_on_rails_pkg}
|
|
177
|
+
MSG
|
|
178
|
+
rescue StandardError => e
|
|
179
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
180
|
+
⚠️ Error adding react-on-rails package: #{e.message}
|
|
181
|
+
|
|
182
|
+
You can install it manually by running:
|
|
183
|
+
npm install #{react_on_rails_pkg}
|
|
184
|
+
MSG
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def add_react_dependencies
|
|
188
|
+
puts "Installing React dependencies..."
|
|
189
|
+
return if add_packages(REACT_DEPENDENCIES)
|
|
190
|
+
|
|
191
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
192
|
+
⚠️ Failed to add React dependencies.
|
|
193
|
+
|
|
194
|
+
You can install them manually by running:
|
|
195
|
+
npm install #{REACT_DEPENDENCIES.join(' ')}
|
|
196
|
+
MSG
|
|
197
|
+
rescue StandardError => e
|
|
198
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
199
|
+
⚠️ Error adding React dependencies: #{e.message}
|
|
200
|
+
|
|
201
|
+
You can install them manually by running:
|
|
202
|
+
npm install #{REACT_DEPENDENCIES.join(' ')}
|
|
203
|
+
MSG
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def add_css_dependencies
|
|
207
|
+
puts "Installing CSS handling dependencies..."
|
|
208
|
+
return if add_packages(CSS_DEPENDENCIES)
|
|
209
|
+
|
|
210
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
211
|
+
⚠️ Failed to add CSS dependencies.
|
|
212
|
+
|
|
213
|
+
You can install them manually by running:
|
|
214
|
+
npm install #{CSS_DEPENDENCIES.join(' ')}
|
|
215
|
+
MSG
|
|
216
|
+
rescue StandardError => e
|
|
217
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
218
|
+
⚠️ Error adding CSS dependencies: #{e.message}
|
|
219
|
+
|
|
220
|
+
You can install them manually by running:
|
|
221
|
+
npm install #{CSS_DEPENDENCIES.join(' ')}
|
|
222
|
+
MSG
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def add_rspack_dependencies
|
|
226
|
+
puts "Installing Rspack core dependencies..."
|
|
227
|
+
return if add_packages(RSPACK_DEPENDENCIES)
|
|
228
|
+
|
|
229
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
230
|
+
⚠️ Failed to add Rspack dependencies.
|
|
231
|
+
|
|
232
|
+
You can install them manually by running:
|
|
233
|
+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
|
|
234
|
+
MSG
|
|
235
|
+
rescue StandardError => e
|
|
236
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
237
|
+
⚠️ Error adding Rspack dependencies: #{e.message}
|
|
238
|
+
|
|
239
|
+
You can install them manually by running:
|
|
240
|
+
npm install #{RSPACK_DEPENDENCIES.join(' ')}
|
|
241
|
+
MSG
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def add_swc_dependencies
|
|
245
|
+
puts "Installing SWC transpiler dependencies (20x faster than Babel)..."
|
|
246
|
+
return if add_packages(SWC_DEPENDENCIES, dev: true)
|
|
247
|
+
|
|
248
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
249
|
+
⚠️ Failed to add SWC dependencies.
|
|
250
|
+
|
|
251
|
+
SWC is the default JavaScript transpiler for Shakapacker 9.3.0+.
|
|
252
|
+
You can install them manually by running:
|
|
253
|
+
npm install --save-dev #{SWC_DEPENDENCIES.join(' ')}
|
|
254
|
+
MSG
|
|
255
|
+
rescue StandardError => e
|
|
256
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
257
|
+
⚠️ Error adding SWC dependencies: #{e.message}
|
|
258
|
+
|
|
259
|
+
You can install them manually by running:
|
|
260
|
+
npm install --save-dev #{SWC_DEPENDENCIES.join(' ')}
|
|
261
|
+
MSG
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def add_typescript_dependencies
|
|
265
|
+
puts "Installing TypeScript dependencies..."
|
|
266
|
+
return if add_packages(TYPESCRIPT_DEPENDENCIES, dev: true)
|
|
267
|
+
|
|
268
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
269
|
+
⚠️ Failed to add TypeScript dependencies.
|
|
270
|
+
|
|
271
|
+
You can install them manually by running:
|
|
272
|
+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
|
|
273
|
+
MSG
|
|
274
|
+
rescue StandardError => e
|
|
275
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
276
|
+
⚠️ Error adding TypeScript dependencies: #{e.message}
|
|
277
|
+
|
|
278
|
+
You can install them manually by running:
|
|
279
|
+
npm install --save-dev #{TYPESCRIPT_DEPENDENCIES.join(' ')}
|
|
280
|
+
MSG
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def add_dev_dependencies
|
|
284
|
+
puts "Installing development dependencies..."
|
|
285
|
+
|
|
286
|
+
# Use Rspack-specific dev dependencies if --rspack flag is set
|
|
287
|
+
dev_deps = if respond_to?(:options) && options&.rspack?
|
|
288
|
+
RSPACK_DEV_DEPENDENCIES
|
|
289
|
+
else
|
|
290
|
+
DEV_DEPENDENCIES
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
return if add_packages(dev_deps, dev: true)
|
|
294
|
+
|
|
295
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
296
|
+
⚠️ Failed to add development dependencies.
|
|
297
|
+
|
|
298
|
+
You can install them manually by running:
|
|
299
|
+
npm install --save-dev #{dev_deps.join(' ')}
|
|
300
|
+
MSG
|
|
301
|
+
rescue StandardError => e
|
|
302
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
303
|
+
⚠️ Error adding development dependencies: #{e.message}
|
|
304
|
+
|
|
305
|
+
You can install them manually by running:
|
|
306
|
+
npm install --save-dev #{dev_deps.join(' ')}
|
|
307
|
+
MSG
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Add a single dependency using package_json gem
|
|
311
|
+
#
|
|
312
|
+
# This method is used internally for adding the react-on-rails package
|
|
313
|
+
# with version-specific handling (react-on-rails@VERSION).
|
|
314
|
+
# For batch operations, use add_packages instead.
|
|
315
|
+
#
|
|
316
|
+
# The exact: true flag ensures version pinning aligns with the gem version,
|
|
317
|
+
# preventing version mismatches between the Ruby gem and NPM package.
|
|
318
|
+
#
|
|
319
|
+
# @param package [String] Package specifier (e.g., "react-on-rails@16.0.0")
|
|
320
|
+
# @param dev [Boolean] Whether to add as dev dependency
|
|
321
|
+
# @return [Boolean] true if successful, false otherwise
|
|
322
|
+
def add_package(package, dev: false)
|
|
323
|
+
pj = package_json
|
|
324
|
+
return false unless pj
|
|
325
|
+
|
|
326
|
+
begin
|
|
327
|
+
# Ensure package is in array format for package_json gem
|
|
328
|
+
packages_array = [package]
|
|
329
|
+
if dev
|
|
330
|
+
pj.manager.add(packages_array, type: :dev, exact: true)
|
|
331
|
+
else
|
|
332
|
+
pj.manager.add(packages_array, exact: true)
|
|
333
|
+
end
|
|
334
|
+
true
|
|
335
|
+
rescue StandardError
|
|
336
|
+
# Return false to trigger warning in calling method
|
|
337
|
+
false
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Add multiple dependencies at once using package_json gem
|
|
342
|
+
#
|
|
343
|
+
# This method delegates to GeneratorHelper's add_npm_dependencies for
|
|
344
|
+
# better package manager abstraction and batch processing efficiency.
|
|
345
|
+
#
|
|
346
|
+
# @param packages [Array<String>] Package names to add
|
|
347
|
+
# @param dev [Boolean] Whether to add as dev dependencies
|
|
348
|
+
# @return [Boolean] true if successful, false otherwise
|
|
349
|
+
def add_packages(packages, dev: false)
|
|
350
|
+
# Use the add_npm_dependencies helper from GeneratorHelper
|
|
351
|
+
add_npm_dependencies(packages, dev: dev)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def install_js_dependencies
|
|
355
|
+
# Use package_json gem's install method (always available via shakapacker)
|
|
356
|
+
# package_json is guaranteed to be available because:
|
|
357
|
+
# 1. react_on_rails gemspec requires shakapacker
|
|
358
|
+
# 2. shakapacker gemspec requires package_json
|
|
359
|
+
# 3. GeneratorHelper provides package_json method
|
|
360
|
+
pj = package_json
|
|
361
|
+
unless pj
|
|
362
|
+
GeneratorMessages.add_warning("package_json not available, skipping dependency installation")
|
|
363
|
+
return false
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
pj.manager.install
|
|
367
|
+
true
|
|
368
|
+
rescue StandardError => e
|
|
369
|
+
GeneratorMessages.add_warning(<<~MSG.strip)
|
|
370
|
+
⚠️ JavaScript dependencies installation failed: #{e.message}
|
|
371
|
+
|
|
372
|
+
This could be due to network issues or package manager problems.
|
|
373
|
+
You can install dependencies manually later by running:
|
|
374
|
+
• npm install (if using npm)
|
|
375
|
+
• yarn install (if using yarn)
|
|
376
|
+
• pnpm install (if using pnpm)
|
|
377
|
+
MSG
|
|
378
|
+
false
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
end
|
|
383
|
+
# rubocop:enable Metrics/ModuleLength
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Service Dependencies Configuration
|
|
2
|
+
#
|
|
3
|
+
# This file defines external services that must be running before bin/dev starts.
|
|
4
|
+
# Copy this file to .dev-services.yml and customize for your application.
|
|
5
|
+
#
|
|
6
|
+
# bin/dev will check each service before starting the development server.
|
|
7
|
+
# If any service is not running, it will display helpful error messages with
|
|
8
|
+
# instructions on how to start the service.
|
|
9
|
+
#
|
|
10
|
+
# ⚠️ SECURITY WARNING:
|
|
11
|
+
# Commands in this file are executed during bin/dev startup. Only add commands
|
|
12
|
+
# from trusted sources. This file should not be committed if it contains
|
|
13
|
+
# sensitive information or custom paths specific to your machine. Consider
|
|
14
|
+
# adding .dev-services.yml to .gitignore if it contains machine-specific config.
|
|
15
|
+
#
|
|
16
|
+
# Security best practices:
|
|
17
|
+
# - Commands are executed without shell expansion (shell metacharacters won't work)
|
|
18
|
+
# - Use simple, single commands (e.g., "redis-cli ping", "pg_isready")
|
|
19
|
+
# - Do NOT use shell features: &&, ||, |, $, ;, backticks, etc. will fail
|
|
20
|
+
# - Only include services you trust
|
|
21
|
+
# - Keep commands simple and focused on service health checks
|
|
22
|
+
# - Consider adding .dev-services.yml to .gitignore (commit .example instead)
|
|
23
|
+
#
|
|
24
|
+
# Example configuration:
|
|
25
|
+
#
|
|
26
|
+
# services:
|
|
27
|
+
# redis:
|
|
28
|
+
# check_command: "redis-cli ping"
|
|
29
|
+
# expected_output: "PONG"
|
|
30
|
+
# start_command: "redis-server"
|
|
31
|
+
# install_hint: "brew install redis (macOS) or apt-get install redis-server (Linux)"
|
|
32
|
+
# description: "Redis (for caching and background jobs)"
|
|
33
|
+
#
|
|
34
|
+
# postgresql:
|
|
35
|
+
# check_command: "pg_isready"
|
|
36
|
+
# expected_output: "accepting connections"
|
|
37
|
+
# start_command: "pg_ctl -D /usr/local/var/postgres start"
|
|
38
|
+
# install_hint: "brew install postgresql (macOS) or apt-get install postgresql (Linux)"
|
|
39
|
+
# description: "PostgreSQL database"
|
|
40
|
+
#
|
|
41
|
+
# elasticsearch:
|
|
42
|
+
# check_command: "curl -s http://localhost:9200"
|
|
43
|
+
# expected_output: "cluster_name"
|
|
44
|
+
# start_command: "brew services start elasticsearch-full"
|
|
45
|
+
# install_hint: "brew install elasticsearch-full"
|
|
46
|
+
# description: "Elasticsearch (for search)"
|
|
47
|
+
#
|
|
48
|
+
# Field descriptions:
|
|
49
|
+
# check_command: Shell command to check if service is running (required)
|
|
50
|
+
# expected_output: String that must appear in command output (optional)
|
|
51
|
+
# start_command: Command to start the service (shown in error messages)
|
|
52
|
+
# install_hint: How to install the service if not found
|
|
53
|
+
# description: Human-readable description of the service
|
|
54
|
+
#
|
|
55
|
+
# To use this file:
|
|
56
|
+
# 1. Copy to .dev-services.yml: cp .dev-services.yml.example .dev-services.yml
|
|
57
|
+
# 2. Uncomment and configure the services your app needs
|
|
58
|
+
# 3. Add .dev-services.yml to .gitignore if it contains sensitive info
|
|
59
|
+
# 4. Run bin/dev - it will check services before starting
|
|
60
|
+
|
|
61
|
+
services:
|
|
62
|
+
# Uncomment and configure the services your application requires:
|
|
63
|
+
|
|
64
|
+
# redis:
|
|
65
|
+
# check_command: "redis-cli ping"
|
|
66
|
+
# expected_output: "PONG"
|
|
67
|
+
# start_command: "redis-server"
|
|
68
|
+
# install_hint: "brew install redis (macOS) or apt-get install redis-server (Linux)"
|
|
69
|
+
# description: "Redis (for caching and background jobs)"
|
|
70
|
+
|
|
71
|
+
# postgresql:
|
|
72
|
+
# check_command: "pg_isready"
|
|
73
|
+
# expected_output: "accepting connections"
|
|
74
|
+
# start_command: "pg_ctl -D /usr/local/var/postgres start" # macOS; Linux: sudo service postgresql start
|
|
75
|
+
# install_hint: "brew install postgresql (macOS) or apt-get install postgresql (Linux)"
|
|
76
|
+
# description: "PostgreSQL database"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Shakapacker precompile hook for React on Rails
|
|
5
|
+
#
|
|
6
|
+
# This script runs before webpack compilation to generate pack files
|
|
7
|
+
# for auto-bundled components. It's called automatically by Shakapacker
|
|
8
|
+
# when configured in config/shakapacker.yml:
|
|
9
|
+
# precompile_hook: 'bin/shakapacker-precompile-hook'
|
|
10
|
+
#
|
|
11
|
+
# Emoji Scheme:
|
|
12
|
+
# 🔄 = Running/in-progress
|
|
13
|
+
# ✅ = Success
|
|
14
|
+
# ❌ = Error
|
|
15
|
+
|
|
16
|
+
# Skip validation during precompile hook execution
|
|
17
|
+
# The hook runs early in the build process, potentially before full Rails initialization,
|
|
18
|
+
# and doesn't need package version validation since it's part of the build itself
|
|
19
|
+
ENV["REACT_ON_RAILS_SKIP_VALIDATION"] = "true"
|
|
20
|
+
|
|
21
|
+
require_relative "../config/environment"
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
puts Rainbow("🔄 Running React on Rails precompile hook...").cyan
|
|
25
|
+
ReactOnRails::PacksGenerator.instance.generate_packs_if_stale
|
|
26
|
+
rescue StandardError => e
|
|
27
|
+
warn Rainbow("❌ Error in precompile hook: #{e.message}").red
|
|
28
|
+
warn e.backtrace.first(5).join("\n")
|
|
29
|
+
exit 1
|
|
30
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "yaml"
|
|
6
|
+
require "json"
|
|
7
|
+
|
|
8
|
+
# Script to switch between webpack and rspack bundlers
|
|
9
|
+
class BundlerSwitcher
|
|
10
|
+
WEBPACK_DEPS = {
|
|
11
|
+
dependencies: %w[webpack webpack-assets-manifest webpack-merge],
|
|
12
|
+
dev_dependencies: %w[webpack-cli webpack-dev-server @pmmmwh/react-refresh-webpack-plugin]
|
|
13
|
+
}.freeze
|
|
14
|
+
|
|
15
|
+
RSPACK_DEPS = {
|
|
16
|
+
dependencies: %w[@rspack/core rspack-manifest-plugin],
|
|
17
|
+
dev_dependencies: %w[@rspack/cli @rspack/plugin-react-refresh]
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def initialize(target_bundler)
|
|
21
|
+
@target_bundler = target_bundler.to_s.downcase
|
|
22
|
+
@shakapacker_config = "config/shakapacker.yml"
|
|
23
|
+
validate_bundler!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def switch!
|
|
27
|
+
puts "🔄 Switching to #{@target_bundler}..."
|
|
28
|
+
|
|
29
|
+
update_shakapacker_config
|
|
30
|
+
update_dependencies
|
|
31
|
+
install_dependencies
|
|
32
|
+
|
|
33
|
+
puts "✅ Successfully switched to #{@target_bundler}!"
|
|
34
|
+
puts "\nNext steps:"
|
|
35
|
+
puts " 1. Review your webpack configuration files in config/webpack/"
|
|
36
|
+
puts " 2. Restart your development server"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def validate_bundler!
|
|
42
|
+
return if %w[webpack rspack].include?(@target_bundler)
|
|
43
|
+
|
|
44
|
+
abort "❌ Invalid bundler: #{@target_bundler}. Use 'webpack' or 'rspack'"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def update_shakapacker_config
|
|
48
|
+
abort "❌ #{@shakapacker_config} not found" unless File.exist?(@shakapacker_config)
|
|
49
|
+
|
|
50
|
+
puts "📝 Updating #{@shakapacker_config}..."
|
|
51
|
+
config = YAML.load_file(@shakapacker_config)
|
|
52
|
+
|
|
53
|
+
config["default"] ||= {}
|
|
54
|
+
config["default"]["assets_bundler"] = @target_bundler
|
|
55
|
+
|
|
56
|
+
# Update webpack_loader based on bundler
|
|
57
|
+
# Rspack works best with SWC, webpack typically uses babel
|
|
58
|
+
config["default"]["webpack_loader"] = @target_bundler == "rspack" ? "swc" : "babel"
|
|
59
|
+
|
|
60
|
+
File.write(@shakapacker_config, YAML.dump(config))
|
|
61
|
+
puts "✅ Updated assets_bundler to '#{@target_bundler}'"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def update_dependencies
|
|
65
|
+
puts "📦 Updating package.json dependencies..."
|
|
66
|
+
|
|
67
|
+
package_json_path = "package.json"
|
|
68
|
+
unless File.exist?(package_json_path)
|
|
69
|
+
puts "⚠️ package.json not found, skipping dependency updates"
|
|
70
|
+
return
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
package_json = JSON.parse(File.read(package_json_path))
|
|
74
|
+
|
|
75
|
+
remove_deps = @target_bundler == "rspack" ? WEBPACK_DEPS : RSPACK_DEPS
|
|
76
|
+
|
|
77
|
+
# Remove old bundler dependencies
|
|
78
|
+
remove_deps[:dependencies].each do |dep|
|
|
79
|
+
package_json["dependencies"]&.delete(dep)
|
|
80
|
+
end
|
|
81
|
+
remove_deps[:dev_dependencies].each do |dep|
|
|
82
|
+
package_json["devDependencies"]&.delete(dep)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
puts "✅ Removed #{@target_bundler == 'rspack' ? 'webpack' : 'rspack'} dependencies"
|
|
86
|
+
File.write(package_json_path, JSON.pretty_generate(package_json))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def install_dependencies
|
|
90
|
+
puts "📥 Installing #{@target_bundler} dependencies..."
|
|
91
|
+
|
|
92
|
+
deps = @target_bundler == "rspack" ? RSPACK_DEPS : WEBPACK_DEPS
|
|
93
|
+
|
|
94
|
+
# Detect package manager
|
|
95
|
+
package_manager = detect_package_manager
|
|
96
|
+
|
|
97
|
+
# Install dependencies using array form to prevent command injection
|
|
98
|
+
success = case package_manager
|
|
99
|
+
when "yarn"
|
|
100
|
+
system("yarn", "add", *deps[:dependencies])
|
|
101
|
+
when "pnpm"
|
|
102
|
+
system("pnpm", "add", *deps[:dependencies])
|
|
103
|
+
else
|
|
104
|
+
system("npm", "install", *deps[:dependencies])
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
abort("❌ Failed to install dependencies") unless success
|
|
108
|
+
|
|
109
|
+
# Install dev dependencies using array form to prevent command injection
|
|
110
|
+
success = case package_manager
|
|
111
|
+
when "yarn"
|
|
112
|
+
system("yarn", "add", "-D", *deps[:dev_dependencies])
|
|
113
|
+
when "pnpm"
|
|
114
|
+
system("pnpm", "add", "-D", *deps[:dev_dependencies])
|
|
115
|
+
else
|
|
116
|
+
system("npm", "install", "--save-dev", *deps[:dev_dependencies])
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
abort("❌ Failed to install dev dependencies") unless success
|
|
120
|
+
|
|
121
|
+
puts "✅ Installed #{@target_bundler} dependencies"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def detect_package_manager
|
|
125
|
+
return "yarn" if File.exist?("yarn.lock")
|
|
126
|
+
return "pnpm" if File.exist?("pnpm-lock.yaml")
|
|
127
|
+
|
|
128
|
+
"npm"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Main execution
|
|
133
|
+
if ARGV.empty?
|
|
134
|
+
puts "Usage: bin/switch-bundler [webpack|rspack]"
|
|
135
|
+
puts "\nExamples:"
|
|
136
|
+
puts " bin/switch-bundler rspack # Switch to Rspack"
|
|
137
|
+
puts " bin/switch-bundler webpack # Switch to Webpack"
|
|
138
|
+
exit 1
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
BundlerSwitcher.new(ARGV[0]).switch!
|