Skip to content

Commit 4141a39

Browse files
justin808claude
andcommitted
✨ Add --rails-env option for configurable asset precompilation environment
## New Feature - Add `--rails-env` option to `bin/dev prod` for custom Rails environment during assets:precompile - Default: NODE_ENV=production, RAILS_ENV=development (avoids credentials complexity) - Option: `--rails-env=production` for full production Rails environment - Clear documentation that option only affects assets:precompile, not server processes ## Enhanced Documentation - Comprehensive help text with examples and environment explanations - Clear runtime messaging about environment configuration - Separation of asset precompilation vs server process environments - Guidance on when to use each option ## Usage Examples ```bash bin/dev prod # Default: production webpack, development Rails bin/dev prod --rails-env=production # Full production environment bin/dev prod --route=dashboard # Custom route in URLs ``` ## Benefits - ✅ Production webpack optimizations without production Rails complexity by default - ✅ Option for full production environment when needed (testing credentials, etc.) - ✅ Clear documentation prevents confusion about scope - ✅ Better error handling with environment-specific guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent dc301fd commit 4141a39

File tree

1 file changed

+86
-32
lines changed

1 file changed

+86
-32
lines changed

lib/react_on_rails/dev/server_manager.rb

Lines changed: 86 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ module ReactOnRails
88
module Dev
99
class ServerManager
1010
class << self
11-
def start(mode = :development, procfile = nil, verbose: false, route: nil)
11+
def start(mode = :development, procfile = nil, verbose: false, route: nil, rails_env: nil)
1212
case mode
1313
when :production_like
14-
run_production_like(_verbose: verbose, route: route)
14+
run_production_like(_verbose: verbose, route: route, rails_env: rails_env)
1515
when :static
1616
procfile ||= "Procfile.dev-static-assets"
1717
run_static_development(procfile, verbose: verbose, route: route)
@@ -119,7 +119,7 @@ def show_help
119119
def run_from_command_line(args = ARGV)
120120
require "optparse"
121121

122-
options = { route: nil }
122+
options = { route: nil, rails_env: nil }
123123

124124
OptionParser.new do |opts|
125125
opts.banner = "Usage: dev [command] [options]"
@@ -128,6 +128,10 @@ def run_from_command_line(args = ARGV)
128128
options[:route] = route
129129
end
130130

131+
opts.on("--rails-env ENV", "Override RAILS_ENV for assets:precompile step only (prod mode only)") do |env|
132+
options[:rails_env] = env
133+
end
134+
131135
opts.on("-h", "--help", "Prints this help") do
132136
show_help
133137
exit
@@ -140,7 +144,7 @@ def run_from_command_line(args = ARGV)
140144
# Main execution
141145
case command
142146
when "production-assets", "prod"
143-
start(:production_like, nil, verbose: false, route: options[:route])
147+
start(:production_like, nil, verbose: false, route: options[:route], rails_env: options[:rails_env])
144148
when "static"
145149
start(:static, "Procfile.dev-static-assets", verbose: false, route: options[:route])
146150
when "kill"
@@ -182,12 +186,21 @@ def help_commands
182186
end
183187
# rubocop:enable Metrics/AbcSize
184188

189+
# rubocop:disable Metrics/AbcSize
185190
def help_options
186191
<<~OPTIONS
187192
#{Rainbow('⚙️ OPTIONS:').cyan.bold}
188-
#{Rainbow('--verbose, -v').green.bold} #{Rainbow('Enable verbose output for pack generation').white}
193+
#{Rainbow('--route ROUTE').green.bold} #{Rainbow('Specify route to display in URLs (default: root)').white}
194+
#{Rainbow('--rails-env ENV').green.bold} #{Rainbow('Override RAILS_ENV for assets:precompile step only (prod mode only)').white}
195+
#{Rainbow('--verbose, -v').green.bold} #{Rainbow('Enable verbose output for pack generation').white}
196+
197+
#{Rainbow('📝 EXAMPLES:').cyan.bold}
198+
#{Rainbow('bin/dev prod').green.bold} #{Rainbow('# NODE_ENV=production, RAILS_ENV=development').white}
199+
#{Rainbow('bin/dev prod --rails-env=production').green.bold} #{Rainbow('# NODE_ENV=production, RAILS_ENV=production').white}
200+
#{Rainbow('bin/dev prod --route=dashboard').green.bold} #{Rainbow('# Custom route in URLs').white}
189201
OPTIONS
190202
end
203+
# rubocop:enable Metrics/AbcSize
191204

