shakapacker 9.3.0.beta.2 → 9.3.0.beta.4

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.
@@ -18,9 +18,71 @@ module Shakapacker
18
18
  exit(0)
19
19
  end
20
20
 
21
+ # Check for --build flag
22
+ build_index = argv.index("--build")
23
+ if build_index
24
+ build_name = argv[build_index + 1]
25
+
26
+ unless build_name
27
+ $stderr.puts "[Shakapacker] Error: --build requires a build name"
28
+ $stderr.puts "Usage: bin/shakapacker-dev-server --build <name>"
29
+ exit(1)
30
+ end
31
+
32
+ loader = BuildConfigLoader.new
33
+
34
+ unless loader.exists?
35
+ $stderr.puts "[Shakapacker] Config file not found: #{loader.config_file_path}"
36
+ $stderr.puts "Run 'bin/shakapacker --init' to create one"
37
+ exit(1)
38
+ end
39
+
40
+ begin
41
+ build_config = loader.resolve_build_config(build_name)
42
+
43
+ # Check if this build is meant for dev server
44
+ unless loader.uses_dev_server?(build_config)
45
+ $stderr.puts "[Shakapacker] Error: Build '#{build_name}' is not configured for dev server (dev_server: false)"
46
+ $stderr.puts "[Shakapacker] Use this command instead:"
47
+ $stderr.puts " bin/shakapacker --build #{build_name}"
48
+ exit(1)
49
+ end
50
+
51
+ # Remove --build and build name from argv
52
+ remaining_argv = argv.dup
53
+ remaining_argv.delete_at(build_index + 1)
54
+ remaining_argv.delete_at(build_index)
55
+
56
+ run_with_build_config(remaining_argv, build_config)
57
+ return
58
+ rescue ArgumentError => e
59
+ $stderr.puts "[Shakapacker] #{e.message}"
60
+ exit(1)
61
+ end
62
+ end
63
+
21
64
  new(argv).run
22
65
  end
23
66
 
67
+ def self.run_with_build_config(argv, build_config)
68
+ # Apply build config environment variables
69
+ build_config[:environment].each do |key, value|
70
+ ENV[key] = value.to_s
71
+ end
72
+
73
+ # Set SHAKAPACKER_ASSETS_BUNDLER so JS/TS config files use the correct bundler
74
+ # This ensures the bundler override (from --bundler or build config) is respected
75
+ ENV["SHAKAPACKER_ASSETS_BUNDLER"] = build_config[:bundler]
76
+
77
+ puts "[Shakapacker] Running dev server for build: #{build_config[:name]}"
78
+ puts "[Shakapacker] Description: #{build_config[:description]}" if build_config[:description]
79
+ puts "[Shakapacker] Bundler: #{build_config[:bundler]}"
80
+ puts "[Shakapacker] Config file: #{build_config[:config_file]}" if build_config[:config_file]
81
+
82
+ # Pass bundler override so Configuration.assets_bundler reflects the build
83
+ new(argv, build_config, build_config[:bundler]).run
84
+ end
85
+
24
86
  def self.print_help
25
87
  puts <<~HELP
26
88
  ================================================================================
@@ -33,6 +95,17 @@ module Shakapacker
33
95
  -h, --help Show this help message
34
96
  -v, --version Show Shakapacker version
35
97
  --debug-shakapacker Enable Node.js debugging (--inspect-brk)
98
+ --build <name> Run a specific build configuration
99
+
100
+ Build configurations (config/shakapacker-builds.yml):
101
+ bin/shakapacker-dev-server --build dev-hmr # Run the 'dev-hmr' build
102
+
103
+ To manage builds:
104
+ bin/shakapacker --init # Create config file
105
+ bin/shakapacker --list-builds # List available builds
106
+
107
+ Note: You can also use bin/shakapacker --build with a build that has
108
+ WEBPACK_SERVE=true, and it will automatically use the dev server.
36
109
 
37
110
  Examples:
38
111
  bin/shakapacker-dev-server # Start dev server
@@ -2,6 +2,7 @@ require_relative "utils/misc"
2
2
  require_relative "utils/manager"
3
3
  require_relative "configuration"
4
4
  require_relative "version"
5
+ require_relative "build_config_loader"
5
6
 
6
7
  require "package_json"
7
8
  require "pathname"
@@ -34,15 +35,109 @@ module Shakapacker
34
35
  elsif argv.include?("--version") || argv.include?("-v")
35
36
  print_version
36
37
  exit(0)