192205
def help_customization
193206
<<~CUSTOMIZATION
@@ -225,17 +238,19 @@ def help_mode_details
225238
226239
#{Rainbow('🏭 Production-assets mode').cyan.bold} - #{Rainbow('Procfile.dev-prod-assets').green}:
227240
#{Rainbow('•').yellow} #{Rainbow('React on Rails pack generation before Procfile start').white}
228-
#{Rainbow('•').yellow} #{Rainbow('Asset precompilation with production optimizations').white}
229-
#{Rainbow('•').yellow} #{Rainbow('Optimized, minified bundles').white}
230-
#{Rainbow('•').yellow} #{Rainbow('Extracted CSS files (no FOUC)').white}
241+
#{Rainbow('•').yellow} #{Rainbow('Asset precompilation with NODE_ENV=production (webpack optimizations)').white}
242+
#{Rainbow('•').yellow} #{Rainbow('RAILS_ENV=development by default for assets:precompile (avoids credentials)').white}
243+
#{Rainbow('•').yellow} #{Rainbow('Use --rails-env=production for assets:precompile only (not server processes)').white}
244+
#{Rainbow('•').yellow} #{Rainbow('Server processes controlled by Procfile.dev-prod-assets environment').white}
245+
#{Rainbow('•').yellow} #{Rainbow('Optimized, minified bundles with CSS extraction').white}
231246
#{Rainbow('•').yellow} #{Rainbow('No HMR (static assets)').white}
232-
#{Rainbow('•').yellow} #{Rainbow('Slower recompilation').white}
233247
#{Rainbow('•').yellow} #{Rainbow('Access at:').white} #{Rainbow('http://localhost:3001/<route>').cyan.underline}
234248
MODES
235249
end
236250
# rubocop:enable Metrics/AbcSize
237251

238-
def run_production_like(_verbose: false, route: nil)
252+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
253+
def run_production_like(_verbose: false, route: nil, rails_env: nil)
239254
procfile = "Procfile.dev-prod-assets"
240255

241256
print_procfile_info(procfile, route: route)
@@ -252,12 +267,33 @@ def run_production_like(_verbose: false, route: nil)
252267
route: route
253268
)
254269

255-
# Precompile assets in production mode (includes pack generation automatically)
256-
puts "🔨 Precompiling assets..."
270+
# Precompile assets with production webpack optimizations (includes pack generation automatically)
271+
env_vars = ["NODE_ENV=production"]
272+
env_vars << "RAILS_ENV=#{rails_env}" if rails_env
273+
command = "#{env_vars.join(' ')} bundle exec rails assets:precompile"
274+
275+
puts "🔨 Precompiling assets with production webpack optimizations..."
276+
puts ""
277+
278+
puts Rainbow("ℹ️ Asset Precompilation Environment:").blue
279+
puts " • NODE_ENV=production → Webpack optimizations (minification, compression)"
280+
if rails_env
281+
puts " • RAILS_ENV=#{rails_env} → Custom Rails environment for assets:precompile only"
282+
puts " • Note: RAILS_ENV=production requires credentials, database setup, etc."
283+
puts " • Server processes will use environment from Procfile.dev-prod-assets"
284+
else
285+
puts " • RAILS_ENV=development → Simpler Rails setup (no credentials needed)"
286+
puts " • Use --rails-env=production for assets:precompile step only"
287+
puts " • Server processes will use environment from Procfile.dev-prod-assets"
288+
puts " • Gets production webpack bundles without production Rails complexity"
289+
end
290+
puts ""
291+
puts "#{Rainbow('💻 Running:').blue} #{command}"
292+
puts ""
257293

258294
# Capture both stdout and stderr
259295
require "open3"
260-
stdout, stderr, status = Open3.capture3("RAILS_ENV=production NODE_ENV=production bundle exec rails assets:precompile")
296+
stdout, stderr, status = Open3.capture3(command)
261297

262298
if status.success?
263299
puts "✅ Assets precompiled successfully"
@@ -267,51 +303,69 @@ def run_production_like(_verbose: false, route: nil)
267303
puts "❌ Asset precompilation failed"
268304
puts ""
269305

270-
# Display the actual error output
271-
unless stderr.empty?
272-
puts "#{Rainbow('🚨 Error Output:').red.bold}"
273-
puts stderr
274-
puts ""
275-
end
306+
# Combine and display all output
307+
all_output = []
308+
all_output << stdout unless stdout.empty?
309+
all_output << stderr unless stderr.empty?
276310

277-
unless stdout.empty? && stdout.strip != stderr.strip
278-
puts "#{Rainbow('📋 Command Output:').yellow.bold}"
279-
puts stdout
311+
unless all_output.empty?
312+
puts Rainbow("📋 Full Command Output:").red.bold
313+
puts Rainbow("─" * 60).red
314+
all_output.each { |output| puts output }
315+
puts Rainbow("─" * 60).red
280316
puts ""
281317
end
282318

283-
puts "#{Rainbow('💡 Common fixes:').yellow.bold}"
319+
puts Rainbow("🛠️ To debug this issue:").yellow.bold
320+
puts "#{Rainbow('1.').cyan} #{Rainbow('Run the command separately to see detailed output:').white}"
321+
puts " #{Rainbow(command).cyan}"
322+
puts ""
323+
puts "#{Rainbow('2.').cyan} #{Rainbow('Add --trace for full stack trace:').white}"
324+
puts " #{Rainbow("#{command} --trace").cyan}"
325+
puts ""
326+
puts "#{Rainbow('3.').cyan} #{Rainbow('Or try with development webpack (faster, less optimized):').white}"
327+
puts " #{Rainbow('NODE_ENV=development bundle exec rails assets:precompile').cyan}"
328+
puts ""
329+
330+
puts Rainbow("💡 Common fixes:").yellow.bold
284331

285332
# Provide specific guidance based on error content
286333
error_content = "#{stderr} #{stdout}".downcase
287334

288335
if error_content.include?("secret_key_base")
289-
puts "#{Rainbow('•').yellow} #{Rainbow('Missing secret_key_base:').white.bold} Run #{Rainbow('bin/rails credentials:edit').cyan}"
336+
puts "#{Rainbow('•').yellow} #{Rainbow('Missing secret_key_base:').white.bold} " \
337+
"Run #{Rainbow('bin/rails credentials:edit').cyan}"
290338
end
291339

292-
if error_content.include?("database") || error_content.include?("relation") || error_content.include?("table")
293-
puts "#{Rainbow('•').yellow} #{Rainbow('Database issues:').white.bold} Run #{Rainbow('bin/rails db:create db:migrate').cyan}"
340+
if error_content.include?("database") || error_content.include?("relation") ||
341+
error_content.include?("table")
342+
puts "#{Rainbow('•').yellow} #{Rainbow('Database issues:').white.bold} " \
343+
"Run #{Rainbow('bin/rails db:create db:migrate').cyan}"
294344
end
295345

296346
if error_content.include?("gem") || error_content.include?("bundle") || error_content.include?("load error")
297-
puts "#{Rainbow('•').yellow} #{Rainbow('Missing dependencies:').white.bold} Run #{Rainbow('bundle install && npm install').cyan}"
347+
puts "#{Rainbow('•').yellow} #{Rainbow('Missing dependencies:').white.bold} " \
348+
"Run #{Rainbow('bundle install && npm install').cyan}"
298349
end
299350

300-
if error_content.include?("webpack") || error_content.include?("module") || error_content.include?("compilation")
301-
puts "#{Rainbow('•').yellow} #{Rainbow('Webpack compilation:').white.bold} Check JavaScript/webpack errors above"
351+
if error_content.include?("webpack") || error_content.include?("module") ||
352+
error_content.include?("compilation")
353+
puts "#{Rainbow('•').yellow} #{Rainbow('Webpack compilation:').white.bold} " \
354+
"Check JavaScript/webpack errors above"
302355
end
303356

304357
# Always show these general options
305-
puts "#{Rainbow('•').yellow} #{Rainbow('General debugging:').white} Run with #{Rainbow('--trace').cyan} for full stack trace"
306-
puts "#{Rainbow('•').yellow} #{Rainbow('Environment issues:').white} Check #{Rainbow('config/environments/production.rb').cyan}"
358+
puts "#{Rainbow('•').yellow} #{Rainbow('Environment config:').white} " \
359+
"Check #{Rainbow('config/environments/production.rb').cyan}"
307360

308361
puts ""
309-
puts "#{Rainbow('ℹ️ Alternative for development:').blue}"
362+
puts Rainbow("ℹ️ Alternative for development:").blue
310363
puts " #{Rainbow('bin/dev static').green} # Static assets without production optimizations"
311364
puts ""
312365
exit 1
313366
end
314367
end
368+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
315369

316370
def run_static_development(procfile, verbose: false, route: nil)
317371
print_procfile_info(procfile, route: route)

0 commit comments

Comments
 (0)