38
+ elsif argv.include?("--init")
39
+ init_config_file
40
+ exit(0)
41
+ elsif argv.include?("--list-builds")
42
+ list_builds
43
+ exit(0)
44
+ end
45
+
46
+ # Check for --bundler flag
47
+ bundler_override = nil
48
+ bundler_index = argv.index("--bundler")
49
+ if bundler_index
50
+ bundler_value = argv[bundler_index + 1]
51
+ unless bundler_value && %w[webpack rspack].include?(bundler_value)
52
+ $stderr.puts "[Shakapacker] Error: --bundler requires 'webpack' or 'rspack'"
53
+ $stderr.puts "Usage: bin/shakapacker --bundler <webpack|rspack>"
54
+ exit(1)
55
+ end
56
+ bundler_override = bundler_value
57
+ end
58
+
59
+ # Check for --build flag
60
+ build_index = argv.index("--build")
61
+ if build_index
62
+ build_name = argv[build_index + 1]
63
+
64
+ unless build_name
65
+ $stderr.puts "[Shakapacker] Error: --build requires a build name"
66
+ $stderr.puts "Usage: bin/shakapacker --build <name>"
67
+ exit(1)
68
+ end
69
+
70
+ loader = BuildConfigLoader.new
71
+
72
+ unless loader.exists?
73
+ $stderr.puts "[Shakapacker] Config file not found: #{loader.config_file_path}"
74
+ $stderr.puts "Run 'bin/shakapacker --init' to create one"
75
+ exit(1)
76
+ end
77
+
78
+ begin
79
+ # Pass bundler override to resolve_build_config
80
+ resolve_opts = {}
81
+ resolve_opts[:default_bundler] = bundler_override if bundler_override
82
+ build_config = loader.resolve_build_config(build_name, **resolve_opts)
83
+
84
+ # Remove --build and build name from argv
85
+ remaining_argv = argv.dup
86
+ remaining_argv.delete_at(build_index + 1)
87
+ remaining_argv.delete_at(build_index)
88
+
89
+ # Remove --bundler and bundler value from argv if present
90
+ if bundler_index
91
+ bundler_idx_in_remaining = remaining_argv.index("--bundler")
92
+ if bundler_idx_in_remaining
93
+ remaining_argv.delete_at(bundler_idx_in_remaining + 1)
94
+ remaining_argv.delete_at(bundler_idx_in_remaining)
95
+ end
96
+ end
97
+
98
+ # If this build uses dev server, delegate to DevServerRunner
99
+ if loader.uses_dev_server?(build_config)
100
+ $stdout.puts "[Shakapacker] Build '#{build_name}' requires dev server"
101
+ $stdout.puts "[Shakapacker] Running: bin/shakapacker-dev-server --build #{build_name}"
102
+ $stdout.puts ""
103
+ require_relative "dev_server_runner"
104
+ DevServerRunner.run_with_build_config(remaining_argv, build_config)
105
+ return
106
+ end
107
+
108
+ # Otherwise run with this build config
109
+ run_with_build_config(remaining_argv, build_config)
110
+ return
111
+ rescue ArgumentError => e
112
+ $stderr.puts "[Shakapacker] #{e.message}"
113
+ exit(1)
114
+ end
37
115
  end
38
116
 
39
117
  Shakapacker.ensure_node_env!
40
118
 
119
+ # Remove --bundler flag from argv if present (not using --build)
120
+ remaining_argv = argv.dup
121
+ if bundler_index
122
+ bundler_idx = remaining_argv.index("--bundler")
123
+ if bundler_idx
124
+ remaining_argv.delete_at(bundler_idx + 1)
125
+ remaining_argv.delete_at(bundler_idx)
126
+ end
127
+ end
128
+
129
+ # Set SHAKAPACKER_ASSETS_BUNDLER if bundler override is specified
130
+ # This ensures JS/TS config files use the correct bundler
131
+ ENV["SHAKAPACKER_ASSETS_BUNDLER"] = bundler_override if bundler_override
132
+
41
133
  # Create a single runner instance to avoid loading configuration twice.
42
134
  # We extend it with the appropriate build command based on the bundler type.
43
- runner = new(argv)
135
+ runner = new(remaining_argv, nil, bundler_override)
136
+
137
+ # Determine which bundler to use (override takes precedence)
138
+ use_rspack = bundler_override ? (bundler_override == "rspack") : runner.config.rspack?
44
139
 
45
- if runner.config.rspack?
140
+ if use_rspack
46
141
  require_relative "rspack_runner"
47
142
  # Extend the runner instance with rspack-specific methods
48
143
  # This avoids creating a new RspackRunner which would reload the configuration
@@ -69,17 +164,71 @@ module Shakapacker
69
164
  end
70
165
  end
71
166
 
72
- def initialize(argv)
167
+ def self.run_with_build_config(argv, build_config)
168
+ $stdout.sync = true
169
+ Shakapacker.ensure_node_env!
170
+
171
+ # Apply build config environment variables
172
+ build_config[:environment].each do |key, value|
173
+ ENV[key] = value.to_s
174
+ end
175
+
176
+ # Set SHAKAPACKER_ASSETS_BUNDLER so JS/TS config files use the correct bundler
177
+ # This ensures the bundler override (from --bundler or build config) is respected
178
+ ENV["SHAKAPACKER_ASSETS_BUNDLER"] = build_config[:bundler]
179
+
180
+ puts "[Shakapacker] Running build: #{build_config[:name]}"
181
+ puts "[Shakapacker] Description: #{build_config[:description]}" if build_config[:description]
182
+ puts "[Shakapacker] Bundler: #{build_config[:bundler]}"
183
+ puts "[Shakapacker] Config file: #{build_config[:config_file]}" if build_config[:config_file]
184
+
185
+ # Create runner with modified argv and bundler from build_config
186
+ # The build_config[:bundler] already has any CLI --bundler override applied
187
+ runner = new(argv, build_config, build_config[:bundler])
188
+
189
+ # Use bundler from build_config (which includes CLI override)
190
+ if build_config[:bundler] == "rspack"
191
+ require_relative "rspack_runner"
192
+ runner.extend(Module.new do
193
+ def build_cmd
194
+ package_json.manager.native_exec_command("rspack")
195
+ end
196
+
197
+ def assets_bundler_commands
198
+ BASE_COMMANDS + %w[build watch]
199
+ end
200
+ end)
201
+ runner.run
202
+ else
203
+ require_relative "webpack_runner"
204
+ runner.extend(Module.new do
205
+ def build_cmd
206
+ package_json.manager.native_exec_command("webpack")
207
+ end
208
+ end)
209
+ runner.run
210
+ end
211
+ end
212
+
213
+ def initialize(argv, build_config = nil, bundler_override = nil)
73
214
  @argv = argv
215
+ @build_config = build_config
216
+ @bundler_override = bundler_override
217
+
218
+ @app_path = File.expand_path(".", Dir.pwd)
219
+ @shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
74
220
 
75
- @app_path = File.expand_path(".", Dir.pwd)
76
- @shakapacker_config = ENV["SHAKAPACKER_CONFIG"] || File.join(@app_path, "config/shakapacker.yml")
77
- @config = Configuration.new(
221
+ # Create config with bundler override if provided
222
+ config_opts = {
78
223
  root_path: Pathname.new(@app_path),
79
224
  config_path: Pathname.new(@shakapacker_config),
80
225
  env: ENV["RAILS_ENV"] || ENV["NODE_ENV"] || "development"
81
- )
82
- @webpack_config = find_assets_bundler_config
226
+ }
227
+ config_opts[:bundler_override] = bundler_override if bundler_override
228
+
229
+ @config = Configuration.new(**config_opts)
230
+
231
+ @webpack_config = find_webpack_config_from_build_or_default
83
232
 
84
233
  Shakapacker::Utils::Manager.error_unless_package_manager_is_obvious!
85
234
  end
@@ -175,13 +324,26 @@ module Shakapacker
175
324
  --debug-shakapacker Enable Node.js debugging (--inspect-brk)
176
325
  --trace-deprecation Show stack traces for deprecations
177
326
  --no-deprecation Silence deprecation warnings
327
+ --bundler <webpack|rspack>
328
+ Override bundler (defaults to shakapacker.yml)
178
329
 
179
- Examples:
180
- bin/shakapacker # Build for production
181
- bin/shakapacker --mode development # Build for development
182
- bin/shakapacker --watch # Watch mode
183
- bin/shakapacker --mode development --analyze # Development build with analysis
184
- bin/shakapacker --debug-shakapacker # Debug with Node inspector
330
+ Build configurations (config/shakapacker-builds.yml):
331
+ --init Create config/shakapacker-builds.yml
332
+ --list-builds List available builds
333
+ --build <name> Run a specific build configuration
334
+
335
+ Examples (build configs):
336
+ bin/shakapacker --init # Create config file
337
+ bin/shakapacker --list-builds # Show available builds
338
+ bin/shakapacker --build dev-hmr # Run the 'dev-hmr' build
339
+ bin/shakapacker --build prod # Run the 'prod' build
340
+ bin/shakapacker --build prod --bundler rspack # Override to use rspack
341
+
342
+ Note: If a build has dev_server: true in its config, it will
343
+ automatically use bin/shakapacker-dev-server instead.
344
+
345
+ Advanced: Use bin/shakapacker-config for more config management options
346
+ (validate builds, export configs, etc.)
185
347
 
186
348
  HELP
187
349
 
@@ -189,6 +351,14 @@ module Shakapacker
189
351
 
190
352
  puts <<~HELP
191
353
 
354
+ Examples (passing options to webpack/rspack):
355
+ bin/shakapacker # Build for production
356
+ bin/shakapacker --bundler rspack # Build with rspack instead of webpack
357
+ bin/shakapacker --mode development # Build for development
358
+ bin/shakapacker --watch # Watch mode
359
+ bin/shakapacker --mode development --analyze # Development build with analysis
360
+ bin/shakapacker --debug-shakapacker # Debug with Node inspector
361
+
192
362
  Options managed by Shakapacker (configured via config files):
193
363
  --config Set automatically based on assets_bundler_config_path
194
364
  (defaults to config/webpack or config/rspack)
@@ -301,6 +471,52 @@ module Shakapacker
301
471
  end
302
472
  end
303
473
 
474
+ def self.init_config_file
475
+ loader = BuildConfigLoader.new
476
+ config_path = loader.config_file_path
477
+
478
+ if loader.exists?
479
+ puts "[Shakapacker] Config file already exists: #{config_path}"
480
+ puts "Use --list-builds to see available builds"
481
+ return
482
+ end
483
+
484
+ # Delegate to bin/shakapacker-config
485
+ app_path = File.expand_path(".", Dir.pwd)
486
+ shakapacker_config_path = File.join(app_path, "bin", "shakapacker-config")
487
+
488
+ unless File.exist?(shakapacker_config_path)
489
+ $stderr.puts "[Shakapacker] Error: bin/shakapacker-config not found"
490
+ $stderr.puts "Please ensure Shakapacker is properly installed"
491
+ exit(1)
492
+ end
493
+
494
+ # Run the init command and check if it succeeded
495
+ unless system(shakapacker_config_path, "--init")
496
+ exit_code = $?.exitstatus || 1
497
+ $stderr.puts "[Shakapacker] Error: Failed to run: #{shakapacker_config_path} --init"
498
+ $stderr.puts "[Shakapacker] Command exited with status: #{exit_code}"
499
+ exit(exit_code)
500
+ end
501
+ end
502
+
503
+ def self.list_builds
504
+ loader = BuildConfigLoader.new
505
+
506
+ unless loader.exists?
507
+ puts "[Shakapacker] No config file found: #{loader.config_file_path}"
508
+ puts "Run 'bin/shakapacker --init' to create one"
509
+ return
510
+ end
511
+
512
+ begin
513
+ loader.list_builds
514
+ rescue ArgumentError => e
515
+ $stderr.puts "[Shakapacker] Error: #{e.message}"
516
+ exit(1)
517
+ end
518
+ end
519
+
304
520
  def self.get_bundler_version
305
521
  execute_bundler_command("--version") { |stdout| stdout.strip }
306
522
  end
@@ -356,6 +572,15 @@ module Shakapacker
356
572
  end
357
573
 
358
574
  private
575
+
576
+ def find_webpack_config_from_build_or_default
577
+ if @build_config && @build_config[:config_file]
578
+ File.join(@app_path, @build_config[:config_file])
579
+ else
580
+ find_assets_bundler_config
581
+ end
582
+ end
583
+
359
584
  def find_assets_bundler_config
360
585
  if @config.rspack?
361
586
  find_rspack_config_with_fallback
@@ -1,4 +1,4 @@
1
1
  module Shakapacker
2
2
  # Change the version in package.json too, please!
3
- VERSION = "9.3.0.beta.2".freeze
3
+ VERSION = "9.3.0.beta.4".freeze
4
4
  end
@@ -865,13 +865,13 @@ export class BuildValidator {
865
865
  const failedBuilds = results.filter((r) => !r.success)
866
866
  failedBuilds.forEach((result) => {
867
867
  lines.push(
868
- ` bin/export-bundler-config --validate-build ${result.buildName} --verbose`
868
+ ` bin/shakapacker-config --validate-build ${result.buildName} --verbose`
869
869
  )
870
870
  })
871
871
 
872
872
  lines.push("")
873
873
  lines.push(
874
- " Or validate all builds with full output: bin/export-bundler-config --validate --verbose"
874
+ " Or validate all builds with full output: bin/shakapacker-config --validate --verbose"
875
875
  )
876
876
  lines.push("=".repeat(80))
877
877
  }